亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

從狀態(tài)機(jī)的角度加深理解并實(shí)現(xiàn)Promise

IamDLY / 946人閱讀

摘要:這篇文章內(nèi)容主要來自一篇高票答案聲明此的實(shí)現(xiàn)僅僅是為了加深本人對其的理解,和規(guī)范有些出入,但是的確是目前看過所有代碼中最漂亮,思路比較清晰的一個。

這篇文章內(nèi)容主要來自一篇stack Overflow高票答案

聲明:此Promise的實(shí)現(xiàn)僅僅是為了加深本人對其的理解,和A+規(guī)范有些出入,但是的確是目前看過所有promise代碼中最漂亮,思路比較清晰的一個。
文章不會特意幫助讀者復(fù)習(xí)Promise基本操作。

狀態(tài)機(jī)

Promise其實(shí)本質(zhì)上就是一個狀態(tài)機(jī),所以首先我們描述一個靜態(tài)的狀態(tài)機(jī),就像下邊這樣

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 存儲的狀態(tài)是上邊的三個:執(zhí)行中,已完成,已拒絕
  var state = PENDING;

  // 存儲異步結(jié)果或者異步錯誤消息
  var value = null;

  // 負(fù)責(zé)處理中途加入的處理函數(shù)
  var handlers = [];
}
狀態(tài)改變

完成了基本的狀態(tài)機(jī)定義,接下來的問題就是完成“狀態(tài)改變”這個動作的實(shí)現(xiàn):

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 存儲三個狀態(tài)
  var state = PENDING;

  // 一旦出現(xiàn)狀態(tài)的改變,異步結(jié)果就會被存到這個地方
  var value = null;

  // 存儲成功或者失敗的handler
  var handlers = [];

//狀態(tài)轉(zhuǎn)移到成功
  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }
//狀態(tài)轉(zhuǎn)移到失敗
  function reject(error) {
    state = REJECTED;
    value = error;
  }
}

到目前為止,我們給出了兩個很純粹的變化動作,在開發(fā)的過程中這兩個動作會很不好用,所以我們在這兩個動作的基礎(chǔ)上構(gòu)建一個高層次的動作(其實(shí)就是加點(diǎn)判斷然后封裝一層),就像下邊這兒,名字就叫做resolve,但是注意和我們正常使用promise調(diào)用的那個resolve并不一樣,不要搞混:

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {

  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }
//這里暫時缺少兩個重要函數(shù)getThen和doResolve這兩個函數(shù),稍后會說道
  function resolve(result) {
    try {
      var then = getThen(result);
      //判斷then是不是一個Promise對象
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }
}

是的,我們的用到了兩個輔助函數(shù)getThen和doResolve,現(xiàn)在給出實(shí)現(xiàn):

/**
 * 這里會判斷value的類型,我們只要promise.then這個函數(shù),其他的統(tǒng)統(tǒng)返回null
 *
 * @param {Promise|Any} value
 * @return {Function|Null}
 */
function getThen(value) {
  var t = typeof value;
  if (value && (t === "object" || t === "function")) {
    var then = value.then;
    if (typeof then === "function") {
      return then;
    }
  }
  return null;
}

/**
 * 這個函數(shù)的主要作用就是串主邏輯,完成“變化狀態(tài)”這個動作
 *
 * @param {Function} fn A resolver function that may not be trusted
 * @param {Function} onFulfilled
 * @param {Function} onRejected
 */
function doResolve(fn, onFulfilled, onRejected) {
//done的作用是讓onFulfilled或者onRejected僅僅被調(diào)用一次,狀態(tài)機(jī)狀態(tài)一旦改變沒法回頭
  var done = false;
  try {
//在我們正常使用Promise的時候調(diào)的resolve,其實(shí)用的就是這里fn注入函數(shù)然后調(diào)用
    fn(function (value) {
      if (done) return
      done = true
      **onFulfilled(value)**
    }, function (reason) {
      if (done) return
      done = true
      onRejected(reason)
    })
  } catch (ex) {
    if (done) return
    done = true
    onRejected(ex)
  }
}
構(gòu)建

好了,一個完整的狀態(tài)機(jī)已經(jīng)完成,我們完成了一個基本的狀態(tài)變化邏輯,接下來要做的就是一步一步的朝promise標(biāo)準(zhǔn)進(jìn)發(fā),這個promise缺少什么呢,暫時缺的就是初始的動作啦(new promise(func)對象一旦被初始化內(nèi)部代碼立即執(zhí)行),所以我們加上初始動作的開啟

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {

  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }
//開啟任務(wù)的執(zhí)行,所以我說doResolve其實(shí)才是“主線任務(wù)”的引子,而fn其實(shí)就是你寫的代碼
  doResolve(fn, resolve, reject);
}
聯(lián)動

我們實(shí)現(xiàn)了狀態(tài)機(jī),但是目前的問題是我們只能眼睜睜的看著代碼的流動直到一個Promise結(jié)束為止,即沒法添加也沒法獲取結(jié)果,這就有很大的局限性了,所以我們要使用then方法來串聯(lián)Promise,用done方法來完成結(jié)果的收集,首先實(shí)現(xiàn)done方法,因?yàn)閠hen其實(shí)說白了就是收集上邊的結(jié)果--完成自己的邏輯--把結(jié)果傳遞給下一個Promise,做的事情是done的超集。

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {

  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
    //專門封裝一個handle函數(shù)處理后續(xù)邏輯,在下面有this.handle(handler)方法
    handlers.forEach(handle);
    //在狀態(tài)變成已處理并且之前加入的handler都被處理完畢的情況下再加入handler就會報錯并且沒有卵用
    handlers = null;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
    handlers.forEach(handle);
    handlers = null;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }

  function handle(handler) {
    if (state === PENDING) {
      handlers.push(handler);
    } else {
      if (state === FULFILLED &&
        typeof handler.onFulfilled === "function") {
        handler.onFulfilled(value);
      }
      if (state === REJECTED &&
        typeof handler.onRejected === "function") {
        handler.onRejected(value);
      }
    }
  }

//注意看下面done方法的實(shí)現(xiàn),里邊只有一個異步方法,換句話說就是會立即返回不會產(chǎn)生阻塞,我們之后會在then當(dāng)中調(diào)用done方法,這里的onFulfilled, onRejected就是用戶寫的處理函數(shù),promise異步的特性就是這樣來的。
  this.done = function (onFulfilled, onRejected) {
    // ensure we are always asynchronous
    setTimeout(function () {
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  }

  doResolve(fn, resolve, reject);
}

最后,我們來實(shí)現(xiàn)Promise.then,完成狀態(tài)機(jī)的串聯(lián):

//這段代碼有點(diǎn)繞,主要需要完成的工作其實(shí)就是,判斷上一個Promise是否完成,然后執(zhí)行用戶的then里邊的回調(diào)代碼,并最終返回一個新的Promise,然后依次循環(huán)。。。
this.then = function (onFulfilled, onRejected) {
//開啟then之后就會返回一個新的promise,但是這個時候我們還可能有上一個Promise的任務(wù)沒有完成,所以先把上邊一個promise對象的this指向保存下來
  var self = this;
//返回一個新包裝Promise,這和我們普通的在外邊寫new Promise是一個道理
  return new Promise(function (resolve, reject) {
//done的代碼同樣是立即返回,然后異步執(zhí)行的
    return self.done(function (result) {
      if (typeof onFulfilled === "function") {
        try {
          return resolve(onFulfilled(result));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return resolve(result);
      }
    }, function (error) {
      if (typeof onRejected === "function") {
        try {
          return resolve(onRejected(error));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return reject(error);
      }
    });
  });
}

Over
更多參考請看下面:
簡單的實(shí)現(xiàn)Promsie
高性能實(shí)現(xiàn)Promise,以及專門的wiki

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/107272.html

相關(guān)文章

  • 源碼看 Promise 概念與實(shí)現(xiàn)

    摘要:從源碼看概念與實(shí)現(xiàn)是異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問題。這些概念中有趣的地方在于,標(biāo)識狀態(tài)的變量如都是形容詞,用于傳入數(shù)據(jù)的接口如與都是動詞,而用于傳入回調(diào)函數(shù)的接口如及則在語義上用于修飾動詞的副詞。 從源碼看 Promise 概念與實(shí)現(xiàn) Promise 是 JS 異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問題。在沒有引入新的語言機(jī)制的前提下,這...

    kel 評論0 收藏0
  • 深入理解promise對象

    摘要:前言中的異步,剛開始的時候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來出現(xiàn)了,解決了回調(diào)地獄的問題。 前言 js中的異步,剛開始的時候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來es6出現(xiàn)了promise,解決了回調(diào)地獄的問題?,F(xiàn)在我們就自己寫代碼實(shí)現(xiàn)一下promise,這樣才能深入理解...

    CoderDock 評論0 收藏0
  • spring statemachine的企業(yè)可用級開發(fā)指南1-說些廢話

    摘要:讓我們先看下狀態(tài)機(jī)的概念。下面是狀態(tài)機(jī)模型中的個要素,即現(xiàn)態(tài)條件動作次態(tài)。因?yàn)橛唵魏蛯徟亩加泻芏嗟牧鞒?,每個流程都會產(chǎn)生狀態(tài)的變化,而且流程是這種業(yè)務(wù)的主軸,其他都是圍繞這個流程和狀態(tài)變化來考慮的,所以看起來蠻適合用狀態(tài)機(jī)來做。 1、背景在我打算學(xué)習(xí)spring statemachine的時候,我?guī)缀蹩催^了所有網(wǎng)上的中文教程,基本上都處于淺嘗輒止的階段,有幾篇講的比較深入的,都只是...

    BakerJ 評論0 收藏0
  • 白潔血戰(zhàn)Node.js發(fā)編程 01 狀態(tài)機(jī)

    摘要:狀態(tài)機(jī)狀態(tài)機(jī)是模型層面的概念,與編程語言無關(guān)。狀態(tài)機(jī)具有良好的可實(shí)現(xiàn)性和可測試性。在代碼里,這是一個,但是我們在狀態(tài)機(jī)模型中要把他理解為事件。 這一篇是這個系列的開篇,沒有任何高級內(nèi)容,就講講狀態(tài)機(jī)。 狀態(tài)機(jī) 狀態(tài)機(jī)是模型層面的概念,與編程語言無關(guān)。它的目的是為對象行為建模,屬于設(shè)計范疇。它的基礎(chǔ)概念是狀態(tài)(state)和事件(event)。 對象的內(nèi)部結(jié)構(gòu)描述為一組狀態(tài)S1, S2,...

    fjcgreat 評論0 收藏0
  • 簡單理解Javascript的各種異步流程控制方法

    摘要:所以僅用于簡化理解,快速入門,依然需要閱讀有深入研究的文章來加深對各種異步流程控制的方法的掌握。 原文地址:http://zodiacg.net/2015/08/javascript-async-control-flow/ 隨著ES6標(biāo)準(zhǔn)逐漸成熟,利用Promise和Generator解決回調(diào)地獄問題的話題一直很熱門。但是對解決流程控制/回調(diào)地獄問題的各種工具認(rèn)識仍然比較麻煩。最近兩天...

    makeFoxPlay 評論0 收藏0

發(fā)表評論

0條評論

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