Promise & async
[[toc]]
Promise
主要用于异步计算
可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
可以在对象之间传递和操作promise,帮助我们处理队列
实现一个 Promise
let resolvePromise = (promise2,x,resolve,reject ) => { if (promise2 === x){ return reject(new TypeError ('循环引用' )) } if (typeof x === 'function' || (typeof x === 'object' && x !== null )){ let called; try { let then = x.then; if (typeof then === 'function' ){ then.call(x,y=>{ if (called) return ; called = true ; resolvePromise(promise2,y,resolve,reject); },r=>{ if (called) return ; called = true ; reject(r); }) }else { resolve(x); } }catch (e){ if (called) return ; called = true ; reject(e); } }else { resolve(x); } } class Promise { constructor (executor){ this .status = 'pending' ; this .value; this .reason; this .resolveCallbacks = []; this .rejectCallbacks = []; let resolve = (value )=> { if (value instanceof Promise ){ return value.then(resolve,reject); } if (this .status == 'pending' ){ this .status = 'fulfilled' ; this .value = value; this .resolveCallbacks.forEach(fn => fn()); } } let reject = (reason )=> { if (this .status === 'pending' ){ this .status = 'rejected' ; this .reason = reason; this .rejectCallbacks.forEach(fn => fn()) } } try { executor(resolve,reject); }catch (e){ reject(e); } } then(onfulfilled,onrejected){ onfulfilled = typeof onfulfilled === 'function' ?onfulfilled:val => val; onrejected = typeof onrejected === 'function' ?onrejected:r => {throw r} let promise2; promise2 = new Promise ((resolve,reject )=> { if (this .status === 'fulfilled' ){ setTimeout(() => { try { let x = onfulfilled(this .value); resolvePromise(promise2,x,resolve,reject); }catch (e){ reject(e); } },0 ); } if (this .status === 'rejected' ){ setTimeout(() => { try { let x = onrejected(this .reason); resolvePromise(promise2,x,resolve,reject); }catch (e){ reject(e); } },0 ) } if (this .status === 'pending' ){ this .resolveCallbacks.push(() => { setTimeout(() => { try { let x = onfulfilled(this .value); resolvePromise(promise2,x,resolve,reject); }catch (e){ reject(e); } },0 ) }); this .rejectCallbacks.push(() => { setTimeout(() => { try { let x = onrejected(this .reason); resolvePromise(promise2,x,resolve,reject); }catch (e){ reject(e); } },0 ) }) } }); return promise2; } catch (rejectFunc){ return this .then(null ,rejectFunc); } } Promise .defer = Promise .deferred = function ( ) { let dfd = {} dfd.promise = new Promise ((resolve,reject )=> { dfd.resolve = resolve; dfd.reject = reject; }) return dfd; } Promise .resolve = function (value ) { return new Promise ((resolve,reject )=> { resolve(value); }) } Promise .reject = function (reason ) { return new Promise ((resolve,reject )=> { reject(reason); }) } Promise .all = function (values ) { return new Promise ((resolve,reject )=> { let results = []; let i = 0 ; let processData = (value,index )=> { results[index] = value; if (++i === values.length){ resolve(results); } } for (let i = 0 ; i< values.length;i++){ let current = values[i]; if ((typeof current === 'object' && current !==null )|| typeof current == 'function' ){ if (typeof current.then == 'function' ){ current.then(y => { processData(y,i); },reject); }else { processData(current,i); } }else { processData(current,i); } } }); } Promise .race = function (values ) { return new Promise ((resolve,reject )=> { for (let i = 0 ; i< values.length;i++){ let current = values[i]; if ((typeof current === 'object' && current !==null )|| typeof current == 'function' ){ let then = current.then; if (typeof then == 'function' ){ then.call(current,resolve,reject) }else { resolve(current); } }else { resolve(current); } } }); }
Generator
generator也是为了解决地狱回调问题的,和promise一样都是为了实现异步编程,本质还是各种回调;
generator为es6中新定义的数据类型,这种数据类型和函数很像,每个函数只能返回一个结果,即只能return一次, 如果在某些函数中没有看到return,其实质在函数结尾是存在一个隐藏的return undefined 的,而generator不同,可以返回多次
function * gen ( ) { yield 1 ; yield 2 ; yield 3 ; yield 4 ; yield 5 ; return "结束" ; } let g = gen();let i = 0 ;let timer = setInterval(() => { i++; console .log(g.next()); if (i>7 ){ clearInterval(timer); } }, 500 ); try { g.throw(new Error ('test1' )) }catch (e){ console .log(e) }
上述例子 可以看出generator 遇到yleld就会暂停,只有当调用generator.next()
才会向下执行, 调用这个方法会返回{value: x, done: true/false}
,这个对象中value是yield的返回值, done表示generator是否执行结束,只有当执行到return时,这个对象中的done才会变成true,说明执行结束
async/await 原理就是利用 generator(生成器)分割代码片段。然后我们使用一个函数让其自迭代,每一个yield 用 promise 包裹起来。执行下一步的时机由 promise 来控制
而且相较于Promise,async的优越性就是把每次异步返回的结果从then中拿到最外层的方法中,不需要链式调用,只要用同步的写法就可以了。 更加直观而且,更适合处理并发调用的问题。但是async必须以一个Promise对象开始 ,所以async通常是和Promise结合使用的
function _asyncToGenerator (fn ) { return function ( ) { var self = this , args = arguments ; return new Promise (function (resolve, reject ) { var gen = fn.apply(self, args); function _next (value ) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next' , value); } function _throw (err ) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw' , err); } _next(undefined ); }); }; } function asyncGeneratorStep (gen, resolve, reject, _next, _throw, key, arg ) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return ; } if (info.done) { resolve(value); } else { Promise .resolve(value).then(_next, _throw); } }
await 每次遇到await都会中断此次进程,然后去执行外面的同步代码,然后再进来,根据上次保存的next值,继续执行
async function foo ( ) { await console .log(121212 ) console .log(121212 ) }
function _foo ( ) { _foo = _asyncToGenerator( regeneratorRuntime.mark(function _callee ( ) { return regeneratorRuntime.wrap(function _callee$ (_context ) { while (1 ) { switch (_context.prev = _context.next) { case 0 : _context.next = 2 ; return console .log(121212 ); case 2 : console .log(121212 ); case "end" : return _context.stop(); } } }, _callee); })); return _foo.apply(this , arguments ); }
测试
const asyncFunc = _asyncToGenerator(function *( ) { const e = yield new Promise (resolve => { setTimeout(() => { resolve('e' ); }, 1000 ); }); const a = yield Promise .resolve('a' ); const d = yield 'd' ; const b = yield Promise .resolve('b' ); const c = yield Promise .resolve('c' ); return [a, b, c, d, e]; }); asyncFunc().then(res => { console .log(res); });
总的来说,async和generator函数主要就是为了解决异步的并发调用使用的 ,直接将参数从then里取出来,相比promise的链式调用,传参更加方便,异步顺序更加清晰
捕获错误 try catch
(async () => { try { const data = await fn() } catch (err) { console .log('err is ->' , err) } })()
单个还好,多个await就显得麻烦了
利用promise
(async () => { const [err, data] = await fn().then(data => [null , data] ).catch(err => [err, null ]) })() const awaitWrap = (promise ) => { return promise .then(data => [null , data]) .catch(err => [err, null ]) } const [err, data] = await awaitWrap(fn())
async函数Generator函数的区别 1.内置执行器。 Generator 函数的执行必须靠执行器,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。如果你是从上面顺着看下来的,这里的执行器就是Generator和Iterator的yield和next机制,不用怀疑!
2.更好的语义。 async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
3.正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
4.返回值是 Promise。 async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。