国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[前端漫談_2] 從 Dva 的 Effect 到 Generator + Promise 實現異步

pekonchan / 2703人閱讀

摘要:你能學到什么如何使用實現異步編程異步編程的原理解析前言結合上一篇文章,我們來聊聊基礎原理說到異步編程,你想到的是和,但那也只是的語法糖而已。表示一個異步操作的最終狀態完成或失敗,以及其返回的值。至此實現異步操作的控制。

你能學到什么

如何使用 Generator + Promise 實現異步編程

異步編程的原理解析

前言

結合 上一篇文章 ,我們來聊聊 Generator

基礎原理

說到異步編程,你想到的是asyncawait ,但那也只是 Generator 的語法糖而已。dva 中有一個 Effect 的概念,它就是使用 Generator 來解決異步請求的問題,我們也來聊一聊 Generator + Promise 如何異步編程:

開始之前,我們需要了解一些基本的概念:

Generator作為 ES6 中使用協程的解決方案來處理異步編程的具體實現,它的特點是: Generator 中可以使用 yield 關鍵字配合實例 gen 調用 next() 方法,來將其內部的語句分割執行。 簡言之 : next() 被調用一次,則 yield 語句被執行一句,隨著 next() 調用, yield 語句被依次執行。

Promise表示一個異步操作的最終狀態(完成或失敗),以及其返回的值。參考Promise-MDN

所以,異步編程使用 GeneratorPromise 來實現的原理是什么呢?

因為 Generator 本身 yield 語句是分離執行的,所以我們利用這一點,在 yield 語句中返回一個 Promise 對象

首次調用 Generator 中的 next() 后, 假設返回值叫 result ,那么此時 result.value 就是我們定義在 yield 語句中的 Promise 對象

注意:在這一步,我們已經把原來的執行流程暫停,轉而執行 Promise 的內容,已經實現了控制異步代碼的執行,因為此時我們如果不繼續執行 next()generator 中位于當前被執行的 yield 后面的內容,將不會繼續執行,這已經達到了我們需要的效果

接下來我們就是在執行完當前 Promise 之后,讓代碼繼續往下執行,直到遇到下一個 yield 語句:

這一步是最關鍵的 所以我們怎么做呢:

步驟1: 在當前的 Promisethen() 方法中,繼續執行 gen.next()

步驟2: 當 gen.next() 返回的結果 result.done === true 時,我們拿到 result.value【也就是一個新的 Promise 對象】再次執行并且在它的then() 方法中繼續上面的步驟1,直至 result.done === false 的時候。這時候調用 resolve() 使 promise 狀態改變,因為所有的 yield 語句已經被執行完。

步驟1 保證了我們可以走到下一個 yield 語句

步驟2 保證了下一個 yield 語句執行完不會中斷,直至 Generator 中的最后一個 yield 語句被執行完。

流程示意圖:

具體實現
co 是著名大神 TJ 實現的 Generator 的二次封裝庫,那么我們就從co庫中的一個demo開始,了解我們的整個異步請求封裝實現:
co(function*() {
    yield me.loginAction(me.form);
    ...
});

在這里我們引入了co庫,并且用co來包裹了一個generator(生成器)對象。

接下來我們看下co對于包裹起來的generator做了什么處理

function co(gen) {
  // 1.獲取當前co函數的執行上下文環境,獲取到參數列表
  var ctx = this;
  var args = slice.call(arguments, 1);
  // 2.返回一個Promise對象
  return new Promise(function(resolve, reject) {
    //  判斷并且使用ctx:context(上下文環境)和arg:arguments(參數列表)初始化generator并且復制給gen
    // 注意:
    // gen = gen.apply(ctx, args)之后
    // 我們調用 gen.next() 時,返回的是一個指針,實際的值是一個對象
    // 對象的形式:{done:[false | true], value: ""}
    if (typeof gen === "function") gen = gen.apply(ctx, args);
    // 當返回值不為gen時或者gen.next的類型不為function【實際是判斷是否為generator】時
    // 當前promise狀態被設置為resolve而結束
    if (!gen || typeof gen.next !== "function") return resolve(gen);
    // 否則執行onFulfilled()
    onFulfilled();
  });
}

總結一下這里發生了什么

返回一個 promise

promise 中將被包裹的 generator 實例化為一個指針,指向 generator 中第一個 yield 語句

判斷 generator 實例化出來的指針是否存在:如果沒有 yield 語句則指針不存在
判斷指針 gen.next() 方法是否為 function :如果不為 function 證明無法執行 gen.next()
條件有一項不滿足就將 promise 的狀態置為 resolve
否則執行 onFulfilled()

接下來我們看下 onFulfilled() 的實現

    function onFulfilled(res) {
      // 在執行onFulfilled時,定義了一個ret來儲存gen.next(res)執行后的指針對象
      var ret;
      try {
        ret = gen.next(res);
      // 在這里,yield語句拋出的值就是{value:me.loginAction(me.form), done:false}
      } catch (e) {
        return reject(e);
      }
    // 將ret對象傳入到我們定義在promise中的next方法中
      next(ret);
      return null;
    }

總結一下,onFulfilled 最主要的工作就是

執行 gen.next() 使代碼執行到 yield 語句

將執行后返回的結果傳入我們自定義的 next() 方法中

那么我們再來看 next() 方法

    function next(ret) {
    // 進入next中首先判斷我們傳入的ret的done狀態:
    // 情況1:ret.done = true 代表我們這個generator中所有yield語句都已經執行完。
    // 那么將ret.value傳入到resolve()中,promise的狀態變成解決,整個過程結束。
      if (ret.done) return resolve(ret.value);
    // 情況2:當前ret.done = false 代表generator還未將所有的yield語句執行完,那么這時候
    // 我們把當前上下文和ret.value傳入toPromise中,將其轉換為對應的Promise對象`value`
      var value = toPromise.call(ctx, ret.value);
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
    // 當value確實是一個promise對象的時候,return value.then(onFulfilled,onRejected)
    // 我們重新進入到了generator中,執行下一條yield語句
      return onRejected(new TypeError("You may only yield a function, promise, generator, array, or object, "
        + "but the following object was passed: "" + String(ret.value) + """));
    }

總結一下,next 主要工作

判斷上一次 yield 語句的執行結果

yieldresultvalue 值【其實就是我們要異步執行的 Promise

執行 valuethen 方法,重新進入到 onFulfilled 方法中,而在 onFulfilled 中,我們又將進入到當前方法,如此循環的調用,實現了 generatorPromise 的執行切換,從而實現了 Promise 的內容按照我們所定義的順序執行。

有同學可能對這里的 toPromise 方法有一些疑惑,我先把代碼貼出來

function toPromise(obj) {
  if (!obj) return obj;
  if (isPromise(obj)) return obj;
  if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
  if ("function" == typeof obj) return thunkToPromise.call(this, obj);
  if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
  if (isObject(obj)) return objectToPromise.call(this, obj);
  return obj;
}

其實這個函數做的事情就是,根據不同的類型進行轉換,使得最后輸出的類型都是一個 Promise。那具體的轉換細節,大家可以參考co庫的源碼。

至此實現異步操作的控制。

最后

這里是 Dendoink ,奇舞周刊原創作者,掘金 [聯合編輯 / 小冊作者] 。
對于技術人而言:技 是單兵作戰能力,術 則是運用能力的方法。得心應手,出神入化就是 藝 。在前端娛樂圈,我想成為一名出色的人民藝術家。掃碼關注公眾號 前端惡霸 我在這里等你:

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104337.html

相關文章

  • [前端漫談_1] for of 聊 Generator

    摘要:數據的層級意味著迭代數據結構并提取它的數據。對于技術人而言技是單兵作戰能力,術則是運用能力的方法。在前端娛樂圈,我想成為一名出色的人民藝術家。 聊聊 for of 說起 for of 相信每個寫過 JavaScript 的人都用過 for of ,平時我們用它做什么呢?大多數情況應該就是遍歷數組了,當然,更多時候,我們也會用 map() 或者 filer() 來遍歷一個數組。 但是就...

    miqt 評論0 收藏0
  • redux-saga框架使用詳解及Demo教程

    摘要:通過創建將所有的異步操作邏輯收集在一個地方集中處理,可以用來代替中間件。 redux-saga框架使用詳解及Demo教程 前面我們講解過redux框架和dva框架的基本使用,因為dva框架中effects模塊設計到了redux-saga中的知識點,可能有的同學們會用dva框架,但是對redux-saga又不是很熟悉,今天我們就來簡單的講解下saga框架的主要API和如何配合redux框...

    Nosee 評論0 收藏0
  • React生態,dva源碼閱讀

    摘要:下面會從淺到深,淡淡在閱讀源碼過程中自己的理解。分拆子頁面后,每一個子頁面對應一個文件。總結上面就是最早版本的源碼,很簡潔的使用了等其目的也很簡單簡化相關生態的繁瑣邏輯參考源碼地址 ??dva的思想還是很不錯的,大大提升了開發效率,dva集成了Redux以及Redux的中間件Redux-saga,以及React-router等等。得益于Redux的狀態管理,以及Redux-saga中...

    bergwhite 評論0 收藏0

發表評論

0條評論

pekonchan

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<