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())
 
await 能获取到 Promise.reject 抛出的值吗 是的,await 可以获取到 Promise.reject 抛出的值,但它需要用 try...catch 捕获。否则,Promise.reject 会导致一个未处理的异常抛出。而且会阻止后续代码执行。
async  function  example ( )  {  try  {     const  result = await  Promise .reject("Error occurred" );     console .log(result);    } catch  (error) {     console .log("Caught:" , error);    } } example(); 
 
解释
 
如果 await 遇到一个 Promise.reject,它会抛出该 Promise 的拒绝值。 
我们可以通过 try...catch 来捕获这个值。 
 
如果没有用 try...catch 或者没有为返回的 Promise 设置 .catch(),会导致未处理的拒绝错误。例如:
async  function  example ( )  {  const  result = await  Promise .reject("Error occurred" );    console .log(result);  } example();  
 
解决方法:  始终用 try...catch 或为返回的 Promise 添加 .catch() 来处理异常。
reject 被内层的 try…catch 捕获并处理了 最外层的 catch 不会再捕获到该错误,除非内层 catch 中显式地重新抛出错误。
示例 1:内层 catch 处理错误,外层无法捕获 
async  function  example ( )  {    try  {         await  Promise .reject(new  Error ('出错了' ));     } catch  (error) {         console .error('内层捕获到错误:' , error.message);               } } (async  () => {     try  {         await  example();     } catch  (error) {         console .error('外层捕获到错误:' , error.message);      } })(); 
 
输出:
内层捕获到错误: 出错了
示例 2:内层 catch 重新抛出错误,外层可以捕获  如果内层 catch 中显式地重新抛出错误(使用 throw),外层 catch 就能捕获到。
async  function  example ( )  {    try  {         await  Promise .reject(new  Error ('出错了' ));     } catch  (error) {         console .error('内层捕获到错误:' , error.message);          throw  error;      } } (async  () => {     try  {         await  example();     } catch  (error) {         console .error('外层捕获到错误:' , error.message);      } })(); 
 
输出:
内层捕获到错误: 出错了
外层捕获到错误: 出错了
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方法指定下一步的操作。