我想深入了解Promises如何在内部工作。 因此我有一些示例代码:
var p1 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
var p2 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
},2000);
});
function chainPromises(){
return p1.then(function(val) {
console.log("p1");
return p2.then(function(val) {
console.log("p2");
return val;
});
});
}
chainPromises().then(function(val) {
console.log(val);
}
);
这里有link来执行此代码。
正如您所预测的那样,第一个p1被解析,然后是p2,最后一个结果然后打印出resolv值。
但是API引用了以下内容:
"then" returns a new promise equivalent to the value you return from
onFulfilled/onRejected after being passed through Promise.resolve
因此,知道什么时候执行“then”函数会很有趣? 因为代码中的最后“then”被链接到chainPromises(),我首先想到了 它会在函数chainPromises()返回一些东西后执行(在这种情况下是另一个promise)。
如果是这种情况,最后“then”函数的“val”将是返回的promise。 但相反,最终的“然后”等待,直到返回的第一个“然后”内的所有承诺都已解决。 这绝对有道理,因为通过这种方式,“then”功能可以叠加,但是 我不知道如何做到这一点,因为API规范。并没有真正涵盖“then”返回的内容以及执行“then”函数的时间。
或者换句话说,为什么最后的“then”函数会等到所有Promise在chainPromises()函数内解析,而不是像API文档那样等待第一个返回的对象。
我希望我能说清楚我的意思.. :)
答案 0 :(得分:10)
您在这里见证的事情称为递归then
能够解决。 Promises / A +规范中的promise解析过程包含以下子句:
onFulfilled或onRejected返回值x,运行Promise Resolution Procedure [[Resolve]](promise2,x)
ES6承诺规范(承诺解包)包含类似的条款。
这要求当resolve
操作发生时:在promise构造函数中,通过调用Promise.resolve
或在then
链中的情况下,promise实现必须递归地解包返回的值,如果它是一个承诺。
这意味着如果onFulfilled
(then
)返回一个值,请尝试自己“解析”promise值,从而以递归方式等待整个链。
这意味着以下内容:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
例如:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
那:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
这是承诺规范过程中备受争议的主题,第二个链式方法没有表现出这种行为,但是已经讨论过了(仍然可以在Chrome中使用,但很快就会删除)。你可以阅读整个辩论in this esdiscuss thread。 此行为是出于实际原因,因此您无需手动执行此操作。
值得一提的是,其他语言不会这样做,Scala中的未来或C#中的任务都不具备此属性。例如,在C#中,您必须在任务上调用Task.Unwrap
才能等待其链解析。
答案 1 :(得分:6)
让我们从一个简单的角度开始:“chainPromises”返回一个承诺,所以你可以这样看待它:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
一般来说,当从“then”子句中返回一个承诺时,封装承诺的“then”函数只有在内部“then”结束后才会被标记为已完成。
所以,如果“a”是承诺,而“b”是承诺:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
所以输出将是:
B!
Done!
请注意,如果你没有“返回”内部承诺,情况就不会这样了:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
这里我们不知道先输出什么。它可能是“B!”或“完成!”。
答案 2 :(得分:1)
请检查以下有关 promises
工作方式的示例:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1: shoe ticket');
console.log('person2: shoe ticket');
const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ticket');
}, 3000);
});
promiseGirlFriendBringingTickets.then((t) => {
console.log(`person3: show ${t}`);
})
console.log('person4: shoe ticket');
console.log('person5: shoe ticket');
答案 3 :(得分:0)
我不知道在实际的promises库中是如何完成的,但我能够通过以下方式重新创建此功能: 1)每个承诺都有waitingPromises属性; 2)then方法返回一个新的promise,原始promise的waitingPromises属性指向新的promise。
通过这种方式,.then()的链创建了一个类似于链表或结构树的结构(每个promise可以有几个等待的promise)。只有在其父母的承诺之后才能解决承诺。承诺已经解决。 .then方法本身立即执行,但它创建的相应承诺仅在以后解决。 我不确定这是一个很好的解释,并希望了解其他可能的方法。
答案 4 :(得分:0)
承诺then
返回promise object
,而不是promise's resolved value
。我分叉了你的JsFiddle,并添加了我的一些try this。
promise.then
在promise object
解决后立即执行。
答案 5 :(得分:0)
通常代码是同步的-一个语句执行 like(fileopen),并且可以保证下一条语句将紧随 like filewrite()
之后执行。但是在像nodejs 这样的异步操作中,您应该假设
答案 6 :(得分:0)
您可以将Promise
视为某些后台任务的包装。它具有需要在后台执行的功能。
使用promise的最合适的地方是一些代码依赖于某些后台处理,并且它需要知道已执行的后台任务的状态。为此,后台任务本身接受两个回调resolve
和reject
,以便将其状态传达给依赖于它的代码。用外行人的话来说,此代码是promise链中的代码。
当后台任务使用某些参数调用resolve
回调时。它标志着后台操作成功,并将后台操作的结果传递到下一个要执行的下一个then
块。如果调用reject
并将其标记为不成功,则将执行第一个catch
块。
在您的自定义promise
中,您可以将错误obj传递到拒绝回调,以便下一个catch
块知道后台任务中发生的错误。