ES7 明确提出的async 表达式,总算让 JavaScript 对触发器操作形式有了毁灭者软件系统。No more callback hell。
async 表达式是 Generator 表达式的句法糖。采用 关键字 async 来则表示,在表达式外部采用 await 来则表示触发器。
想较于 Generator,Async 表达式的改良是上面五点:内建开伞器。Generator 表达式的继续执行要倚靠开伞器,而 Aysnc 表达式便携式开伞器,初始化形式跟一般表达式的初始化那样更快的句法。async 和 await 相对 * 和 yield 更为句法化更广的精确性。co 组件签订合同,yield 指示前面根本无法是 Thunk 表达式或 Promise第一类。而 async 表达式的 await 指示前面则能是 Promise 或是 原初类别的值(Number,string,boolean,但此时等同同步操作形式)codice是 Promise。async 表达式codice是 Promise 第一类,比 Generator 表达式回到的 Iterator 第一类方便快捷,能间接采用 then() 形式展开初始化Async 与其它触发器操作形式的对照
先表述两个
function fetchUser() {
return new Promise((resolve, reject) => {
fetch(https://api.github.com/users/superman66)
.then((data) => {
resolve(data.json());
}, (error) => {
reject(error);
})
});
}
Promise 形式
/**
* Promise 形式
*/
function getUserByPromise() {
fetchUser()
.then((data) => {
console.log(data);
}, (error) => {
console.log(error);
})
}
getUserByPromise();
Promise 的形式虽然解决了 callback hell,但是这种形式充满了 Promise的 then() 形式,如果处理流程复杂的话,整段代码将充满 then。句法化不明显,代码流程不能很好的则表示继续执行流程。
Generator 形式
/**
* Generator 形式
*/
function* fetchUserByGenerator() {
const user = yield fetchUser();
return user;
}
const g = fetchUserByGenerator();
const result = g.next().value;
result.then((v) => {
console.log(v);
}, (error) => {
console.log(error);
})
Generator 的形式解决了 Promise 的一些问题,流程更为直观、句法化。但是 Generator 的问题是,表达式的继续执行需要倚靠开伞器,每次都需要通过 g.next() 的形式去继续执行。
async 形式
/**
* async 方式 */
async function getUserByAsync(){
let user = await fetchUser();
return user;
}
getUserByAsync()
.then(v => console.log(v));
async 表达式完美的解决了上面两种形式的问题。流程清晰,直观、句法明显。操作形式触发器流程就如同操作形式同步流程。同时 async 表达式便携式开伞器,继续执行的时候无需手动加载。
句法
async 表达式回到两个 Promise 第一类
async 表达式外部 return 回到的值。会成为 then 形式回调表达式的参数。
async function f() {
return hello world
};
f().then( (v) => console.log(v)) // hello world
如果 async 表达式外部抛出异常,则会导致回到的 Promise 第一类状态变为 reject 状态。抛出的错误而会被 catch 形式回调表达式接收到。
async function e(){
throw new Error(error);
}
e().then(v => console.log(v))
.catch( e => console.log(e));
async 表达式回到的 Promise 第一类,要等到外部所有的 await 指示的 Promise 第一类继续执行完,才会发生状态改变
也就是说,只有当 async 表达式外部的触发器操作形式都继续执行完,才会继续执行 then 形式的回调。
const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout));
async function f(){
await delay(1000);
await delay(2000);
await delay(3000);
return done;
}
f().then(v => console.log(v)); // 等待6s后才输出 done
正常情况下,await 指示前面跟着的是 Promise ,如果不是的话,也会被转换成两个 立即 resolve 的 Promise
如上面这个例子:
async function f() {
return await 1
};
f().then( (v) => console.log(v)) // 1
如果回到的是 reject 的状态,则会被 catch 形式捕获。
Async 表达式的错误处理
async 表达式的句法不难,难在错误处理上。
先来看上面的例子:
let a;
async function f() {
await Promise.reject(error);
a = await 1; // 这段 await 并没有继续执行}
f().then(v => console.log(a));
如上面所示,当 async 表达式中只要两个 await 出现 reject 状态,则前面的 await 都不会被继续执行。
解决办法:能添加 try/catch。
// 正确的写法
let a;
async function correct() {
try {
await Promise.reject(error)
} catch (error) {
console.log(error);
}
a = await 1;
return a;
}
correct().then(v => console.log(a)); // 1
如果有多个 await 则能将其都放在 try/catch 中。
如何在项目中采用
依然是通过 babel 来采用。
只需要设置 presets 为 stage-3 即可。
安装依赖:
npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime
修改.babelrc:
“presets”: [“es2015”, “stage-3”],
“plugins”: [“transform-runtime”]
这样就能在项目中采用 async 表达式了。