异步编程主要实现
回调函数、setTimeout, Promise, Generator/yield, async/await等
async/await
promise的语法糖
await后对象状态变为resolve
async关键字用来声明异步函数,返回一个Promise对象, 若无明显返回值则返回Promise.resolve(undefined)
async function fn() {
return 1; // Promise.resolve(1)
}
fn().then(console.log) // 1
await和yield类似,会让出JS执行线程,对后面对象进行“解包”
await期待一个实现thenable接口的对象,通常为Promise对象。如果为常规值,则当作Promise.resolve(常规值)
async function fn() {
const res1 = await 1;
const res2 = await { then: (callback) => callback('thenable') }
console.log(res1); // 1
console.log(res2); // thenable
}
reject情况
我们知道单独的Promise.reject不会被异步函数捕获,抛出未捕获错误
try {
new Promise((resolve, reject) => {
reject('err')
})
} catch (error) {
console.log(error); // (node:58599) UnhandledPromiseRejectionWarning: err
}
但是!await会返回
(async function() {
try {
await Promise.reject('err')
} catch (error) {
console.log(error); // err
}
})()
实现sleep()
之前找实习面试经常会要求写一些异步函数
比如:输入一个数n,函数实现输出1~n,要求每隔1s输出一个。
我之前的丑陋写法👇
const fn = function(count) {
let i = 1;
const print = () => {
if (i > count) return;
setTimeout(() => {
console.log(i++);
print();
}, 1000);
}
print()
}
async/await写法
const fn = async function(count) {
for (let i = 1; i <= count; i++) {
await new Promise(resolve => setTimeout(() => {
console.log(i);
resolve();
}, 1000));
}
}
在事件循环中的表现
await后跟promise对象时,会先向消息队列中添加一个改变Promise状态的任务,等到取出处理程序后再向队列中添加一个恢复执行的任务。