【问题标题】:Is it true that the JavaScript ES6 promise has a standard procedure for then() to chain several time-consuming promises with asynchronous tasks?JavaScript ES6 Promise 是否有一个标准的 then() 程序将多个耗时的 Promise 与异步任务链接起来?
【发布时间】:2020-04-17 15:22:50
【问题描述】:

我认为这个问题的简短版本是:如果提供给.then() 的履行处理程序返回一个新的承诺,这个新的承诺如何“解开”.then() 返回的承诺? (展开似乎是 promise 技术中使用的一个术语)。 (如果它没有返回一个新的承诺而只是一个“thenable”,它是如何解包的?)

将几个耗时的异步promise链在一起,比如doing several network fetches described on this page或a series of animations,我认为标准方法是这样表述的:

在传递给.then()的实现处理程序中,创建并返回一个新的promisep,并在传递给创建p的构造函数的执行程序中,做耗时的任务,并解决这个新的promise@ 987654332@ 完成后。

有时我可能会认为:这就是它的方式(如何链接耗时的承诺),或者它是语言特性,你可以认为它是通过魔法发生的(如果它是语言功能)。

但是,如果履行处理程序返回一个新的承诺,这是否是通过标准程序完成的?

我在下面写了一些关于如何完成的草稿。用几句话来说,就是

  1. p1 是第一个承诺。
  2. then() 返回一个新的承诺 p2
  3. then() 记住 p2 是什么,作为 p1 的内部属性。
  4. 当传递给then 的实现处理程序最终被调用(当p1 被解析时),返回值被检查。如果它是一个具有名为then 的属性并且是一个函数的对象,那么这个对象将被视为一个thenable,这意味着它可以是一个真正的promise,也可以只是一个虚拟的thenable(我们称之为p1_New)。
  5. 立即调用:p1_New.then(() => { resolveP2() })
  6. 假设p1_New 是一个真正的承诺。当我们解析p1_New时,它会解析p2,而p2会执行它的“then”实现处理程序,一系列耗时的promise可以继续下去。

所以这是粗略的代码:

let p1 = new Promise(function(resolve, reject) {
    // does something that took 10 seconds
    resolve(someValue);
});

经过上述代码,p1的状态为:

p1 = {
  __internal__resolved_value: undefined,
  __internal__state: "PENDING",
  __internal__executor: function() {    
    // this is the executor passed to the constructor Promise().
    // Something is running and the resolve(v) statement probably
    // will do
    // this.__internal__onResolve(v)
  },

  __internal__onResolve: function(resolvedValue) {

    if (this.__internal__then_fulfillHandler) {   // if it exists
      let vFulfill = this.__internal__then_fulfillHandler(this.__internal__resolved_value);

      // if the fulfillment handler returns a promise (a thenable),
      // then immediately set this promise.then(fn1)
      // where fn1 is to call this.__internal__resolveNewPromise()
      // so as to resolve the promise newPromise that I am returning

      if (vFulfill && typeof vFulfill.then === "function") { // a promise, or thenable
        vFulfill.then(function() {
          this.__internal__resolveNewPromise(this.__internal__resolved_value)
        })
      }
    }

  },

  // in reality, the then should maintain an array of fulfillmentHandler
  //   because `then` can be called multiple times

  then: function(fulfillmentHandler, rejectionHandler) {
    this.__internal__then_fulfillHandler = fulfillmentHandler;

    // create a new promise newPromise to return in any case
    let newPromise = new Promise(function(resolve, reject) {
      this.__internal__resolveNewPromise = resolve;
    });

    // if promise already resolved, then call the onResolve 
    //   to do what is supposed to be done whenever this promise resolves
    if (this.__internal__state === "RESOLVED") {
      this.__internal__onResolve(this.__internal__resolved_value);
    }

    return newPromise;
  }
}

这就是当p1_New 被解析,然后p2 被解析,并且传递给p2.then() 的履行处理程序将继续。

let p2 = p1.then(function() {
  p1_New = new Promise(function(resolve, reject) {
    // does something that took 20 seconds
    resolve(someValue);
  });
  return p1_New;
});

p2.then(fulfillmentHandler, rejectionHandler);

但是what if p1_New is not really a promise, but just a dummy thenable是这样写的:

class Thenable {
  constructor(num) {
    this.num = num;
  }
  then(resolve, reject) {
    alert(resolve); // function() { native code }
    // resolve with this.num*2 after the 1 second
    setTimeout(() => resolve(this.num * 2), 1000); // (**)
  }
}

new Promise(resolve => resolve(1))
  .then(result => {
    return new Thenable(result); // (*)
  })
  .then(alert); // shows 2 after 1000ms

它正在其then() 中执行耗时的任务。这也很好:如果我们看一下上面的第 5 步:

  1. 立即调用:p1_New.then(() => { resolveP2() })

也就是说,立即调用then,并且传入的第一个函数能够解析p2。这样thenable会执行一些耗时的任务,完成后调用它的第一个参数(解析p2的函数),整个序列就可以像以前一样进行。

但在这种情况下,是 then() 执行耗时任务,而不是执行者执行它(执行者传递给新承诺的构造函数)。在某种程度上,就像then() 成为了执行者。

【问题讨论】:

  • 在这里很难说出您真正要问的是什么。仅供参考,您不应该认为链接承诺与耗时的操作有任何关系。它是关于跟踪异步操作的结果(无论是否耗时)。并且同步耗时的操作从使用 Promise 中获得的好处很少。
  • 那是真的...我应该编辑问题...我尝试了一个计算 60000!(阶乘)的承诺,它会阻止 Node 和浏览器(Google Chrome)中的所有内容。我应该说的可能是耗时的异步任务。
  • 承诺与“耗时”无关。它们是关于任何持续时间的异步任务。您可以将同步任务包装在 Promise 中,但正如您已经发现的那样,它不会使它们成为非阻塞的,它仍然会在同步执行期间阻塞 JS 事件循环。
  • 你有很多假设和假设。为什么不只看一下 Bluebird 或 Q 库的代码,它们允许在将 Promise 内置到浏览器之前使用它们?
  • 我不确定您在这个问题中真正要问的是什么。如果要检查您对Promise Resolution Procedure 的理解是否正确,您可以针对Promises/A+ Compliance Test Suite 测试您的实现代码。我当时是为我的own implemenatation 这样做的。

标签: javascript es6-promise thenable


【解决方案1】:

我现在对 promises 理解多了,看来这是标准的方式。

无论实现处理程序返回什么:原始值、不是 thenable 的对象、类似于假 promise 或真实 promise 的 thenable 都将设置为解析 p,其中p 是 then 返回的承诺。

这是标准程序,也就是所谓的展开。我们可以对一个promise进行多层封装,当它从内部解包时,它会一直解包,直到它无法继续。

确实如此,当一个thenable的假promise,或者一个真正的promise被返回时,它会触发这个动作发生在下面:

obj.then(resolveP) 其中resolveP 是可以解析p 的解析函数。

该承诺如何解析p,以及thenable 如何执行异步任务并使用传递给它的第一个参数作为解析函数来“解析”p。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-22
    • 2017-05-24
    • 1970-01-01
    • 2019-09-18
    • 2020-02-18
    • 2020-04-16
    • 2017-10-16
    • 2021-04-18
    相关资源
    最近更新 更多