理解 JS Promise

IT技术 javascript promise
2021-03-18 08:59:32

我想更深入地了解 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);
});

这是执行此代码链接

正如您所预测的那样,首先解析 p1,然后解析 p2,最后打印解析值。

但是 API ref 声明如下:

"then" 返回一个新的Promise,相当于你在通过 Promise.resolve 后从 onFulfilled/onRejected 返回的值

因此,知道“then”函数究竟何时执行会很有趣?因为代码中的最后一个“then”链接到 chainPromises(),我首先想到它会在函数 chainPromises() 返回一些东西(在这种情况下是另一个Promise)之后执行。

如果是这种情况,最终“then”函数的“val”将是返回的promise。但是相反,最后的“then”一直等到第一个“then”中返回的所有Promise都已解决。这绝对是有道理的,因为通过这种方式,“then”函数可以堆叠,但我不明白这是如何完成的,因为 API 规范。并没有真正涵盖“then”返回的内容以及“then”函数的执行时间。

或者换句话说,为什么最终的“then”函数要等到所有的 Promises 在 chainPromises() 函数内被解析,而不是像 API 文档所说的那样等待第一个返回的对象。

我希望我能说清楚我的意思.. :)

6个回答

关于 Promise 解析

您在这里看到的事情称为recursiveable thenresolutionPromises/A+ 规范中的 promise 解析过程包含以下子句:

onFulfilled 或 onRejected 返回值 x,运行 Promise 解析过程 [[Resolve]](promise2, x)

ES6 Promise规范(promises unwrapping)包含一个类似的条款。

这要求当resolve操作发生时:在Promise构造函数中,通过调用Promise.resolve或在您的情况下在then链中,如果它是Promise,则Promise实现必须递归解包返回值。

在实践中

这意味着如果onFulfilled(the 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");
});

这是个好主意吗?

在 promises 规范过程中,这一直是很多争论的话题,讨论了没有表现出这种行为的第二种链方法,但决定反对(在 Chrome 中仍然可用,但很快就会被删除)。您可以在此 esdiscuss 线程中阅读整个辩论此行为是出于实用原因,因此您不必手动执行此操作。

其他语言

值得一提的是,其他语言没有这样做,Scala 中的期货或 C# 中的任务都没有这个属性。例如,在 C# 中,您必须调用Task.Unwrap任务以等待其链解析。

让我们从一个简单的角度开始:“chainPromises”返回一个Promise,所以你可以这样看:

// Do all internal promises
var cp = chainPromises();

// After everything is finished you execute the final "then".
cp.then(function(val) {
    console.log(val);
});

一般来说,当从“then”子句中返回一个promise,封装promise的“then”函数只有在内部的“then”完成后才会被标记为完成。

所以,如果“a”是一个Promise,而“b”是一个Promise:

// "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!

注意顺便说一句,如果您不“返回”内部Promise,则情况并非如此:

// "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!” 或“完成!”。

@Naeem,不止一次发生在我身上:)
2021-04-25 08:59:32
@QuicknDirty是,在Promise规范promisesaplus.com解释了这一点-我还补充说,引述了规范的相关部分的答案。
2021-04-29 08:59:32
是的,如果您使用“return”返回“then”中的Promise(第一个示例)。您可以在此处阅读概述:html5rocks.com/en/tutorials/es6/promises/#toc-chaining这不是 API 参考,而是一个简单的解释。
2021-05-02 08:59:32
我只需点击一下即可发布相同的内容:)
2021-05-05 08:59:32
嗯,因此“then”返回一个Promise,该Promise将在“then”中的所有Promise都已解决后解决?是否有一个 API REF 解释了这个返回的Promise?- 这也意味着“then”返回的Promise在解析后评估为其返回的对象,对吗?
2021-05-11 08:59:32

请检查以下有关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');

Promisethen回报promise object,没有promise's resolved value我分叉了你的 JsFiddle,并添加了一些我的试试这个

promise.thenpromise object解决后立即执行

我不知道在实际的 Promise 库中这是如何完成的,但我能够通过以下方式重新创建此功能:1)每个 Promise 都有一个 waitingPromises 属性;2) then 方法返回一个新的promise,原promise的waitingPromises属性指向新的promise。

通过这种方式,.then()s 的链创建了一个类似于链表或树的结构(每个 Promise 可以有多个等待的 Promise)。一个Promise只有在它的“父”Promise被解决后才能被解决。.then 方法本身会立即执行,但它创建的相应Promise仅在稍后解析。我不确定这是一个很好的解释,并且很想了解其他可能的方法。

“.then 方法本身立即执行”是违反规范的。
2021-04-29 08:59:32