简介
async,await大家在平时工作中用得非常的多,大部分同志也知道是Generator的语法糖
开发中,目前也只有在使用dva的时候才会直接接触到Generator编写
本文就带着学习的目的,和大家分享一下具体的实现细节
async/await
利用async和await可以很简单的利用Promise将异步行为改成同步
async function fn(){ await promise1() await promise2() await promise3() } fn()
是Generator+Promise的语法糖
async函数默认返回一个Promis
Generator
又叫生成器,返回一个可迭代的对象
function* gen() { yield 1; yield 2; yield 3; } const obj = gen() for(const o of obj){ console.log(o) // 1 2 3 }
Symbol.iterator
可迭代协议,对象只有实现了
Symbol.iterator方法才可被迭代
const obj = { 0:'000', 1:'777', 2:'666', length:3, [Symbol.iterator]:[][Symbol.iterator] } for(const o of obj){ console.log(o) // 000 777 666 }
定义对象为类数组的形式,然后直接使用Array的Symbol.iterator
模拟实现
第一阶段
- async返回值为Promise
- 自动执行generator
const testGen1 = function* () { const a = yield Promise.resolve(1); console.time('temp') const b = yield new Promise((res) => { setTimeout(() => { res(2); }, 2000); }); const c = yield Promise.resolve(3); console.log(a, b, c); console.timeEnd('temp') }; function myAsync1(generator) { return new Promise( (resolve, reject) => { // 获得迭代器对象 const gen = generator(); function _next(doneValue) { const { done, value, } = doneValue; if (done) { resolve(); return; } // 执行完这一个后执行下一个 value.then(() => { _next(gen.next()); }); } _next(gen.next()); } ); } myAsync1(testGen1) // 输出结果 undefined undefined undefined temp: 2.007s
第二阶段
- await左边的变量能正常接受值
- await右侧非promise自动包装为promise
- 能正确处理async返回值
const testGen2 = function* () { const a = yield 1; console.time('temp') const b = yield new Promise((res) => { setTimeout(() => { res(2); }, 2000); }); const c = yield 3; console.log(a, b, c); console.timeEnd('temp') return [a, b, c]; }; function myAsync2(generator) { return new Promise( (resolve, reject) => { // 获得迭代器对象 const gen = generator(); function _next(doneValue) { const { done, value, } = doneValue; if (done) { // 正确处理async的返回值 resolve(value); return; } // 执行完这一个后执行下一个 // 非promise自动包装为promise Promise.resolve(value).then( (data) => { // 将Promise resolve的内容赋值给await 左侧的变量 _next(gen.next(data)); } ); } _next(gen.next()); } ); } myAsync2(testGen2).then(console.log); // 运行结果 1 2 3 temp: 2.005s [ 1, 2, 3 ]
第三阶段
- 能正确的抛出Promise的reject错误
const testGen3 = function* () { console.time('temp'); const b = yield new Promise( (res, rej) => { setTimeout(() => { res(2); }, 2000); } ); console.log(b); try { const d = yield Promise.reject(4); } catch (error) { console.log(error); } console.timeEnd('temp'); }; function myAsync3(generator) { return new Promise( (resolve, reject) => { // 获得迭代器对象 const gen = generator(); function _next(doneValue) { const { done, value, } = doneValue; if (done) { // 正确处理async的返回值 resolve(value); return; } // 执行完这一个后执行下一个 // 非promise自动包装为promise Promise.resolve(value) .then((data) => { // 将Promise resolve的内容赋值给await 左侧的变量 _next(gen.next(data)); }) .catch((err) => { // 捕获异常则向生成器抛出一个错误 // 并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。 _next(gen.throw(err)); }); } _next(gen.next()); } ); } myAsync3(testGen3); // 运行结果 2 4 temp: 2.009s
第四阶段
- async能够捕获运行时非await表达式抛出的错误
const testGen4 = function* () { console.time('temp'); const b = yield new Promise( (res, rej) => { setTimeout(() => { res(2); }, 2000); } ); console.log(b); console.timeEnd('temp'); b = 'err'; }; function myAsync4(generator) { return new Promise( (resolve, reject) => { // 获得迭代器对象 const gen = generator(); function _next(doneValue) { const { done, value, } = doneValue; if (done) { // 正确处理async的返回值 resolve(value); return; } // 执行完这一个后执行下一个 // 非promise自动包装为promise Promise.resolve(value) .then((data) => { // 捕获生成器内部非yield表达式抛出的错误 try { // 将Promise resolve的内容赋值给await 左侧的变量 _next(gen.next(data)); } catch (err) { reject(err); } }) .catch((err) => { // 捕获异常则向生成器抛出一个错误 // 并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。 _next(gen.throw(err)); }); } // 捕获生成器内部非yield表达式抛出的错误 try { _next(gen.next()); } catch (err) { reject(err); } } ); } myAsync4(testGen4).catch((err) => { console.log('catch err'); console.log(err); }); // 运行结果 2 temp: 2.008s catch err TypeError: Assignment to constant variable.
最终
对上述的myAsync的冗余代码进行一些优化
function myAsync(generator) { return new Promise( (resolve, reject) => { // 获得迭代器对象 const gen = generator(); function _next(doneValue) { const { done, value } = doneValue || {}; if (done) { // 正确处理async的返回值 resolve(value); return; } // 执行完这一个后执行下一个 // 非promise自动包装为promise Promise.resolve(value) .then((data) => { // 捕获生成器内部非yield表达式抛出的错误 try { // 将Promise resolve的内容赋值给await 左侧的变量 _next(gen.next(data)); } catch (err) { reject(err); } }) .catch((err) => { // 捕获异常则向生成器抛出一个错误 // 并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。 _next(gen.throw(err)); }); } _next(); } ); }
测试
例1
async/await
async function demo1() { const a = await 1; const b = await new Promise( (res, rej) => { setTimeout(() => { res(2); }, 2000); } ); const c = await Promise.resolve(3); console.log(a, b, c); try { const d = await Promise.reject(4); } catch (error) { console.log(error); } return [a, b, c]; } demo1().then(console.log).catch(err=>{ console.log('catch err'); console.log(err); }) // 输出结果 1 2 3 4 [ 1, 2, 3 ]
myAsync实现测试
myAsync(function* () { const a = yield 1; const b = yield new Promise( (res, rej) => { setTimeout(() => { res(2); }, 2000); } ); const c = yield Promise.resolve(3); console.log(a, b, c); try { const d = yield Promise.reject(4); } catch (error) { console.log(error); } return [a, b, c]; }) .then(console.log) .catch((err) => { console.log('catch err'); console.log(err); }); // 输出结果 1 2 3 4 [ 1, 2, 3 ]
例2
await/async
async function demo2() { const a = await 'hello'; const b = await 'world'; console.log(a, b); b = 'err'; return a + b; } demo2() .then(console.log) .catch((err) => { console.log('catch err'); console.log(err); }); // 输出结果 hello world catch err TypeError: Assignment to constant variable.
myAsync测试
myAsync(function* () { const a = yield 'hello'; const b = yield 'world'; console.log(a, b); b = 'err'; return a + b; }) .then(console.log) .catch((err) => { console.log('catch err'); console.log(err); }); // 输出结果 hello world catch err TypeError: Assignment to constant variable.