【问题标题】:Is javascript Promise API more convoluted than it needs to be?javascript Promise API 是否比它需要的更复杂?
【发布时间】:2016-05-24 09:03:51
【问题描述】:

我想我终于设法在很大程度上将注意力集中在 javascript/ES6 Promises 上。这并不容易!但是这个设计有一些让我困惑的地方。

为什么 Promise 构造函数需要回调?鉴于回调被立即调用,调用者不能直接执行该代码,从而避免一种不必要的“别打电话给我,我会打电话给你”吗?

这是我认为 Promise 用法的原型示例,复制自 Jake Archibald 的 Javascript Promises 教程 http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest ,去掉了 cmets。

它是一个基于 Promise 的 XMLHttpRequest GET 请求包装器:

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);
    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };
    req.onerror = function() {
      reject(Error("Network Error"));
    };
    req.send();
  });
}

对我来说,如果将上面的代码改写如下,使用与我想象的完全不同的承诺类型,使用无参数构造函数和解析/拒绝方法,将更容易理解:

function get(url) {
  var promise = new MyEasierToUnderstandPromise();
  var req = new XMLHttpRequest();
  req.open('GET', url);
  req.onload = function() {
    if (req.status == 200) {
      promise.resolve(req.response);
    }
    else {
      promise.reject(Error(req.statusText));
    }
  };
  req.onerror = function() {
    promise.reject(Error("Network Error"));
  };
  req.send();
  return promise;
}

MyEasierToUnderstandPromise 在 Promise 方面实现起来并不难。起初我试图让它成为 Promise 的一个实际子类,但由于某种原因我无法让它工作;所以我将它实现为一个简单的工厂函数,它返回一个普通的旧 Promise 对象和几个额外的函数 附加的行为类似于成员函数:

function NewMyEasierToUnderstandPromise() {
  var resolveVar;
  var rejectVar;
  var promise = new Promise(function(resolveParam, rejectParam) {
    resolveVar = resolveParam;
    rejectVar = rejectParam;
  });
  promise.resolve = resolveVar;
  promise.reject = rejectVar;
  return promise;
};

那么,为什么 Promise 不是这样设计的呢?我想如果是这样的话,它会帮助我更快地理解 Promise ——我敢打赌它会把我的学习时间缩短一半。

我知道很多聪明人都参与了 Promise API 的制作,而且每个人似乎都普遍为它感到高兴和自豪,所以我想知道他们在想什么。

【问题讨论】:

  • 你的“easierToUnderstandPromise”在某种程度上就像 jQuery.Deferred。对于您的设计,返回的承诺必然会公开解析/拒绝方法。我在某处读过为什么这是“坏事”,但我找不到那个资源(我已经读了好几年了)
  • 了解ES7 async/await
  • 也有延迟模式,不过it's deprecated for good reason

标签: javascript promise es6-promise


【解决方案1】:

Promise 旨在用作值。 ES 构造方法封装了 Promise 的创建,然后可以像值一样传递。当该值被传递时,该值的使用者不需要resolvereject,因此这些函数不应成为公共 API 的一部分。

(以及关于异常处理和链接的所有内容)

【讨论】:

    【解决方案2】:

    作为辅助信息,当脚本定义类似 ES6 的承诺链时

    var promise = new Promise(executor).then(something).catch(handleError);
    

    promise 变量设置为 .catch 方法调用返回的 promise。 executor 函数持有的 resolve/reject 函数引用实际上阻止了整个链或 Promise 对象被垃圾收集。如果调用 resolve (通常在执行器返回之后异步调用,但在让解析/拒绝函数超出范围之前),then 侦听器“something”被调用,Promise 平台内部执行器为 Promise 保存解析/拒绝函数引用由then 调用返回,以防止它和任何后续的链式承诺本身被过早地进行垃圾收集。

    在延迟模型下,建议您不能以这种方式设置承诺链,因为您需要对链中的 first 承诺的引用才能解决或拒绝它。代码变得更像

    var promise = new Promise(); // no executor
    promise.then(something).catch(handleError);
    initiateOperation( promise);
    

    然后在操作响应代码中异步

    promise.resolve(value);  // if no error occurred
    promise = null;          // explicit discard of first promise reference to allow GC?
    

    ES6 承诺的一般简约方法现在开始看起来很有希望(哎哟)。我很同情你在学习 Promise 是如何工作的过程中遇到的困难——一段有趣的旅程!!!

    【讨论】:

    • 不,您不需要在异步回调中显式丢弃对promise 的引用,就像您不需要在执行程序中显式丢弃对resolve/reject 的引用一样范围。
    【解决方案3】:

    您的版本不是异常安全的,而 Promises/A+ 是安全的,因为它们被 Promise 构造函数捕获。

    【讨论】:

    • 很好的答案,谢谢。我认为通过提及这一点,所有介绍性文档和教程都会得到很大的改进——我的大脑只是不想吸收它看不到原因的东西!
    猜你喜欢
    • 1970-01-01
    • 2019-01-25
    • 2018-02-18
    • 1970-01-01
    • 2014-06-02
    • 2017-05-11
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多