手写之前先学习下async/await
async
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
异步的简写,用于申明一个函数是异步的,而await用于等待一个异步方法执行完成,await只能出现在async函数中。
1 2 3 4 5 6 7 8 9 10 11 12
| var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000)) async function test() { const data = await getData() console.log('data: ', data); const data2 = await getData() console.log('data2: ', data2); return 'success' } test().then(res => console.log(res))
|
换成generator函数就是
1 2 3 4 5 6 7
| function* test() { const data = yield getData() console.log('data: ', data); const data2 = yield getData() console.log('data2: ', data2); return 'success' }
|
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
async函数对 Generator 函数的改进,体现在以下四点。
- 内置执行器。
Generator函数的执行必须靠执行器,而async函数自带执行器,不许再跳用next方法
- 更好的语义
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
- 更广的适用性
yield/await
- 返回值是 Promise
async返回的是Promise,你阔以用then指定下一步操作。而Generator返回的是Iterator迭代器对象。
async函数完全能理解成多个异步操作,包装成一个Promise对象, async函数是Generator函数的语法糖,而await命令就是内部的then命令的语法糖
总的解释就是:
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。手写async(单说async)
1 2 3 4 5 6 7
| async function foo() { return 1 }
function foo() { return Promise.resolve(1) }
|
模拟实现async1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async function foo() { console.log('foo function') return 1 } var data = foo() data.then(res => console.log(res))
function _async(fn) { return (...args) => Promise.resolve(fn(...args)) } function foo() { console.log('foo function') return 1 } var data = _async(foo)() data.then(res => console.log(res)) console.log('data')
|
async/await
await使用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function takeLongTime(n) { return new Promise(resolve => { setTimeout(() => resolve(n + 200), n); }); } function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n); } function step2(m, n) { console.log(`step2 with ${m} and ${n}`); return takeLongTime(m + n); } function step3(k, m, n) { console.log(`step3 with ${k}, ${m} and ${n}`); return takeLongTime(k + m + n); }
async function doIt() { console.time("doIt"); const time1 = 300; const time2 = await step1(time1); const time3 = await step2(time1, time2); const result = await step3(time1, time2, time3); console.log(`result is ${result}`); console.timeEnd("doIt"); }
|
如果用Promise如何实现1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| function takeLongTime(n) { return new Promise(resolve => { setTimeout(() => resolve(n + 200), n); }); } function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n); } function step2(m, n) { console.log(`step2 with ${m} and ${n}`); return takeLongTime(m + n); } function step3(k, m, n) { console.log(`step3 with ${k}, ${m} and ${n}`); return takeLongTime(k + m + n); }
function doIt() { console.time("doIt"); const time1 = 300; step1(time1) .then((time2) => { return step2(time1, time2).then( time3 => [time1, time2,time3] ) }) .then((rest) => { const [time1, time2, time3] = rest return step3(time1, time2, time3) }) .then(result => { console.log(`result is ${result}`); console.timeEnd("doIt"); }) }
|
Promise解法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function doIt() { console.time("doIt"); const time1 = 300; step1(time1).then((res1) => { const time2 = res1; step2(time1, time2).then((res2) => { const time3 = res2; step3(time1, time2, time3).then((res3) => { console.log(`result is ${res3}`); console.timeEnd("doIt"); }) }) }) }
doIt();
|
注意:
await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中,或者await后的Promise添加catch回调
1 2 3 4
| await read('1.txt','utf8') .catch(function(err){ console.log(err); })
|
手写 await
如果是手动执行里面的执行器,则需要这么实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000)) console.log(getData(), 'getData') function* testG() { var data = yield getData() console.log('data1', data) var data2 = yield getData() console.log('data2',data2) return 'success' } var gg = testG() var dataPromise = gg.next() dataPromise.value.then((val1) => { var data2proimse = gg.next(val1); console.log(data2proimse, 'data2proimse') data2proimse.value.then((val2) => { var data3 = gg.next(val2); gg.next() console.log(data3, 'da ta3') }) })
|
大神版模拟async/await
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| var getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 3000)) console.log(getData(), 'getData') function asyncToGenerator(generatorFunc) { return function() { const gen = generatorFunc.apply(this, arguments) return new Promise((resolve, reject) => { function step(key, arg) { let generatorResult try { generatorResult = gen[key](arg) } catch (error) { return reject(error) } const { value, done } = generatorResult if (done) { return resolve(value) } else { return Promise.resolve(value).then( val => step('next', val), err => step('throw', err)) } } step("next") }) } } var gg = asyncToGenerator( function* testG() { var data = yield getData() console.log('data1', data) var data2 = yield getData() console.log('data2',data2) return 'success' } ) gg().then(res => console.log(res, 'res'))
|
参考链接