async 函数总览:
async 函数就是 Generator 函数的语法糖。
1、async 函数语法:
async 函数的常见使用形式:
//函数声明式
async function () {}
//函数表达式
let test = async function () {];
//还可以写成箭头函数: let test = async () => {};
//对象方法
let obj = { foo: async function () {}};
//写进class里面
class Test {
constructor () { }
async getTxt (url) {
return await getText(url);
}
}
let test = new Test();
test.getTxt ('/wamp/www/aaa.php').then(val => console.log(val));
//this is a async function test!
async 函数返回的是一个Promise 对象,return 出去的返回值就是then()
中回调函数的参数;
let getText = function (url) {
let promise = new Promise((resolve, reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readystate == 4) {
if (xhr.status == 200) {
resolve(xhr.responseText);
throw new Error('test');
}else{
reject(xhr.status);
}
}
}
});
return promise;
};
async function fn () {
let text = await getText('/wamp/www/aaa.php');
console.log(text); //text 内容是:this is a async function test!
return text;
}
fn().then((val)=>{
console.log(val);
});
//this is a async function test!
因为async 函数返回的是一个Promise 对象,所以就要看看这个对象的状态的变化情况:
async 函数返回的Promise 对象的状态,由 async 内部所有的 await 命令后面跟着的 Promise 对象共同决定;
要么await 后面的所有promise 对象的状态确定为“成功”,async 函数状态随之确定为“成功”;
要么有一个 await 函数后面的Promise 对象状态确定为“失败”,async 函数状态随之确定为“失败”,然后async 函数中断执行(遇到return ,async 函数也会中断执行)。
换句话说,只有返回的Promise 对象状态确定下来,它才会执行 then() 方法中的回调函数;
2、await 命令的用法:
正常情况下,await 命令后面跟一个 Promise 对象,如果不是,引擎也会先用 Promise.resolve()
来转换一下,所以就不用我们瞎操心了;
await 后面跟着的 Promise 对象如果状态为“失败”,reject(reason)
出去的 reason 会被 async 返回的Promise 对象的catch()
方法捕抓到(当然你也可以将这个错误 给return 出去,如果不嫌多此一举的话)。
async function test () {
await Promise.reject('Uncaught RangeError: Invalid array length');
//也可以加上return
//let err = await Promise.reject('Uncaught RangeError: Invalid array length');
//return err;
}
test().then(val => console.log(val))
.catch(error => console.log(error));
上面已经提及,只要await 后面有一个Promise 对象的状态为“失败”,async 函数就会中断执行,如果想async 函数继续执行,应该怎么解决?
有两种方案:
第一种是利用try{ } catch(error){ }
;
第二种是直接给await 后面的Promise 对象加上catch()
方法,处理出现的错误;
let test = async function () {
try{
await Promise.reject('出错啦,老哥');
//这里还可以放多个await
} catch (error) {
console.log(error);
}
//第二种方案:
//await Promise.reject('出错啦,老哥').catch(err => console.log(err));
await Promise.resolve('hello world');
};
test().then(val => console.log(val));
//出错啦,老哥
//hello world
多提一句:如果多个 await 后面的异步操作没有一定的继发依赖,大可以将他们写成并发的,同时执行效率更高:
//比如
let foo = await foo();
let bar = await bar();
//上面的两个异步操作没有继发关系,就可以让他们一起执行啦,这样写:
let [foo, bar] = await Promise.all([foo(), bar()]);
3、async 函数实现原理探究:
利用Generator 函数 和 自动执行器 spawn 就可以实现 async 函数:
async function () {}
//equal to
function () {
return spawn (function* () {} );
}
下面就来看看 spawn()
自行执行器的具体原理:
function spawn (genFn) {
// spawn 最后返回出去的是个 Promise 对象
return new Promise ( (resolve, reject) => {
let gen = genFn(); // Generator 函数genFn() 返回的一个遍历器对象
function nextFn () {
return gen.next();
}
function step (nextFn) {
try {
let next = nextFn();
} catch (e) {
return reject(e);
}
if (next.done) {
resolve(next.value);
}
Promise.resolve(next.value).then( (val) =>{
step( () => return gen.next(val) );
}, (e) => {
step( () => return gen.next(e) );
});
}
step( () => return gen.next(undefined) );
});
}