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

資訊專欄INFORMATION COLUMN

從零開始實(shí)現(xiàn)一個(gè)自己的Promise庫(kù)

paulquei / 2107人閱讀

摘要:所以,這篇文章我會(huì)帶大家從零開始,手寫一個(gè)基本能用的。首先,規(guī)定對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成實(shí)例。然后,這個(gè)構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是和。對(duì)象通過自身的狀態(tài),來(lái)控制異步操作。

剛開始寫前端的時(shí)候,處理異步請(qǐng)求經(jīng)常用callback,簡(jiǎn)單又順手。后來(lái)寫著寫著就拋棄了callback,開始用promise來(lái)處理異步問題。promise寫起來(lái)確實(shí)更加優(yōu)美,但由于缺乏對(duì)它內(nèi)部結(jié)構(gòu)的深刻認(rèn)識(shí),每次在遇到一些復(fù)雜的情況時(shí),promise用起來(lái)總是不那么得心應(yīng)手,debug也得搞半天。

所以,這篇文章我會(huì)帶大家從零開始,手寫一個(gè)基本能用的promise。跟著我寫下來(lái)以后,你會(huì)對(duì)promise是什么以及它的內(nèi)部結(jié)構(gòu)有一個(gè)清楚的認(rèn)知,未來(lái)在復(fù)雜場(chǎng)景下使用promise也能如魚得水。

什么是Promise

回到正文,什么是Promise?說白了,promise就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。

首先,ES6規(guī)定Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成Promise實(shí)例。然后,這個(gè)構(gòu)造函數(shù)接受一個(gè)函數(shù)(executor)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject。最后,Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)(onFulfilled和onRejected)。

具體的使用方法,用代碼表現(xiàn)是這樣:

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

理解了這個(gè)后,我們就可以大膽的開始構(gòu)造我們自己的promise了,我們給它取個(gè)名字:CutePromise

實(shí)現(xiàn)一個(gè)Promise:CutePromise

我們直接用ES6的class來(lái)創(chuàng)建我們的CutePromise,對(duì)ES6語(yǔ)法還不熟悉的,可以先讀一下我的另外兩篇介紹ES6核心語(yǔ)法的文章后再回來(lái)。30分鐘掌握ES6/ES2015核心內(nèi)容(上)、30分鐘掌握ES6/ES2015核心內(nèi)容(下)

class CutePromise {

  // executor是我們實(shí)例化CutePromise時(shí)傳入的參數(shù)函數(shù),它接受兩個(gè)參數(shù),分別是resolve和reject。
  // resolve和reject我們將會(huì)定義在constructor當(dāng)中,供executor在執(zhí)行的時(shí)候調(diào)用
  constructor(executor) {
    const resolve = () => {}
    const reject = () => {}
    
    executor(resolve, reject)
  }

  // 為實(shí)例提供一個(gè)then的方法,接收兩個(gè)參數(shù)函數(shù),
  // 第一個(gè)參數(shù)函數(shù)必傳,它會(huì)在promise已成功(fulfilled)以后被調(diào)用
  // 第二個(gè)參數(shù)非必傳,它會(huì)在promise已失敗(rejected)以后被調(diào)用
  then(onFulfilled, onRejected) {}

}

創(chuàng)建了我們的CutePromise后,我們?cè)賮?lái)搞清楚一個(gè)關(guān)鍵點(diǎn):Promise 對(duì)象的狀態(tài)。

Promise 對(duì)象通過自身的狀態(tài),來(lái)控制異步操作。一個(gè)Promise 實(shí)例具有三種狀態(tài):

異步操作未完成(pending)

異步操作成功(fulfilled)

異步操作失?。╮ejected)

上面三種狀態(tài)里面,fulfilled和rejected合在一起稱為resolved(已定型)。狀態(tài)的切換只有兩條路徑:第一種是從pending=>fulfilled,另一種是從pending=>rejected,狀態(tài)一旦切換就不能再改變。

現(xiàn)在我們來(lái)為CutePromise添加狀態(tài),大概流程就是:
首先,實(shí)例化初始過程中,我們先將狀態(tài)設(shè)為PENDING,然后當(dāng)executor執(zhí)行resolve的時(shí)候,將狀態(tài)更改為FULFILLED,當(dāng)executor執(zhí)行reject的時(shí)候?qū)顟B(tài)更改為REJECTED。同時(shí)更新實(shí)例的value。

constructor(executor) {
    ...
    this.state = "PENDING";
    ...
    const resolve = (result) => {
      this.state = "FULFILLED";
      this.value = result;
    }
    const reject = (error) => {
      this.state = "REJECTED";
      this.value = error;
    }
    ...
}

再來(lái)看下我們的then函數(shù)。then函數(shù)的兩個(gè)參數(shù),onFulfilled表示當(dāng)promise異步操作成功時(shí)調(diào)用的函數(shù),onRejected表示當(dāng)promise異步操作失敗時(shí)調(diào)用的函數(shù)。假如我們調(diào)用then的時(shí)候,promise已經(jīng)執(zhí)行完成了(當(dāng)任務(wù)是個(gè)同步任務(wù)時(shí)),我們可以直接根據(jù)實(shí)例的狀態(tài)來(lái)執(zhí)行相應(yīng)的函數(shù)。假如promise的狀態(tài)還是PENDING, 那我們就將onFulfilled和onRejected直接存儲(chǔ)到chained這個(gè)變量當(dāng)中,等promise執(zhí)行完再調(diào)用。

constructor(executor) {
    ...
    this.state = "PENDING";
    
    // chained用來(lái)儲(chǔ)存promise執(zhí)行完成以后,需要被依次調(diào)用的一系列函數(shù)
    this.chained = [];
    
    const resolve = (result) => {
      this.state = "FULFILLED";
      this.value = result;
      
      // promise已經(jīng)執(zhí)行成功了,可以依次調(diào)用.then()函數(shù)里的onFulfilled函數(shù)了
      for (const { onFulfilled } of this.chained) {
          onFulfilled(res);
      }
    }

    ...
}
then(onFulfilled, onRejected) {
  if (this.state === "FULFILLED") {
    onFulfilled(this.value);
  } else if (this.state === "REJECTED") {
    onRejected(this.value);
  } else {
    this.$chained.push({ onFulfilled, onRejected });
  }
}

這樣我們就完成了一個(gè)CutePromise的創(chuàng)建,下面是完整代碼,大家可以復(fù)制代碼到控制臺(tái)測(cè)試一下:

class CutePromise {

  constructor(executor) {
    if (typeof executor !== "function") {
      throw new Error("Executor must be a function");
    }

    this.state = "PENDING";
    this.chained = [];

    const resolve = res => {
      if (this.state !== "PENDING") {
        return;
      }

      this.state = "FULFILLED";
      this.internalValue = res;

      for (const { onFulfilled } of this.chained) {
        onFulfilled(res);
      }
    };
    const reject = err => {
      if (this.state !== "PENDING") {
        return;
      }
      this.state = "REJECTED";
      this.internalValue = err;
      for (const { onRejected } of this.chained) {
        onRejected(err);
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
    
  then(onFulfilled, onRejected) {
    if (this.state === "FULFILLED") {
      onFulfilled(this.internalValue);
    } else if (this.$state === "REJECTED") {
      onRejected(this.internalValue);
    } else {
      this.chained.push({ onFulfilled, onRejected });
    }
  }
}

提供一下測(cè)試代碼:

let p = new CutePromise(resolve => {
  setTimeout(() => resolve("Hello"), 100);
});

p.then(res => console.log(res));

p = new CutePromise((resolve, reject) => {
  setTimeout(() => reject(new Error("woops")), 100);
});

p.then(() => {}, err => console.log("Async error:", err.stack));

p = new CutePromise(() => { throw new Error("woops"); });

p.then(() => {}, err => console.log("Sync error:", err.stack));
實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用

實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用其實(shí)很簡(jiǎn)單,只需要在我們定義的then()方法里返回一個(gè)新的CutePromise即可。

  then(onFulfilled, onRejected) {
    return new CutePromise((resolve, reject) => {

      const _onFulfilled = res => {
        try {
          //注意這里resolve有可能要處理的是一個(gè)promise
          resolve(onFulfilled(res));
        } catch (err) {
          reject(err);
        }
      };
      const _onRejected = err => {
        try {
          reject(onRejected(err));
        } catch (_err) {
          reject(_err);
        }
      };
      if (this.state === "FULFILLED") {
        _onFulfilled(this.internalValue);
      } else if (this.state === "REJECTED") {
        _onRejected(this.internalValue);
      } else {
        this.chained.push({ onFulfilled: _onFulfilled, onRejected: _onRejected });
      }
    });
  }

不過,我們還需要解決一個(gè)問題:假如then函數(shù)的第一個(gè)參數(shù)onfulfilled()本身返回的也是一個(gè)promise怎么辦?比如下面這種使用方式,其實(shí)是最真實(shí)項(xiàng)目場(chǎng)景中最常見:

p = new CutePromise(resolve => {
  setTimeout(() => resolve("World"), 100);
});

p.
  then(res => new CutePromise(resolve => resolve(`Hello, ${res}`))).
  then(res => console.log(res));

所以我們需要讓我們的resolve方法能夠處理promise:

const resolve = res => {
      if (this.state !== "PENDING") {
        return;
      }
      
      // 假如說res這個(gè)對(duì)象有then的方法,我們就認(rèn)為res是一個(gè)promise
      if (res != null && typeof res.then === "function") {
        return res.then(resolve, reject);
      }
    ...
}
三道思考題

promise array的鏈?zhǔn)秸{(diào)用?

promise怎么做并發(fā)控制?

promise怎么做異步緩存?

以上三道思考題其實(shí)跟你用不用promise并沒有多大關(guān)系,但是如果你不深刻理解promise想要解決這三個(gè)問題還真不是那么輕松的。

參考:https://brunoscopelliti.com/l...

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

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

相關(guān)文章

  • 前端之從零開始系列

    摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫函數(shù)庫(kù)中高級(jí)前端面試手寫代碼無(wú)敵秘籍如何用不到行代碼寫一款屬于自己的類庫(kù)原理講解實(shí)現(xiàn)一個(gè)對(duì)象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...

    Youngdze 評(píng)論0 收藏0
  • 從零開始一個(gè) Promise 庫(kù)

    摘要:是什么在規(guī)范中,是一個(gè)類,它的構(gòu)造函數(shù)接受一個(gè)函數(shù)。在這種情況下,是但處于狀態(tài)。與一起使用關(guān)鍵字會(huì)暫停執(zhí)行一個(gè)函數(shù),直到等待的變成狀態(tài)。此外,會(huì)一直等待調(diào)用直到下一個(gè)時(shí)序。 原文:Write Your Own Node.js Promise Library from Scratch作者:code_barbarian Promise 已經(jīng)是 JavaScript 中異步處理的基石,回調(diào)...

    Binguner 評(píng)論0 收藏0
  • 從零開始搭建React同構(gòu)應(yīng)用(二):瀏覽器端工程化

    摘要:從零開始搭建同構(gòu)應(yīng)用二項(xiàng)目工程化瀏覽器端在從零開始同構(gòu)開發(fā)一中我們已經(jīng)能實(shí)現(xiàn)基本的配置和編譯了。接下來(lái)我們需要將編譯工作工程化。配置作用自動(dòng)生成自動(dòng)在引入,。文件內(nèi)容如下同構(gòu)開發(fā)配置自動(dòng)刷新這里我們用到的修飾器特性。 從零開始搭建React同構(gòu)應(yīng)用(二) 項(xiàng)目工程化(瀏覽器端) 在從零開始React同構(gòu)開發(fā)(一)中我們已經(jīng)能實(shí)現(xiàn)基本的React配置和編譯了。接下來(lái)我們需要將編譯工作工程...

    wwq0327 評(píng)論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...

    tuniutech 評(píng)論0 收藏0
  • javascript知識(shí)點(diǎn)

    摘要:模塊化是隨著前端技術(shù)的發(fā)展,前端代碼爆炸式增長(zhǎng)后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調(diào)也不等同于異步。將會(huì)討論安全的類型檢測(cè)惰性載入函數(shù)凍結(jié)對(duì)象定時(shí)器等話題。 Vue.js 前后端同構(gòu)方案之準(zhǔn)備篇——代碼優(yōu)化 目前 Vue.js 的火爆不亞于當(dāng)初的 React,本人對(duì)寫代碼有潔癖,代碼也是藝術(shù)。此篇是準(zhǔn)備篇,工欲善其事,必先利其器。我們先在代...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<