国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

如何從零開始利用js手寫一個Promise庫詳解

2024-05-06 16:43:47
字體:
供稿:網(wǎng)友

前言

ECMAScript 是 JavaScript 語言的國際標準,JavaScript 是 ECMAScript 的實現(xiàn)。ES6 的目標,是使得 JavaScript 語言可以用來編寫大型的復雜的應用程序,成為企業(yè)級開發(fā)語言。

概念

ES6 原生提供了 Promise 對象。

所謂 Promise,就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結(jié)果的事件(通常是一個異步操作),并且這個事件提供統(tǒng)一的 API,可供進一步處理。

三道思考題

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

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

而且,為了檢驗大家是否真的完全掌握了promise,我會在文章結(jié)尾出幾道跟promise相關的練習題。說是練習題,其實都是大家項目中會遇到的真實場景的抽象,熟練掌握可以幫助大家在前端方面更上一層樓。

提前將三道練習題給出來,大家可以先不看下文的內(nèi)容,在腦海里大概構思下你會怎么解決:

  • promise array的鏈式調(diào)用?
  • promise怎么做并發(fā)控制?
  • promise怎么做異步緩存?

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

什么是Promise

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

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

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

jsp/5951.html">js;">const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操作成功 */){ resolve(value); } else { reject(error); }});promise.then(function(value) { // success}, function(error) { // failure});

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

實現(xiàn)一個Promise:CutePromise

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

class CutePromise { // executor是我們實例化CutePromise時傳入的參數(shù)函數(shù),它接受兩個參數(shù),分別是resolve和reject。 // resolve和reject我們將會定義在constructor當中,供executor在執(zhí)行的時候調(diào)用 constructor(executor) { const resolve = () => {} const reject = () => {} executor(resolve, reject) } // 為實例提供一個then的方法,接收兩個參數(shù)函數(shù), // 第一個參數(shù)函數(shù)必傳,它會在promise已成功(fulfilled)以后被調(diào)用 // 第二個參數(shù)非必傳,它會在promise已失敗(rejected)以后被調(diào)用 then(onFulfilled, onRejected) {}}

創(chuàng)建了我們的CutePromise后,我們再來搞清楚一個關鍵點:Promise 對象的狀態(tài)。

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

  • 異步操作未完成(pending)
  • 異步操作成功(fulfilled)
  • 異步操作失敗(rejected)

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

現(xiàn)在我們來為CutePromise添加狀態(tài),大概流程就是:

首先,實例化初始過程中,我們先將狀態(tài)設為PENDING,然后當executor執(zhí)行resolve的時候,將狀態(tài)更改為FULFILLED,當executor執(zhí)行reject的時候?qū)顟B(tài)更改為REJECTED。同時更新實例的value。

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

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

constructor(executor) { ... this.state = 'PENDING';  // chained用來儲存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 }); }}

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

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 }); } }}

提供一下測試代碼:

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));

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網(wǎng)的支持。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 云和县| 三门峡市| 岑巩县| 新宾| 宁海县| 成都市| 云霄县| 和林格尔县| 尤溪县| 景洪市| 唐山市| 商都县| 福州市| 定南县| 洛浦县| 云浮市| 福建省| 元朗区| 上杭县| 广西| 客服| 济源市| 武冈市| 靖江市| 福泉市| 凤翔县| 满城县| 兰考县| 宜章县| 麻江县| 离岛区| 抚宁县| 砚山县| 恩平市| 汤阴县| 霍林郭勒市| 兴义市| 德清县| 万载县| 漳州市| 林甸县|