在 ES7 中会新增 async / await 用于处理异步请求,使开发者能像处理同步请求一样处理异步请求。发起一个异步请求之后,获取到了请求结果,再进行下一步操作,使整个流程看起来就是同步流程;
Prepare
由于当前浏览器并不直接支持最新的 es7 语法,所以需要使用转换器将 es7 语法下的 javascript 转换成 es5 语法的代码块;可以使用 babel 转换器进行转换,需要安装如下几个插件:
1 2 3 4 5
| "dependencies": { "babel-core": "^6.24.1", "babel-loader": "^7.0.0", "babel-preset-stage-3": "^6.24.1" },
|
异步请求
假如有一个函数,需要在执行过程中暂停指定的一段时间,然后再向下执行;
1 2 3 4 5 6 7 8 9 10 11
| var sleep = function(time) { return new Promise((resolve, reject)=> { setTimeout(()=> { if(time >= 1000){ resolve("function sleep is invoked after " + time + " ms"); }else{ reject("function sleep is invoked after " + time + "ms, sleepTime should be longer"); } }, time); }); };
|
CommonInvoke 普通调用
1 2 3 4 5 6 7
| var commonInvoke = ()=> { sleep(1200).then((info)=>{ console.log('commonInvoke'); console.log(info); }); }; commonInvoke();
|
使用 async & await 函数
1 2 3 4 5 6 7 8 9 10 11 12
| var asyncInvoke = async ()=> { console.log('async function begin'); var result = await sleep(1100); console.log(result); console.log('after await => async end with success'); }; asyncInvoke(); async function begin // 等待1s后再输出下面的内容 function sleep is invoked after 1100 ms after await => async end with success
|
在使用 async & await 之后,可以在等 sleep 函数执行完成返回异步函数的结果值之后,再继续向下执行。await 等待的虽然是 promise 对象,但不必写 .then(..),可以直接得到返回值。上面的输出结果中第二行输出即是 sleep 中 promise 的返回值;
async & await 使用规则:
- async 表示这是一个async函数,await只能用在这个函数里面。
- await 表示此行代码需要等待sleep返回的promise执行完成后再继续向下执行。
- await 后面跟着的应该是一个promise对象(当然其他值也没关系,只是会立即执行,不过那样没有意义)
错误捕获
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var asyncInvokeRejected = async ()=> { try { console.log('async function begin'); var result = await sleep(500); console.log(result); console.log('after await => async end with success'); } catch(err) { console.log(err); console.log('after await => async end with error'); } }; asyncInvokeRejected(); async function begin function sleep is invoked after 500ms, sleepTime should be longer after await => async end with error
|
由于给 sleep 的暂停时间小于1000,所以 sleep 函数中 promise 对象调用了 reject 函数表示函数执行不成功,普通调用方法下捕获异常是 p.then(…).catch(…),但是在使用 async / await 的时候,可以直接使用 try {…} catch (err) {} 来捕获异常;
循环执行
await 看起来就像是同步代码,所以可以理所当然的写在for循环里,不必担心以往需要 闭包 才能解决的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function getTime() { return new Date().getTime(); } var asyncInvokeLoop = async ()=> { for(var i = 0; i < 3; i++) { console.log('invoked ' + i + " times"); await sleep(1000); console.log(getTime()); } }; asyncInvokeLoop();
|
需要注意的是 await 必需是要在 async 的上下文中,如下便是一个错误的调用:
1 2 3 4 5
| var arr = [1, 2, 3]; arr.forEach(function (v) { console.log(`当前是第${v}次等待..`); await sleep(1000); });
|
Link