一篇文章總結(jié)Generator/yield與 async await

前言

講真為了寫(xiě)出更優(yōu)雅、更易維護(hù)的代碼,為了解決異步的嵌套問(wèn)題,真是操碎了心,先是出了個(gè)Promise,然后又是Generator、yield組合,直到ES7的async、await組合。好在事情一直在向好的方向反正。

Generator

生成器對(duì)象是由function* 返回的,并且符合可迭代協(xié)議和迭代器協(xié)議。
這里有幾個(gè)概念生成器、可迭代協(xié)議、迭代器協(xié)議。具體的概念可以點(diǎn)擊鏈接查看MDN文檔。

function*: 定義一個(gè)生成器函數(shù),返回一個(gè)Generator對(duì)象;
可迭代協(xié)議: 允許 JavaScript 對(duì)象去定義或定制它們的迭代行為;
迭代器協(xié)議: 定義了一種標(biāo)準(zhǔn)的方式來(lái)產(chǎn)生一個(gè)有限或無(wú)限序列的值;當(dāng)一個(gè)對(duì)象被認(rèn)為是一個(gè)迭代器時(shí),它實(shí)現(xiàn)了一個(gè) next() 的方法,next()返回值如下:

{
 done:true,//false迭代是否結(jié)束,
 value:v,//迭代器返回值
}

從這幾個(gè)基本的概念我們可以了解到,生成器是對(duì)象是可以迭代的,那么為什么要可以迭代、可以迭代解決了什么問(wèn)題。

迭代

下面定義一個(gè)簡(jiǎn)單的迭代生成函數(shù),傳入一個(gè)數(shù)組,則返回一個(gè)可以迭代的對(duì)象

// 1. 迭代器

let iterator = (items)=>{
  let iter = {
    index:0,
    max:items.length,
    next:function(){ // 返回調(diào)用結(jié)果
      return this.index === this.max ? {value:undefined,done:true} : {value:items[this.index++],done:false};
    }
  }

  return iter;
}

export default iterator;

調(diào)用上面的迭代器,并執(zhí)行

let iter = iterator([1,2,3,4]);
let result = null;
console.log('``````iterator````````');
do{
  result = iter.next();
  console.log(result);
}while (!result.done)

運(yùn)行結(jié)果如下:

1.JPG

可以看到,迭代器每次調(diào)用next()方法,都會(huì)返回{value:xx,done:xx}結(jié)構(gòu)的對(duì)象,這個(gè)就是迭代器協(xié)議中next()方法需要遵循的規(guī)則,前面說(shuō)過(guò)generator函數(shù)也是遵循迭代器協(xié)議的,下面用generator實(shí)現(xiàn)此功能。

generator的使用

// generator
function *generator(items){
  let index = 0;
  let max = items.length;

  while (index < max){
    yield items[index++];
  }

}

let gene = generator([1,2,3,4]);
result = null;
console.log('``````````generator`````````');
do{
  result = gene.next();
  console.log(result)
}while(!result.done)

此時(shí)運(yùn)行結(jié)果如下:


2.JPG

對(duì)比兩次運(yùn)行的結(jié)果,得出一個(gè)結(jié)論:生成器(function*)函數(shù),運(yùn)行時(shí),返回的是一個(gè)生成器對(duì)象,這個(gè)生成器對(duì)象是可以迭代(gene.next())的,并且next()的返回值包含value,done兩個(gè)字段。

進(jìn)化

生成器是可以迭代的,而且返回值也是符合一定結(jié)構(gòu)的,我們每次再使用生成器的時(shí)候,都要用循環(huán)去執(zhí)行,知道返回的done為true,為了簡(jiǎn)化操作需要把這個(gè)循環(huán)操作進(jìn)行封裝,下面封裝一個(gè)簡(jiǎn)單的run函數(shù),run可以執(zhí)行迭代器,一直到完成任務(wù)

let tick = (duration)=>{
  return new Promise((resolve)=>{
    setTimeout(function () {
      console.log(duration,new Date());
      resolve(duration);
    },duration);
  });
};

function *generator() {
  var result = yield tick(2000);
  console.log('result = ',result);
  result = yield tick(4000);
  console.log('result = ',result);
  result = yield tick(3000);
  console.log('result = ',result);
}


let run = (generator,res)=>{
  var result = generator.next(res);
  if(result.done) return;
  result.value.then((res)=>{
    run(generator,res);
  });
}

run(generator());

以上的運(yùn)行結(jié)果:

3.JPG

看一下run的實(shí)現(xiàn),像極了前面的do...while... 循環(huán),只是做了一個(gè)簡(jiǎn)單的封裝,以后就沒(méi)用每次都手寫(xiě)循環(huán)來(lái)執(zhí)行生成器函數(shù)了,實(shí)際上有一個(gè)封裝好的庫(kù)可以使用它叫co

co庫(kù)執(zhí)行g(shù)enerator

安裝co

npm install --save co

使用

import co from 'co';
co(generator);

運(yùn)行結(jié)果如下

4.JPG

它的作用跟上面實(shí)現(xiàn)的run方法的作用是一樣的,都是執(zhí)行g(shù)enerator,并返回結(jié)果。這樣生成器大概就可以理解了,說(shuō)白了生成器就是可以返回一個(gè)可迭代的對(duì)象,這個(gè)對(duì)象不是通過(guò)return返回的,而是通過(guò)yield,并且可以實(shí)現(xiàn)異步函數(shù)的同步調(diào)用,我們看上圖的時(shí)間,雖然tick是異步的,但是打印的結(jié)果卻是順序執(zhí)行的。

async/await

generator可以簡(jiǎn)化異步的編碼,減少嵌套,而async、await組合起來(lái)使用,可以更進(jìn)一步,類(lèi)似以上的代碼,使用async、await改寫(xiě)如下

let tick = (duration)=>{
  return new Promise((resolve)=>{
    setTimeout(function () {
      console.log(new Date());
      resolve(duration);
    },duration);
  });
}


async function asyncFunc(){
  var result = await tick(1000);
  console.log(result);
  result = await tick(2000);
  console.log(result);
  result = await tick(3000);
  console.log(result);
}

asyncFunc();

執(zhí)行結(jié)果

5.JPG

雖然實(shí)現(xiàn)的功能是一樣的,但是從代碼的結(jié)構(gòu)上又簡(jiǎn)化了一層。

引用

koa-step-by-step
迭代協(xié)議

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容