async是‘异步’的简写,async声明一个function是异步的,而await用于等待一个异步方法执行完成,await只能出现在async函数中。
async await和generator的写法很像,就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成await
但async 函数对 Generator 函数做了改进:
1、内置执行器:Generator函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器.也就是说,async 函数的执行,与普通函数一模一样。
2、更好的语义:async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
3、更广的适用性: co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
async负责返回一个Promise对象,如果在async函数中return一个直接量,async会将这个直接量用Promise.resolve()封装成一个Promise对象,如果async函数没有返回值。它会返回Promise.resolve(undefine)。
一般的都使用await去等待一个async函数完成,不过按语法说明,await等待的是一个表达式,这个表达式的计算结果是Promise对象或者其他值,所以啊await后面可以接收Promise对象或者直接量。
如果await等到的不是一个Promise对象,那跟着的表达式的计算结果就是要等的东西,如果是一个Promise对象,awiait会阻塞后面的的代码,直到promise对象resolve,得到resolve的值作为await表达式的运算接结果。
注意点: 只要其中一个Promise对象变为reject状态,那么整个async函数都会中断操作。如果状态是resolve,那么他的返回值则会变成resolve的值, 所以使用await时 最好把await 放入try{}catch{}中
async/await技术背后的秘密其实是Promise和生成器的应用,再往底层就是微任务和协程应用(生成器是协程的一种实现方式。
协程:协程是一种比线程更加轻量级的存在,一种线程上可以存在多个协程,但线程上同一时刻只能运行一个协程,比如当前执行的是协程A,如果要去启动协程B,就要让协程A把线程的控制权交给协程B,这就实现了A暂停执行,B恢复执行。同样的也可以从B协程启动A协程。
通过具体的例子来了解一下。
async function fun(){
console.log(1);
let a=await 'await';
console.log(a);
console.log(3);
}
console.log(0);
let aa= fun();
console.log(aa)
console.log(4);
- 首先执行console.log(0)这个语句,打印0。、
- 然后执行fun函数,因为这个函数被async标记,所以js引擎会保存当前的调用栈,而去执行fun函数中语句,所以首先会执行console.log(1)
- 接下来会执行await语句,当执行await "await"时,会自动创建一个Promise对象,最终将resolve的值返回a
let promise=new Promise((resolve,reject)=>{
resolve('await');
})
- js引擎暂停当前协程的执行,将主线程的控制权交给父协程执行,同时会将async创建的promise对象返回给父协程,这里传给了aa
- 接下来执行console.log(aa)和console.log(4),然后主协程将主线程的控制权交给fun协程,最终就会执行console.log(a) console.log(3),执行完成之后将控制权还给父协程。
-
await后面的参数
awiat后面可以跟任何js表达式,如果awiat后面跟着的是Promise
对象则会等待函数执行完成再去执行下面的代码,如果跟着的是正常的表达式则会立即执行。
后面是Promise对象
function fun(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("我是Promise");
}, time);
})
}
async function fuc() {
let result = await fun(2000);
console.log("123")
console.log(result);
console.log("456")
}
fuc();//先回等待两秒,两秒后依次打印123、我是Promise、456
后面是正常表达式
function fun(time) {
console.log("我是js表达式");
setTimeout(() => {
console.log('1');
}, time);
return 2;
}
async function fuc() {
let result = await fun(2000);
console.log("123")
console.log(result);
console.log("456")
}
fuc();//依次输出 "我是js表达式"、123、2 456、1