async、await
ES7 新出的异步编程 API。
// 函数修饰符,控制函数返回 promise 实例
// + 函数内部执行报错,则返回失败的 promise 实例,值是失败的原因
// + 如果自己返回一个 promise,以自己返回的值为主
// + 返回一个非 promise 的话,会自动包装成 promise
// + 如果函数内部做了异常捕获,则还是成功态
async function fn() {
console.log(a);
return 10;
}
console.log(fn());
使用 async 的主要目的,是为了在函数内部使用 await
function api(interval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(interval);
console.log(interval);
}, interval)
})
}
// 这么写的话,我们发现 1s 后输出 1000,再过 2s 后 输出 3000
// 怎么改成串行的呢,await 就可以做这件事
function func() {
api(1000);
api(3000);
}
// await 后面跟的是 promise 实例 「如果不是,浏览器会帮我们转成 promise 实例」
// await 返回一个成功态的值
// + 比如 var data = await 1 => Promise.resolve(1), data 为 1
// await 是异步微任务
// + 函数体中遇到 await,后面代码该咋地咋地,但是(左边和下面的代码)会当成一个微任务
async function func () {
await api(1000);
await api(3000);
}
func();
await 一个失败的 promise
失败态的 promise 会切断 await 后面冻结的代码执行,包括 await 语句左边的 console 或者 赋值
// await 表达式会暂停整个 async 函数 的执行进程并让出其控制权
// await 中断它之后的代码(包括左边的代码)执行
// + await 后面的 priomise 实例是成功态之后,才会把之前暂停的代码执行
// + 如果后面的 promise 实例是失败的,则下面的代码就不再执行了
function api(interval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// console.log(xxx); // 等同于 rejected
reject(1);
}, interval)
})
}
// 这么写的话,我们发现 1s 后输出 1000,再过 2s 后 输出 3000
// 怎么改成串行的呢,await 就可以做这件事
async function func () {
console.log(await api(1000)); // 不打印 但是内部抛错 Uncaught (in promise) 1
console.log(2222); // 不执行
}
func();
串行的 promise 调用
var resolveAfter2Seconds = function resolveAfter2Seconds() {
console.log('starting slow promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('slow');
console.log('slow promise is done');
}, 2000);
});
}
var resolveAfter1Seconds = function resolveAfter1Seconds() {
console.log('starting fast promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('fast');
console.log('fast promise is done');
}, 1000);
});
}
var sequeial = async function sequential() {
console.log('== SEQUENTIAL START==');
const slow = await resolveAfter2Seconds();
console.log(slow);
const fast = await resolveAfter1Seconds();
console.log(fast);
}
sequeial();
// == SEQUENTIAL START==
// starting slow promise
// 2s 后 'slow promise is done'
// "slow"
// starting fast promise
// 又 1s 后 fast promise is done
// fast
并行的 promise 调用
var resolveAfter2Seconds = function resolveAfter2Seconds() {
console.log('starting slow promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('slow');
console.log('slow promise is done');
}, 2000);
});
}
var resolveAfter1Seconds = function resolveAfter1Seconds() {
console.log('starting fast promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('fast');
console.log('fast promise is done');
}, 1000);
});
}
var concurrent = async function concurrent() {
console.log('== concurrent START ==');
const slow = resolveAfter2Seconds();
const fast = resolveAfter1Seconds();
console.log(await slow);
console.log(await fast);
}
concurrent();
// == concurrent START==
// starting slow promise
// starting fast promise
// 1s 后 'fast promise is done'
// 又 1s 后 'slow fast is done'
// slow
// fast
- 首先输出 "== concurrent START=="
- resolveAfter2Seconds 方法执行,输出 'starting slow promise',然后 slow 延时器作为一个宏任务在 eventTable 注册,并于 2s 后把回调塞进宏任务执行队列。
- resolveAfter1Seconds 方法执行,输出 'starting fast promise',然后 fast 延时器作为一个宏任务在 eventTable 注册,并于 1s 后把回调塞进宏任务执行队列。
- await slow 执行,需要先计算 slow 结果,再打印,并把之后的代码作为一个微任务在 eventTable 中注册,等 slow 延时器 返回结果(差不多 2s)之后,再将其后代码塞进微任务执行队列(标记为可执行)。
- 同步代码执行完毕,微任务队列没有可执行的微任务,检查微任务队列(最快的微任务需要 2s 后可以执行,准确来讲是依赖 slow 延时器返回结果),检查宏任务队列(最快的宏任务需要 1s 后执行),所以先执行 fast 延时器宏任务, 输出 "fast promise is done"
- 此时刚过 1s,微任务队列还没有可执行的微任务,检查微任务队列(最快的微任务是依赖 slow 延时器返回结果),检查宏任务队列(最快的宏任务 slow 是需要 1s 后执行),所以 slow 宏任务执行,输出 "slow promise is done"
- slow 微任务执行,输出 "slow", 遇到 await fast,创建一个新的 fast 微任务(左边的打印和下面的代码,这里下面没有代码了),放入微任务队列,标记为可执行
- slow 微任务执行完毕出列,检查微任务队列,发下还有个 fast 微任务,执行返回 "fast"
- fast 微任务执行完毕出列,此时微任务队列清空,检查宏任务队列,发现没有可执行或待执行的宏任务,事件循环结束。
Promise.all 去做并行调用
var resolveAfter2Seconds = function resolveAfter2Seconds() {
console.log('starting slow promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('slow');
console.log('slow promise is done');
}, 2000);
});
}
var resolveAfter1Seconds = function resolveAfter1Seconds() {
console.log('starting fast promise');
return new Promise(resolve => {
setTimeout(function() {
resolve('fast');
console.log('fast promise is done');
}, 1000);
});
}
var concurrentPromise = function concurrentPromise() {
console.log('== CONCURRENT START Promise.all ==');
return Promise.all([resolveAfter2Seconds(), resolveAfter1Seconds()]).then(
messages => {
console.log(messages[0]);
console.log(messages[1]);
});
}
concurrentPromise();
// == CONCURRENT START Promise.all ==
// starting slow promise
// starting fast promise
// 1s 后输出 fast promise is done
// 再过 1s 输出 slow promise is done
// slow
// fast
值得一提的是:
// .then 后的 onfullfilld 和 onRejected 整个是一个异步微任务。
messages => {
console.log(messages[0]);
console.log(messages[1]);
}