javascript Promise API是否比它需要的更复杂?

javascript Promise API是否比它需要的更复杂?,javascript,promise,es6-promise,Javascript,Promise,Es6 Promise,我想我终于在很大程度上改变了对javascript/ES6承诺的看法。这不容易!但设计上有些东西让我困惑 为什么承诺构造函数接受回调?鉴于回调是立即调用的,调用方难道不能直接执行该代码,从而避免不必要的“不要打电话给我,我会打电话给你”的思维扭曲吗 下面是我认为的Promise用法的典型示例,它是从Jake Archibald的Javascript Promises教程中复制的,去掉了注释 它是XMLHttpRequest GET请求的基于承诺的包装器: function get(url) {

我想我终于在很大程度上改变了对javascript/ES6承诺的看法。这不容易!但设计上有些东西让我困惑

为什么承诺构造函数接受回调?鉴于回调是立即调用的,调用方难道不能直接执行该代码,从而避免不必要的“不要打电话给我,我会打电话给你”的思维扭曲吗

下面是我认为的Promise用法的典型示例,它是从Jake Archibald的Javascript Promises教程中复制的,去掉了注释

它是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();
  });
}
对我来说,如果按照如下方式重写上述代码,使用我想象中的一种稍微不同的承诺,使用无arg构造函数和resolve/reject方法,则更容易理解上述代码:

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;
}
MyAsierTounderstandPromise在承诺方面并不难实现。起初,我试图使它成为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 API的制作,每个人似乎都为此感到高兴和自豪,所以我想知道他们是怎么想的。

您的版本并不例外安全,而Promises/a+是安全的,因为它们被
Promise
构造函数捕获。

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

var promise = new Promise(executor).then(something).catch(handleError);
promise变量保留为.catch方法调用返回的promise。整个链或承诺对象实际上不会被executor函数持有的resolve/reject函数引用垃圾收集。如果调用了resolve(通常在执行器返回后但在让resolve/reject函数超出范围之前异步调用),
则调用
侦听器“某物”,Promise platform内部执行器持有
调用返回的Promise的resolve/reject函数引用,然后调用
以防止它和任何后续链接的Promise本身被过早地垃圾收集

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

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承诺的一般最小化方法现在开始看起来很有希望(哎哟)。我很同情你在学习承诺如何运作方面的困难——一次有趣的旅程

承诺旨在用作价值观。ES构造函数方法封装了承诺的创建,然后可以像值一样传递。当传递该值时,该值的使用者不需要
resolve
reject
,因此这些函数不应该是公共API的一部分


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

您的“easierToUnderstandPromise”就像jQuery。在某种程度上是延迟的。对于您的设计,返回的承诺必然公开解析/拒绝方法。我在某个地方读过为什么这是一件“坏事”,但我找不到我读过的资源(我已经读了好几年了)。还有延迟模式,但回答很好,谢谢。我认为所有的介绍性文档和教程都会因为提到这一点而得到极大的改进——我的大脑只是不想吸收它看不出原因的东西!不,您不需要在异步回调中显式放弃对
promise
的引用,就像您不需要在executor范围中显式放弃对
resolve
/
reject
的引用一样。