async
其实就是 Generator
的语法糖,看本篇文章以前能够先看一下上一篇文章 Generator函数。理解 Generator
就容易理解为何说async
是异步编程的完美解决方案了。前端
async
的笔试题const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error){ return reject(error); } resolve(data); }); }); }; const foo = function* () { const f1 = yield readFile('/src/lib'); const f2 = yield readFile('/src/utils'); console.log(f1.toString()); console.log(f2.toString()); }; 复制代码
把上面代码的Generator
函数 foo
能够写成 async
函数,就是这样:git
const asyncReadFile = async function () { const f1 = await readFile('/src/lib'); const f2 = await readFile('/src/utils'); console.log(f1.toString()); console.log(f2.toString()); }; 复制代码
能够发现,async
函数就是将Generator
函数的星号(*
)替换成async
,将 yield
替换成 await
,仅此而已。github
async
函数是基于 Generator
的改进,体如今如下4点ajax
Generator
函数的执行必须靠执行器。因此才有了 Thunk
函数和co
模块,而 async
函数自带执行器。async
函数的执行和普通函数同样。asyncReadFile();
复制代码
更好的语义。 async
和await
,比起星号和yield
,语义更清楚了。 async
表示函数里有异步操做,await
表示紧跟在后面的表达式须要等待结果。编程
更广的适应性。 即便 Generator
函数能够借助co
模块自动执行,可是co
模块后面只能是Thunk
函数或Promise
对象,而async
函数的await
命令后面,能够是 Promise对象和原始类型的值(数值、字符串和布尔值,但这是会自动转成当即 resolved
的 Promise对象
)微信
返回值是 Promise
。 aysnc函数返回值为 Promise
,这比Generator
函数的返回值是Iterator
对象方便多了。markdown
async
函数彻底能够看做多个异步操做,包装成的一个Promise
对象,而await命令就是内部then
命令的语法糖。异步
总之就是
Generator
函数虽然是JS借鉴其余语言,根据JS自己单线程的特色实现的协程,可是使用起来会麻烦不少,每次都要本身去写执行器,而async
函数就是为了解决这些重复的工做而生的。其实async
函数就是将Generaor
函数和自动执行器完美地封装在了一块儿。async
就是将Generator函数和自动执行器,包装在一个函数里。异步编程
async function fn(args) { // ... } function fn(args) { return spawn(function* () { // ... }) } 复制代码
全部的 async
函数均可以写成上面的第二种形式,其中 spawn 函数就是自动执行器。
// 接受 Generator 函数做为参数,返回一个 Promise 对象 function spawn(genF) { return new Promise(function(resolve, reject) { // 执行genF,获得一个内部指针对象 const gen = genF(); function step(nextF) { let next; // 进行错误处理 try { next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } // 将 next.value 转成 Promise对象 Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } // 会反复调用 step step(function() { return gen.next(undefined); }); }); } 复制代码
能够看到,实际上是 Generator函数和Promise的组合,实现了一个自动执行器,返回 Promise对象
async
的笔试题sleep
:async
实现Promise.all()
的效果每隔1秒输出 1, 2, 3, 4, 5
function sleep(interval) { return new Promise(resolve => { setTimeout(resolve, interval); }) } // 用法 async function one2FiveInAsync() { for (let i = 1; i <= 5; i++) { console.log(i); await sleep(1000); } } one2FiveInAsync(); 复制代码
红灯2秒,黄灯1秒,绿灯3秒
function sleep(duration) { return new Promise(resolve => { setTimeout(resolve, duration); }) } async function changeColor(color, duration) { console.log('当前颜色', color); await sleep(duration); } async function main() { await changeColor('红色', 2000); await changeColor('黄色', 1000); await changeColor('绿色', 3000); } main(); 复制代码
假设 getFoo
和getBar
是两个用于发起ajax
请求的函数。
// 写法一 let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 写法二 let fooPromise = getFoo(); let barPromise = getBar(); let foo = await fooPromise; let bar = await barPromise; 复制代码
上面两种写法,getFoo 和 getBar 都是同时触发,这样就会缩短程序的执行时间。
上面只是简单示例,思考一下,写出完整代码。
async
函数原理就是 Generator
函数 和 自动执行器包装了一下。Generator
就是能够暂定执行和在以前停下的位置接着执行。好比发送一个接口请求,发出以后,JS能够去干其余的事儿,接口请求回来以后(数据经过next传入),会接着继续执行。可是它不能自动执行,因此须要自动执行器, thunk
函数和co
模块都是,可是async给咱们封装得更加完美。文章首发于 个人github博客
最近发起了一个100天前端进阶计划,主要是深挖每一个知识点背后的原理,欢迎关注 微信公众号「牧码的星星」,咱们一块儿学习,打卡100天。