ES7之async,await
一、基本用法
async,await函数是ES7中引入的语法。与Generator,Promise有很大的关系。
async
使用async修饰的函数,会返回一个Promise对象。
async function func() {
return 'a';
}
let res = func();
console.log(res); //Promise { 'a' }
res.then((value)=>{
console.log(value); //a
})
await
async函数中可能包含await表达式,执行到到await表达式时,就会暂停当前函数的执行,直到触发的异步操作执行完成。
await函数只能在async函数中使用,否则会报语法错误。
await表达式的值根据await后面的表达式的值有关:
- 如果是Promise对象: async函数停止执行,等待Promise对象Resolve,最后表达式的值即为Resolve的值
- 如果不是Promise对象:最后表达式的值为await最后表达式的值。
function testAwait (x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function AsyncFunc() {
let x = await testAwait ("hello world");
console.log(x);
}
AsyncFunc();
二.原理
function sumAsync (a, b) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve((a+b));
},1000);
});
}
function * g () {
let sum = yield sumAsync(1,2);
return sum;
}
let it = g();
let promise = it.next();
promise.value.then(value => {
console.log(value);
})
//相比于
async function g() {
let sum = await sumAsync(1,2);
return sum;
}
上面的代码中,可以看到async函数于generator函数十分相似,其实async就是generator函数,只不过多了一个执行器。
执行器:在上面的代码中 generator函数的执行需要两个步骤
let it = g();
let promise = it.next();
promise.value.then(value => {
console.log(value);
})
可以写一个执行器excute()来封装一下上面的代码。
//模拟一个异步请求
function getNum (num) {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(num);
},1000)
});
}
//执行器
function excute (generator,...args) {
let iter = generator.apply(this,args);
let n = iter.next();
if(n.done) {
return new Promise((resolve => resolve(n.value)));
}else{
return new Promise(((resolve) => {
n.value.then((ret) => {
_r(iter,ret,resolve)
})
}));
}
}
function _r (iter,ret,resolve) {
let n = iter.next(ret);
if(n.done) {
resolve(n.value);
}else {
n.value.then(ret=>{
_r(iter,ret,resolve);
});
}
}
//Generator函数
function * generator () {
let r1 = yield getNum(1);
console.log(r1);
let r2 = yield getNum(2);
console.log(r2);
console.log('end');
}
excute(generator).then(value => {
console.log(value);
})
//输出
//1
//2
//end
//undefined
总之,async函数就是内置了执行器的generator函数,当执行async函数时,js引擎会调用执行器。
相关面试题
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
- 首先,打印’script start’,执行到setTimeout,把setTimeout的内容放到宏任务中.
- 接着执行到async1()函数,首先打印’async1 start’,执行到await表达式,发现async2() 是一个async修饰的函数,所以先执行async2()函数里的代码,返回的Promise会被放到回调队列中等待,然后await会让出进程,跳出async1()函数,执行后面的代码。
- 之后执行Promise中的代码,打印’promise1’,然后把.then放到回调队列中,接着打印script end
- 同步的事件都循环执行完了,执行回调队列的内容,打印promise2。然后接着执行async1()函数后面的代码,打印’async1 end’,
- 执行下一个宏任务,打印setTimeout.
Async,Await 是否可以取代Promise
const timeoutFn = function(value,timeout){
return new Promise(function(resolve){
return setTimeout(()=>{resolve(value)},timeout);
});
}
async function getABC() {
let A = await timeoutFn(2,2000); // 2 second to finish
let B = await timeoutFn(2,2000); // 4 second to finish
let C = await timeoutFn(3,3000); // 3 second to finish
return A*B*C;
}
getABC()
.then((res)=>{
console.log(res)
//12
});
对于上面的情况,三个变量不相互依赖,每一个表达式都会等待上一个返回结果,所以会在7s后返回结果。
如果使用Promise.all(),允许我们同时发送所有请求,异步触发,会在3返回结果12
const timeoutFn = function(value,timeout){
return new Promise(function(resolve){
return setTimeout(()=>{resolve(value)},timeout);
});
}
async function getABC() {
let res = await Promise.all([timeoutFn(2,2000),timeoutFn(2,2000),timeoutFn(3,3000)]);
return new Promise(resolve => resolve(res.reduce((total,value)=>total+=value)))
}
getABC()
.then((res)=>{
console.log(res)
//12
});