第 8 题:setTimeout、Promise、Async/Await 的区别
setTimeout
js
console.log("script start"); //1. 打印 script start
setTimeout(function () {
console.log("settimeout"); // 4. 打印 settimeout
}); // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log("script end"); //3. 打印 script end
// 输出顺序:script start->script end->settimeout
Promise
Promise
本身是同步的立即执行函数, 当在 executor
中执行 resolve
或者 reject
的时候, 此时是异步操作, 会先执行 then/catch
等,当主栈完成后,才会去调用 resolve/reject
中存放的方法执行,打印 p
的时候,是打印的返回结果,一个 Promise
实例。
js
console.log("script start");
let promise1 = new Promise(function (resolve) {
console.log("promise1");
resolve();
console.log("promise1 end");
}).then(function () {
console.log("promise2");
});
setTimeout(function () {
console.log("settimeout");
});
console.log("script end");
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
当 JS
主线程执行到 Promise
对象时:
- promise1.then() 的回调就是一个 task
- promise1 是 resolved 或 rejected :那这个 task 就会放入当前事件循环回合的 microtask queue
- promise1 是 pending:这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
- setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况
回到文章开头经典的例子:
js
const p = Promise.resolve(); // 1. p 的状态为 resolve;
(async () => {
await p; // 2. 返回,并将 函数体后面的语句 console.log('await end') 放入下一个事件循环的 microtask queue 中
console.log("await end"); // 6. 执行,打印 await end
})();
p.then(() => {
// 3. p 的状态为 resolve,会把 p.then() 放入当前事件循环的 microtask queue中。
console.log("then 1"); // 4. 执行,打印 then 1
}).then(() => {
console.log("then 2"); // 5. 执行,打印 then 2,当前 microtask queue 结束,运行下一个 microtask queue
});
// 输出结果:then 1->then 1->await end
例如:
js
console.log("script start");
setTimeout(function () {
console.log("setTimeout");
}, 0);
Promise.resolve()
.then(function () {
console.log("promise1");
})
.then(function () {
console.log("promise2");
});
console.log("script end");
// 输出结果:script start->script end->promise1->promise2->setTimeout
async await
js
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
async1();
console.log("script end");
// 输出顺序:script start->async1 start->async2->script end->async1 end
async
函数返回一个 Promise
对象,当函数执行的时候,一旦遇到 await
就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async
函数体。
举个例子:
js
async function func1() {
return 1;
}
console.log(func1());
很显然,func1
的运行结果其实就是一个 Promise
对象。因此我们也可以使用 then
来处理后续逻辑。
js
func1().then((res) => {
console.log(res); // 1
});
await
的含义为等待,也就是 async
函数需要等待 await
后的函数执行完成并且有了返回结果( Promise
对象)之后,才能继续执行下面的代码。await
通过返回一个 Promise
对象来实现同步的效果。