第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

ES6+ Generator 函數(shù)應用

1. 前言

上一節(jié)我們注意學習了生成器的概念和基本用法,并通過兩個案例來說明。但是生成器更加廣泛和設計之初是為了解決異步而產(chǎn)生的。我們會通過一個開發(fā)中常見的問題入手來看 生成器函數(shù)到底是怎么來解決異步調用的問題,并且會實現(xiàn)一個簡版的 co 庫。

2. 案例

在開發(fā)過程中會遇到一個很常見的需求,我們想獲取一個值,但不能直接拿到,我們只能先請求一個接口如:api_1,獲取這個值的接口地址如:api_2。然后,請求 api_2 接口才能獲取這個值。這是一個典型的需要異步回調才能完成的功能。

在學習 Promise 的時候我們也針對這樣的情況,我們可以使用 Promise 來完成這樣的功能:

var promise = function (url) {
	return new Promise((resolve, reject) => {
    ajax(url, (data) => {
      resolve(data)	// 成功
    }, (error) => {
      reject(error)	// 失敗
    })
  })
}
    
promise('api_1').then(res1 => {
  promise(res1).then(res2 => {
    console.log(res2)
  })
})

從上面的代碼中可以看出,在這種情況下,使用 Promise 好像并沒有解決回調地獄的問題。那如何解決這種問題呢?我們想到了 Generator 函數(shù)具有暫停功能,那是不是我們可以讓請求 api_2 接口時暫停,等到 api_1 請求成功獲取到地址后再去請求呢?按照這個思路我們可以有下面的代碼:

const ajax = function(api) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (api === 'api_1') {
        resolve('api_2');
      }
      if (api === 'api_2') {
        resolve(100);
      }
    }, 0)
  })
}

function * getValue() {
  const api = yield ajax('api_1');
  const value = yield ajax(api);
  return value;
}

console.log(getValue());	// Object [Generator] {}

上面的代碼是我們模擬 ajax 請求,通過使用生成器函數(shù)寫出的代碼讓我們感覺有了同步的感覺,但是這樣去執(zhí)行 getValue 函數(shù)是不會得到結果的。那么我們要怎樣去獲得結果呢?根據(jù)生成器函數(shù)的特點,可以這樣寫:

let it = getValue();

let { value } = it.next();
value.then((data) => {
  let { value } = it.next(data);
  value.then((data) => {
    Console.log(data);
  });
});

從上面的代碼中看出還是有嵌套,好像并沒有解決問題。但如果你細心,你會發(fā)現(xiàn)每個回調的邏輯基本都是一樣的。那么我們能不能對這樣的嵌套函數(shù)進行封裝呢?答案當然是可以的,有個庫就專門解決了這個痛點 —— co 庫,有興趣的可以去研究一下這個庫,代碼很少,下面我們就來封裝一個這樣的庫。

先讓我們看看 co 庫是怎么使用的:

co(getValue()).then(res => {
  console.log(res);
})

從上面的代碼中可以看出,把函數(shù)傳入進去,并讓函數(shù)執(zhí)行,然后在 then 的成功回調中可以獲取 getValue 函數(shù)返回的最終結果。這樣非常清晰地解決了上面我們需要手動執(zhí)行的方法,下面我來分析一下具體的實現(xiàn)步驟:

  1. 從上面的用法可以看出,co 返回的是一個 Promise 實例,所以我們需要返回一個 new Promise() 實例;
  2. 傳入的生成器函數(shù)執(zhí)行后,我們可以調用 next () 函數(shù)拿到返回的值和是否執(zhí)行完的狀態(tài),判斷 done 如果是 true 時說明執(zhí)行完了,可以執(zhí)行 resolve;
  3. 當生成器函數(shù)沒有執(zhí)行完時,這時我們就需要遞歸地去調用這個 next () 來執(zhí)行下一步,因為傳入的值是一個 Promise 實例,要想獲取它的結果就需要鏈式調用 then 方法,然后拿到結果進行遞歸執(zhí)行。

有了上面的步驟分析,不難得到下面的代碼:

function co(it) {
  return new Promise((resolve, reject) => {
    function next(data) {
      let { value, done } = it.next(data);
      if (done) {
        resolve(value);
      } else {
        Promise.resolve(value).then(data => {
          next(data);
        }, reject)
      }
    }
    next(undefined);
  })
}

上面的代碼中需要注意的是,如果 yield 返回的不是一個 Promise 對象時,我們對 value 使用了 Promise.resolve() 進行了包裝,這樣就可以處理返回一個普通值時沒有 then 方法的問題。

3. 小結

本節(jié)主要講解了 Generator 函數(shù)在異步中的應用,解決了某些場景下還會產(chǎn)生回調地獄的問題,通過封裝 co 方法讓我們的代碼寫起來像是同步一樣,但是 Generator 函數(shù)還不是我們解決異步的終極方案,下一節(jié)我們將學習 async 函數(shù),看它是怎么來解決異步的。