从一道Promise执行顺序的题目看Promise实现
作者:CQITer小编 时间:2018-03-14 16:10
之前在网上看到一道Promise执行顺序的题目——打印以下程序的输出:
new Promise(resolve => {
console.log(1);
resolve(3);
}).then(num => {
console.log(num)
});
console.log(2)
这道题的输出是123,为什么不是132呢?因为我一直理解Promise是没有异步功能,它只是帮忙解决异步回调的问题,实质上是和回调是一样的,所以如果按照这个想法,resolve之后应该会立刻then。但实际上并不是。难道用了setTimeout?
如果在promise里面再加一个promise:
new Promise(resolve => {
console.log(1);
resolve(3);
Promise.resolve().then(()=> console.log(4))
}).then(num => {
console.log(num)
});
console.log(2)
执行顺序是1243,第二个Promise的顺序会比第一个的早,所以直观来看也是比较奇怪,这是为什么呢?
Promise的实现有很多库,有jQuery的deferred,还有很多提供polyfill的,如es6-promise,lie等,它们的实现都基于Promise/A+标准,这也是ES6的Promise采用的。

为了回答上面题目的执行顺序问题,必须得理解Promise是怎么实现的,所以得看那些库是怎么实现的,特别是我错误地认为不存在的Promise的异步是怎么实现的,因为最后一行的console.log(2)它并不是最后执行的,那么必定有某些类似于setTimeout的异步机制让上面同步的代码在异步执行,所以它才能在代码执行完了之后才执行。
当然我们不只是为了解答一道题,主要还是借此了解Promise的内部机制。读者如果有时间有兴趣可以自行分析,然后再回过头来比较一下本文的分析。或者你可以跟着下面的思路,操起鼠标和键盘和我一起干。
这里使用lie的库,相对于es6-promise来说代码更容易看懂,先npm install一下:
npm install lie
让代码在浏览器端运行,准备以下html:
<!DOCType html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="node_modules/lie/dist/lie.js"></script>
<script src="index.js"></script>
</body>
</html>
其中index.js的内容为:
console.log(Promise);
new Promise(resolve => {
console.log(1);
resolve(3);
Promise.resolve().then(()=> console.log(4))
}).then(num => {
console.log(num)
});
console.log(2);
把Promise打印一下,确认已经把原生的那个覆盖了,对比如下:

因为原生的Promise我们是打不了断点的,所以才需要借助一个第三方的库。
我们在第4行的resolve(3)那里打个断点进去看一下resolve是怎么执行的,层层进去,最后的函数是这个:

我们发现,这个函数好像没干啥,它就是设置了下self的state状态为FULFILLED(完成),并且把结果outcome设置为调resolve传进来的值,这里是3,如果resolve传来是一个Promise的话就会进入到上图187行的Promise链处理,这里我们不考虑这种情况。这里的self是指向一个Promise对象:





