成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Promise 源碼分析

Towers / 2004人閱讀

摘要:最后當(dāng)?shù)姆祷刂禐闀r(shí),也會(huì)執(zhí)行方法。遍歷傳入的數(shù)組,經(jīng)過(guò)的源碼可以看到,如果是一個(gè)則戶(hù)直接將這個(gè)返回,最后數(shù)組中的哪個(gè)優(yōu)先回調(diào)即執(zhí)行。

前言

then/promise項(xiàng)目是基于Promises/A+標(biāo)準(zhǔn)實(shí)現(xiàn)的Promise庫(kù),從這個(gè)項(xiàng)目當(dāng)中,我們來(lái)看Promise的原理是什么,它是如何做到的,從而更加熟悉Promise

分析

從index.js當(dāng)中知道,它是先引出了./core.js,隨后各自執(zhí)行了其他文件的代碼,通過(guò)requeire的方法。

我們首先先想一下最基礎(chǔ)的promise用法

new Promise((resolve, reject) =>  {
    resolve(4);

}).then(res => {
    console.log(res); // export 4
});
Promise中的標(biāo)準(zhǔn)

標(biāo)準(zhǔn)中規(guī)定:

Promise對(duì)象初始狀態(tài)為 Pending,在被 resolvereject 時(shí),狀態(tài)變?yōu)?FulfilledRejected

resolve接收成功的數(shù)據(jù),reject接收失敗或錯(cuò)誤的數(shù)據(jù)

Promise對(duì)象必須有一個(gè) then 方法,且只接受兩個(gè)可函數(shù)參數(shù) onFulfilled、onRejected

index.js

"use strict";

module.exports = require("./core.js");
require("./done.js");
require("./finally.js");
require("./es6-extensions.js");
require("./node-extensions.js");
require("./synchronous.js");

我們先看src/core.js

function Promise(fn) {
  // 判斷 this一定得是object不然就會(huì)報(bào)錯(cuò),這個(gè)方法一定得要new出來(lái)
  if (typeof this !== "object") {
    throw new TypeError("Promises must be constructed via new");
  }
  // 判斷fn 一定得是一個(gè)函數(shù)
  if (typeof fn !== "function") {
    throw new TypeError("Promise constructor"s argument is not a function");
  }
  this._deferredState = 0;
  this._state = 0;
  this._value = null;
  this._deferreds = null;
  if (fn === noop) return;
  // 最終doResolve很關(guān)鍵
  doResolve(fn, this);
}

Promise是一個(gè)構(gòu)造方法,開(kāi)始時(shí),它進(jìn)行了校驗(yàn),確保了fn是一個(gè)函數(shù),隨后對(duì)一些變量進(jìn)行了初始化,最后執(zhí)行了doResolve()

我們接著看doResolve這個(gè)方法。

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
// 
// 確保`onFulfilled`和`onRejected`方法只調(diào)用一次
// 不保證異步
function doResolve(fn, promise) {
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    // 如果done 為true 則return
    if (done) return;
    done = true;
    // 回調(diào)執(zhí)行 resolve()
    resolve(promise, value);
  }, function (reason) {
    // 如果done 為true 則return
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // res為truCallTwo()的返回值
  // 如果done沒(méi)有完成 并且 res 是 `IS_ERROR`的情況下
  // 也會(huì)執(zhí)行reject(),同時(shí)讓done完成
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}

doResolve最關(guān)鍵的是執(zhí)行了tryCallTwo方法,這個(gè)方法的第二,第三個(gè)參數(shù)都是回調(diào),當(dāng)執(zhí)行回調(diào)后,done為true,同時(shí)各自會(huì)執(zhí)行resolve()或者reject()方法。最后當(dāng)tryCallTwo的返回值為IS_ERROR時(shí),也會(huì)執(zhí)行reject()方法。

我們先來(lái)看一下tryCallTwo方法

function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

fn實(shí)際就是Promise初始化時(shí)的匿名函數(shù)(resolve, reject) => {}a,b則代表的是resolve()reject()方法,當(dāng)我們正常執(zhí)行完promise函數(shù)時(shí),則執(zhí)行的是resolve則在doResolve中,我們當(dāng)時(shí)執(zhí)行的第二個(gè)參數(shù)被回調(diào),如果報(bào)錯(cuò),reject()被執(zhí)行,則第二個(gè)參數(shù)被回調(diào)。最后捕獲了異常,當(dāng)發(fā)生了報(bào)錯(cuò)時(shí),會(huì)return IS_ERROR,非報(bào)錯(cuò)時(shí)會(huì)return undinfed

再回到剛才的doResolve方法,當(dāng)執(zhí)行了第二個(gè)參數(shù)的回調(diào)之后,會(huì)執(zhí)行resolve方法

function resolve(self, newValue) {
  // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  // 不能吃傳遞自己
  if (newValue === self) {
    // 報(bào)錯(cuò)
    return reject(
      self,
      new TypeError("A promise cannot be resolved with itself.")
    );
  }
  // promise作為參數(shù)
  if (
    newValue &&
    (typeof newValue === "object" || typeof newValue === "function")
  ) {
    // 獲取它的promise方法 讀取newValue.then
    var then = getThen(newValue);
    if (then === IS_ERROR) {
      // 如果then IS_ERROR
      return reject(self, LAST_ERROR);
    }
    if (
      // 如果then是self的then
      // 并且Promise
      then === self.then &&
      // newValue 屬于Promise
      newValue instanceof Promise
    ) {
      // _state為3
      // 一般then之后走這里
      // 執(zhí)行then(newValue)返回了promise
      self._state = 3;
      // selft.value為newValue
      self._value = newValue;
      // 當(dāng)state為3時(shí)執(zhí)行 finale
      finale(self);
      return;
    } else if (typeof then === "function") {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  self._state = 1;
  self._value = newValue;
  finale(self);
}

在沒(méi)有鏈?zhǔn)秸{(diào)用then的情況下(也就是只要一個(gè)then)的情況下,會(huì)將內(nèi)部狀態(tài)_state設(shè)置成3,將傳入值賦給內(nèi)部變量_value最后會(huì)執(zhí)行final()方法,不然則會(huì)使用doResolve來(lái)調(diào)用then

我們?cè)賮?lái)看下reject

function reject(self, newValue) {
  // _state = 2為reject
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}

reject當(dāng)中我們的_state變更為了2,同樣最后finale被調(diào)用。

我們來(lái)看下finale函數(shù)

// 執(zhí)行自己的deferreds
function finale(self) {
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      // 遍歷handle
      handle(self, self._deferreds[i]);
    }
    // 將deferred 置空
    self._deferreds = null;
  }
}

在該方法當(dāng)中根據(jù)不同的_deferredState,會(huì)執(zhí)行不同的handle方法。

我們?cè)賮?lái)看handle方法

function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  // 如果有onHandle方法 則執(zhí)行該方法
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  // (初始 _state 為0)
  if (self._state === 0) {
    // (初始 _deferredState 為0)
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    // 如果 _deferredState是1 則__deferreds是一個(gè)數(shù)組
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    // 當(dāng)走到這里 _deferredState應(yīng)該是2 將deferred
    // 插入到數(shù)組當(dāng)中
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}

這里比較關(guān)鍵的應(yīng)該就是通過(guò)deferredState不同的狀態(tài),將deferred放入deferreds當(dāng)中。另外當(dāng)我們的_state不為0時(shí),最終會(huì)執(zhí)行handleResolved。

繼續(xù)看handleResolve()方法

function handleResolved(self, deferred) {
  asap(function() {
    // _state為1時(shí),cb = onFulfilled 否則 cb = onRejected
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}.then((res) => {
}).catch((error) => {
})

在這個(gè)方法當(dāng)中,會(huì)根據(jù)我們?nèi)蝿?wù)(_state)的不同狀態(tài),來(lái)執(zhí)行onFulfilled或者onRejected方法。當(dāng)此方法調(diào)用時(shí),也就是我們一個(gè)簡(jiǎn)單的Promise的結(jié)束。

回到剛才說(shuō)的Promise構(gòu)造方法結(jié)束的時(shí)候

設(shè)置了Promise函數(shù)的一些變量

Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

隨后在Promise的原型上設(shè)置了then方法。

Promise.prototype.then = function(onFulfilled, onRejected) {
  // 首先看這是誰(shuí)構(gòu)造的 如果不是promise
  // 則return 執(zhí)行safeThen
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  // 如果是則初始化一個(gè)Promise 但是參數(shù) noop 為空對(duì)象 {}
  var res = new Promise(noop);
  // 隨后執(zhí)行handle方法
  handle(this, new Handler(onFulfilled, onRejected, res));
  return res;
};

then這個(gè)方法中首先判斷了它是否由Promise構(gòu)造的,如果不是,則返回并執(zhí)行safeThen,不然則執(zhí)行Promise構(gòu)造一個(gè)res對(duì)象,然后執(zhí)行handle方法,最后將promise變量res返回。handle方法之前有提過(guò),在這里,當(dāng)初始化時(shí)_state_deferred的轉(zhuǎn)改都為0,因此它會(huì)將defrred保存到promise當(dāng)中。

先看一下上面說(shuō)的safeThen方法

function safeThen(self, onFulfilled, onRejected) {
  return new self.constructor(function (resolve, reject) {
    var res = new Promise(noop);
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}
流程

需要有一個(gè)Promise的構(gòu)造方法,這個(gè)構(gòu)造方法最終會(huì)執(zhí)行它的參數(shù)(resolve, reject) => {},聲明的then方法會(huì)通過(guò)handle()方法將onFulfilledonRejected方法保存起來(lái)。當(dāng)在外部調(diào)用resolve或者onRejected時(shí),最終也會(huì)執(zhí)行handle但是它,會(huì)最后根據(jù)狀態(tài)來(lái)執(zhí)行onFulfilled或者onRejected。從而到我們的then回調(diào)中。

Promise的擴(kuò)展 done

對(duì)done的擴(kuò)展在src/done.js當(dāng)中

"use strict";

var Promise = require("./core.js");

module.exports = Promise;
Promise.prototype.done = function (onFulfilled, onRejected) {
  var self = arguments.length ? this.then.apply(this, arguments) : this;
  self.then(null, function (err) {
    setTimeout(function () {
      throw err;
    }, 0);
  });
};

內(nèi)部執(zhí)行了then()

finally

對(duì)finally的擴(kuò)展在src/finally.js當(dāng)中

Promise的標(biāo)準(zhǔn)當(dāng)中,本身是沒(méi)有finally方法的,但是在ES2018的標(biāo)準(zhǔn)里有,finally的實(shí)現(xiàn)如下

"use strict";

var Promise = require("./core.js");

module.exports = Promise;
Promise.prototype.finally = function (callback) {
  return this.then(function (value) {
    return Promise.resolve(callback()).then(function () {
      return value;
    });
  }, function (err) {
    return Promise.resolve(callback()).then(function () {
      throw err;
    });
  });
};

PromiseonFulfilledonRejected 不管回調(diào)的哪個(gè),最終都會(huì)觸發(fā)callback 回調(diào)。還要注意的一點(diǎn)是finally的返回也是一個(gè)Promise。

es6-extensions.js

es6-extensions.js文件當(dāng)中包含了ES6的一些擴(kuò)展。

Promise.resolve
function valuePromise(value) {
  var p = new Promise(Promise._noop);
  // 將_state賦值為 非0
  // _value進(jìn)行保存
  p._state = 1;
  p._value = value;
  // 這樣做的目的是省略的一些前面的邏輯
  return p;
}

Promise.resolve = function (value) {
  if (value instanceof Promise) return value;

  if (value === null) return NULL;
  if (value === undefined) return UNDEFINED;
  if (value === true) return TRUE;
  if (value === false) return FALSE;
  if (value === 0) return ZERO;
  if (value === "") return EMPTYSTRING;

  // value return new Promise
  if (typeof value === "object" || typeof value === "function") {
    try {
      var then = value.then;
      if (typeof then === "function") {
        // 返回 返回了一個(gè)新的Promise對(duì)象
        return new Promise(then.bind(value));
      }
    } catch (ex) {
        // 如果報(bào)錯(cuò) 則返回一個(gè)就只
      return new Promise(function (resolve, reject) {
        reject(ex);
      });
    }
  }

  return valuePromise(value);
};
Promise.reject
Promise.reject = function (value) {
  return new Promise(function (resolve, reject) {
    reject(value);
  });
};
Promise.all
Promise.all = function (arr) {
  // 類(lèi)似深拷貝了一份給了args
  var args = Array.prototype.slice.call(arr);

  return new Promise(function (resolve, reject) {
    // 判斷了all的promise數(shù)量
    if (args.length === 0) return resolve([]);
    // remaining則是promise數(shù)組的長(zhǎng)度
    var remaining = args.length;
    // i為index val 為 promise
    function res(i, val) {
      if (val && (typeof val === "object" || typeof val === "function")) {
        if (val instanceof Promise && val.then === Promise.prototype.then) {
          while (val._state === 3) {
            val = val._value;
          }
          if (val._state === 1) return res(i, val._value);
          if (val._state === 2) reject(val._value);
          // val._state 為 0時(shí) 走這里
          val.then(function (val) {
            res(i, val);
          }, reject);
          return;
        } else {
          var then = val.then;
          if (typeof then === "function") {
            var p = new Promise(then.bind(val));
            p.then(function (val) {
              res(i, val);
            }, reject);
            return;
          }
        }
      }
      args[i] = val;
      // 當(dāng)所有的promise執(zhí)行完 則是remaining為0
      // 則執(zhí)行resolve();
      if (--remaining === 0) {
        resolve(args);
      }
    }
    // 遍歷所有的promise
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

Promise.all()返回的也是一個(gè)Promise函數(shù)。
內(nèi)部有一個(gè)remaining變量每當(dāng)執(zhí)行完一個(gè)promise函數(shù)后就會(huì)減一,當(dāng)所有promise執(zhí)行完,會(huì)執(zhí)行自己的resolve

Promise.race
Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};

遍歷傳入的promise數(shù)組,經(jīng)過(guò)Promise.resolve(value)的源碼可以看到,如果value是一個(gè)Promise則戶(hù)直接將這個(gè)value返回,最后數(shù)組中的promise哪個(gè)優(yōu)先回調(diào)即執(zhí)行。

Promise.property.catch

catch在標(biāo)準(zhǔn)當(dāng)中也是沒(méi)有,雖然我們用的比較多

Promise.prototype["catch"] = function (onRejected) {
  return this.then(null, onRejected);
};

catch的回調(diào)實(shí)際是then(null, onRejected)的回調(diào)。

廣而告之

本文發(fā)布于薄荷前端周刊,歡迎Watch & Star ★,轉(zhuǎn)載請(qǐng)注明出處。

歡迎討論,點(diǎn)個(gè)贊再走吧 ????? ~

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/100298.html

相關(guān)文章

  • co源碼分析及其實(shí)踐

    摘要:返回的結(jié)果是一個(gè)對(duì)象,類(lèi)似于表示本次后面執(zhí)行之后返回的結(jié)果。對(duì)象用于一個(gè)異步操作的最終完成或失敗及其結(jié)果值的表示簡(jiǎn)單點(diǎn)說(shuō)就是處理異步請(qǐng)求。源碼分析主要脈絡(luò)函數(shù)調(diào)用后,返回一個(gè)實(shí)例。參考鏈接解釋對(duì)象的用法的源碼及其用法 本文始發(fā)于我的個(gè)人博客,如需轉(zhuǎn)載請(qǐng)注明出處。為了更好的閱讀體驗(yàn),可以直接進(jìn)去我的個(gè)人博客看。 前言 知識(shí)儲(chǔ)備 閱讀本文需要對(duì)Generator和Promise有一個(gè)基本的...

    vincent_xyb 評(píng)論0 收藏0
  • lodash源碼分析之?dāng)?shù)據(jù)類(lèi)型獲取的兼容性

    摘要:實(shí)例中構(gòu)造函數(shù)的獲取每個(gè)實(shí)例中都包含一個(gè)的屬性,這個(gè)屬性指向的是實(shí)例的構(gòu)造函數(shù),在獲取到這個(gè)構(gòu)造函數(shù)后,就可以調(diào)用它的方法,然后就可以比較了。 焦慮和恐懼的區(qū)別是,恐懼是對(duì)世界上的存在的恐懼,而焦慮是在我面前的焦慮?!_特《存在與虛無(wú)》 本文為讀 lodash 源碼的第十九篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-lodash gitbook也會(huì)同步倉(cāng)庫(kù)的更新,...

    avwu 評(píng)論0 收藏0
  • Netty 源碼分析之 二 貫穿Netty 的大動(dòng)脈 ── ChannelPipeline (二)

    摘要:目錄源碼之下無(wú)秘密做最好的源碼分析教程源碼分析之番外篇的前生今世的前生今世之一簡(jiǎn)介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開(kāi)神秘的紅蓋頭源碼分析之一揭開(kāi)神秘的紅蓋頭客戶(hù)端 目錄 源碼之下無(wú)秘密 ── 做最好的 Netty 源碼分析教程 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NI...

    kamushin233 評(píng)論0 收藏0
  • 讀Zepto源碼之Deferred模塊

    摘要:為的項(xiàng),取出來(lái)的分別為和,所以上的和方法,調(diào)用的是中的方法,實(shí)質(zhì)是往各自的回調(diào)列表中添加回調(diào)函數(shù)。進(jìn)度回調(diào)函數(shù)數(shù)組。參數(shù)為異步對(duì)象的索引值,參數(shù)為對(duì)應(yīng)的上下文數(shù)組,即或,為對(duì)應(yīng)的回調(diào)函數(shù)數(shù)組,即或。 Deferred 模塊也不是必備的模塊,但是 ajax 模塊中,要用到 promise 風(fēng)格,必需引入 Deferred 模塊。Deferred 也用到了上一篇文章《讀Zepto源碼之C...

    yagami 評(píng)論0 收藏0
  • Netty channelRegisteredChannelActive---源碼分析

    摘要:背景最近發(fā)現(xiàn)的回調(diào)方法,在連接創(chuàng)建成功和讀取數(shù)據(jù)后都會(huì)被回調(diào)。那我也嘗試著從源碼找到答案吧?;卣{(diào)流程分析的回調(diào)流程和流程沒(méi)有什么區(qū)別,可參考上文分析。但是在的方法中會(huì)調(diào)用這個(gè)是讀數(shù)據(jù)的關(guān)鍵讀數(shù)據(jù)分析讀數(shù)據(jù)分析 背景 最近發(fā)現(xiàn)ChannelOutboundHandlerAdapter的read()回調(diào)方法,在連接創(chuàng)建成功和讀取數(shù)據(jù)后都會(huì)被回調(diào)。因此就產(chǎn)生了疑問(wèn)為什么建立連接和讀取數(shù)據(jù)后r...

    wanghui 評(píng)論0 收藏0
  • 從react-start到co源碼(三)

    摘要:第三篇腳手架依賴(lài)的核心庫(kù)的源碼解析。該篇是這個(gè)系列文章的第三篇主要是對(duì)的源碼進(jìn)行分析講解。的源碼十分簡(jiǎn)單但實(shí)現(xiàn)的功能卻是十分的強(qiáng)大。源碼概括源碼主要包含了兩部分公共方法和私有方法。 react作為當(dāng)前十分流行的前端框架,相信很多前端er都有蠢蠢欲動(dòng)的學(xué)習(xí)它的想法。工欲善其事,必先利其器。這篇文章就簡(jiǎn)單的給大家介紹一下如何我快速的搭建一個(gè)react前端開(kāi)發(fā)環(huán)境。主要針對(duì)于react小白,...

    wind5o 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<