关于Promise的超难面试题解读

发布时间 2023-08-10 17:48:54作者: 吕伟昊

让我来看一下题目,如下所示

Promise.resolve().then(()=>{
				console.log(0);
				return Promise.resolve(4);
			}).then((res)=>{
				console.log(res);
			});
			
			Promise.resolve().then(()=>{
				console.log(1);
			}).then(()=>{
				console.log(2);
			}).then(()=>{
				console.log(3);
			}).then(()=>{
				console.log(4);
			}).then(()=>{
				console.log(5);
			}).then(()=>{
				console.log(6);
			})

该代码中有两个Promise,第一个Promise状态自然是fullfield,我们记作pr1:F。

console.log(0);
return Promise.resolve(4);

根据promiseA+规范,我们得出在调用then方法之后必然产生一个新的promise,并由下面两行代码决定,我们记作p0:p,此时他的状态是pending。
此时完成状态的promise方法调用then方法,会把其中的回调函数加到微队列,我们记作micro:0,
接下来又调用了一个then方法,那有产生了一个promise,我们记作pres:p。
接下来新的promise方法,又产生了一个fullfield状态的promise,记作pr2:f,接下来产生的pending状态记作p1:p,加入到微队列,如此类推,产生p2:p,p3:p,p4:p,p5:p,p6:p。
此时我们的微队列micro:0,1。但是问题来了,我们的返回值是一个promise函数,这是V8引擎会如何处理呢?
来,我们看一下A+规范,如果你的then方法返回值是一个promise,那么该then方法的状态将由返回值promise决定,问题关键点了来了我们不知道他是如何保持一致的,同步还是异步呢?
他会在p4的then方法里完成p0,他会将这些步骤放到微队列中执行,我们看一下V8的源码:

const task=NewPromiseResolveThenableJobTask(
   promise,uUnsafeCast<JSReceiver>(resolution),
   UnsafeCast<Callable>(then));
return EnqueueMicrotask(task.context,task);

p4调用了他的then方法并加入到微队列,此时p0还是pending状态,此时控制台输出0,p1输出1状态占位fullfield,此时两个promise的第一次then方法微队列执行完毕,输出0,1,放到微队列的p4开始执行,promise输出无效果,把p4then方法加入到微队列,执行then方法,此时p0的状态为fullfield,立刻把res放到微队列p4,先p1输出p2是输出的是promise(4),然后输出p3,输出then方法,依次类推输出56,最终结果就是0123456。