首页 文章

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

提问于
浏览
5

我想我终于在大多数情况下都围绕着javascript / ES6 Promises . 这并不容易!但是有些东西让我对这个设计感到困惑 .

为什么Promise构造函数会进行回调?鉴于立即调用回调,调用者不能只执行该代码,从而避免一个不必要的心灵弯曲“不要打电话给我,我会打电话给你”?

这里's what I think of as the prototypical example of Promise usage, copied from Jake Archibald'的Javascript Promises教程http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest,删除了评论 .

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

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;
}

就Promise而言,MyEasierToUnderstandPromise并不太难实现 . 起初我尝试将它变成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,每个人似乎都很高兴并为此感到自豪,所以我想知道他们在想什么 .

3 回答

  • 5

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

  • 6

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

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

  • 1

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

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

    将promise变量设置为.catch方法调用返回的promise . 实际上,防止整个链或Promise对象被执行程序函数持有的解析/拒绝函数引用进行垃圾收集 . 如果调用resolve(通常在执行程序返回之后但在让解析/拒绝函数超出范围之前异步),则调用 then listener "something",并使用Promise平台内部执行程序保存 then 返回的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承诺的一般小规模方法现在开始看起来很有希望(哎哟) . 我很同情你学习承诺如何运作的困难 - 一个有趣的旅程!

相关问题