【发布时间】: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@ 完成后。
有时我可能会认为:这就是它的方式(如何链接耗时的承诺),或者它是语言特性,你可以认为它是通过魔法发生的(如果它是语言功能)。
但是,如果履行处理程序返回一个新的承诺,这是否是通过标准程序完成的?
我在下面写了一些关于如何完成的草稿。用几句话来说,就是
-
p1是第一个承诺。 -
then()返回一个新的承诺p2 -
then()记住p2是什么,作为p1的内部属性。 - 当传递给
then的实现处理程序最终被调用(当p1被解析时),返回值被检查。如果它是一个具有名为then的属性并且是一个函数的对象,那么这个对象将被视为一个thenable,这意味着它可以是一个真正的promise,也可以只是一个虚拟的thenable(我们称之为p1_New)。 - 立即调用:
p1_New.then(() => { resolveP2() }) - 假设
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 步:
- 立即调用:
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