先看下面这道面试题:javascript
let counter = 0; const increment = new Promise(resolve => { counter++; resolve(); }); await increment; await increment; console.log(counter); // 结果是什么?
你认为 counter
的值是什么?前端
什么是 promise ?这是否意味着“稍后再作”?java
实际上应该把 promise 当作是一个状态机。程序员
promise 以“pending”状态开始它的生命周期。若是你要在这个状态下查询结果,则必须排队。面试
根据 ECMAScript 标准文档中的描述(https://tc39.es/ecma262/),上面 Promise
构造函数会当即调用咱们的执行器函数。它的 counter++
反作用运行。不带任何参数调用resolve()
,在 promise 上存储一个 undefined
结果,并将其状态提高为“fulfilled”。segmentfault
第一个 await
运行。 await
等同于在你的 promise 上运行.then(onFulfilled)
,将 onFulfilled
设置为“前面的代码”。这项工做做为微任务进入队列。 JavaScript 以先进先出的顺序执行微任务;控制最终返回给咱们的函数。promise
第二个 await
没有什么不同的地方。它建立一个微任务给我 promise 的结果并提早运行代码,而后等待 JavaScript 进行调度。服务器
反作用只在 Promise
构建期间运行过一次,因此 counter
为 1
.微信
咱们推迟了工做吗?没有。promise 是同步建立和执行的。可是咱们使用了 await
来处理其余微任务。多线程
那么应该怎样推迟工做?
const microtask = Promise.resolve() .then(() => console.log('hello from the microtask queue')); const macrotask = new Promise(resolve => // 排队宏任务 setTimeout(() => { console.log('hello from the macrotask queue'); resolve(); }) // 没有解决,promise 仍处于 pending 状态 ); // 这是最早输出的; 咱们成功地推迟了工做 console.log('hello from the original execution context'); // yield 调度器; 运行 .then() 并输出日志 await microtask; // yield 调度器; promise 的状态是 fulfilled ,因此没有日志输出 await microtask; // yield 调度器; 执行全部微任务,而后运行宏任务并输出日志 await macrotask; // yield 调度器; promise 已经完成,因此没有日志输出 await macrotask;
Promise
构造函数是同步运行的,可是咱们没必要同步调用 resolve()
。 Promise.prototype.then
也推迟了工做。
Promise
构造函数和 Promise.prototype.then
都不会重复工做。
这意味着 promise 能够用来记住异步计算。若是你用了一个 promise,并且想要稍后再次用到它的结果,应该考虑保留 promise 而不是它的结果。