日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

promise用法_图解 Promise 实现原理(四):Promise 静态方法实现

發布時間:2024/9/27 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 promise用法_图解 Promise 实现原理(四):Promise 静态方法实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:Morrain

轉發鏈接:https://mp.weixin.qq.com/s/Lp_5BXdpm7G29Z7zT_S-bQ

前言

Promise 是異步編程的一種解決方案,它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。更多關于 Promise 的介紹請參考阮一峰老師的 ES6入門 之 Promise 對象。

很多同學在學習 Promise 時,知其然卻不知其所以然,對其中的用法理解不了。本系列文章由淺入深逐步實現 Promise,并結合流程圖、實例以及動畫進行演示,達到深刻理解 Promise 用法的目的。

本系列文章由如下幾個章節組成:

圖解 Promise 實現原理(一):基礎實現

圖解 Promise 實現原理(二):Promise 鏈式調用

圖解 Promise 實現原理(三):Promise 原型方法實現

圖解 Promise 實現原理(四):Promise 靜態方法實現(本篇)

上一節中,實現了 Promise 的原型方法。包括增加異常狀態,catch以及 finally。截至目前,Promise 的實現如下:

class Promise { callbacks = []; state = 'pending';//增加狀態 value = null;//保存結果 constructor(fn) { fn(this._resolve.bind(this), this._reject.bind(this)); } then(onFulfilled, onRejected) { return new Promise((resolve, reject) => { this._handle({ onFulfilled: onFulfilled || null, onRejected: onRejected || null, resolve: resolve, reject: reject }); }); } catch(onError) { return this.then(null, onError); } finally(onDone) { if (typeof onDone !== 'function') return this.then(); let Promise = this.constructor; return this.then( value => Promise.resolve(onDone()).then(() => value), reason => Promise.resolve(onDone()).then(() => { throw reason }) ); } _handle(callback) { if (this.state === 'pending') { this.callbacks.push(callback); return; } let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected; if (!cb) {//如果then中沒有傳遞任何東西 cb = this.state === 'fulfilled' ? callback.resolve : callback.reject; cb(this.value); return; } let ret; try { ret = cb(this.value); cb = this.state === 'fulfilled' ? callback.resolve : callback.reject; } catch (error) { ret = error; cb = callback.reject } finally { cb(ret); } } _resolve(value) { if (value && (typeof value === 'object' || typeof value === 'function')) { var then = value.then; if (typeof then === 'function') { then.call(value, this._resolve.bind(this), this._reject.bind(this)); return; } } this.state = 'fulfilled';//改變狀態 this.value = value;//保存結果 this.callbacks.forEach(callback => this._handle(callback)); } _reject(error) { this.state = 'rejected'; this.value = error; this.callbacks.forEach(callback => this._handle(callback)); }}

(滑動可查看)

接下來再介紹一下 Promise 種靜態方法的實現,譬如 Promise.resolve、Promise.reject、Promise.all 和 Promise.race。其它靜態方法的實現也是類似的。

【靜態方法】

1、Promise.resolve && Promise.reject

除了前文中提到的 Promise實例的原型方法外,Promise 還提供了 Promise.resolve 和Promise.reject 方法。用于將非 Promise 實例包裝為 Promise 實例。例如:

Promise.resolve('foo')// 等價于new Promise(resolve => resolve('foo'))

(滑動可查看)

Promise.resolve 的參數不同對應的處理也不同,如果 Promise.resolve 的參數是一個 Promise的實例,那么 Promise.resolve 將不做任何改動,直接返回這個 Promise 實例,如果是一個基本數據類型,譬如上例中的字符串,Promise.resolve 就會新建一個 Promise 實例返回。這樣當我們不清楚拿到的對象到底是不是 Promise 實例時,為了保證統一的行為,Promise.resolve 就變得很有用了。看一個例子:

const Id2NameMap = {};const getNameById = function (id) { if (Id2NameMap[id]) return Id2NameMap[id]; return new Promise(resolve => { mockGetNameById(id, function (name) { Id2NameMap[id] = name; resolve(name); }) });}getNameById(id).then(name => { console.log(name);});

(滑動可查看)

上面的場景我們會經常碰到,為了減少請求,經常會緩存數據,我們獲取到 id 對應的名字后,存到 Id2NameMap 對象里,下次再通過 id 去請求 id 對應的 name 時先看 Id2NameMap里有沒有,如果有就直接返回對應的 name,如果沒有就發起異步請求,獲取到后放到 Id2NameMap 中去。

其實上面的代碼是有問題的,如果命中 Id2NameMap 里的值,getNameById 返回的結果就是 name,而不是 Promise 實例。此時 getNameById(id).then 會報錯。在我們不清楚返回的是否是 Promise 實例的情況下,就可以使用 Promise.resolve 進行包裝:

Promise.resolve(getNameById(id)).then(name => { console.log(name);});

(滑動可查看)

這樣一來,不管 getNameById(id) 返回的是什么,邏輯都沒有問題。看下面的Demo:

demo-Promise.resolve 的源碼

地址:https://repl.it/@morrain2016/demo-Promiseresolve

在實現 Promise.resolve 之前,我們先看下它的參數分為哪些情況:

(1)參數是一個 Promise 實例

如果參數是 Promise 實例,那么 Promise.resolve 將不做任何修改、原封不動地返回這個實例。

(2)參數是一個 thenable 對象

thenable 對象指的是具有 then 方法的對象,比如下面這個對象。

let thenable = { then: function(onFulfilled) { onFulfilled(42); }};

(滑動可查看)

Promise.resolve 方法會將這個對象轉為 Promise 對象,然后就立即執行 thenable 對象的 then方法。

let thenable = { then: function(onFulfilled) { onFulfilled(42); }}; let p1 = Promise.resolve(thenable);p1.then(function(value) { console.log(value); // 42});

(滑動可查看)

上面代碼中,thenable對象的then方法執行后,對象p1的狀態就變為resolved,從而立即執行最后那個then方法指定的回調函數,輸出 42。

(3)參數不是具有 then 方法的對象,或根本就不是對象

如果參數是一個原始值,或者是一個不具有then方法的對象,則 Promise.resolve 方法返回一個新的 Promise 對象,狀態為 resolved。

(4)不帶任務參數

Promise.resolve 方法允許調用時不帶參數,直接返回一個 resolved 狀態的 Promise 對象。

static resolve(value) { if (value && value instanceof Promise) { return value; } else if (value && typeof value === 'object' && typeof value.then === 'function') { let then = value.then; return new Promise(resolve => { then(resolve); }); } else if (value) { return new Promise(resolve => resolve(value)); } else { return new Promise(resolve => resolve()); }}

(滑動可查看)

Promise.reject 與 Promise.resolve 類似,區別在于 Promise.reject 始終返回一個狀態的 rejected 的 Promise 實例,而 Promise.resolve 的參數如果是一個 Promise 實例的話,返回的是參數對應的 Promise 實例,所以狀態不一定。

Promise.reject 的實現源碼

地址:https://repl.it/@morrain2016/Promise

2、Promise.all && Promise.race

Promise.all 接收一個 Promise 實例的數組,在所有這些 Promise 的實例都 fulfilled 后,按照 Promise 實例的順序返回相應結果的數組。

const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve('p1'), 1000)}) const p2 = new Promise((resolve, reject) => { setTimeout(() => resolve('p2'), 5000)}) Promise.all([p1, p2]).then(rets => { console.log(rets) // ['p1','p2']})

(滑動可查看)

Promise.all 的實現如下:

static all(promises) { return new Promise((resolve, reject) => { let fulfilledCount = 0 const itemNum = promises.length const rets = Array.from({ length: itemNum }) promises.forEach((promise, index) => { Promise.resolve(promise).then(result => { fulfilledCount++; rets[index] = result; if (fulfilledCount === itemNum) { resolve(rets); } }, reason => reject(reason)); }) })}

(滑動可查看)

Promise.all 的實現源碼

地址:https://repl.it/@morrain2016/Promise

Promise.race 也接收一個 Promise 實例的數組,與 Promise.all不同的是,所以返回的結果是這些 Promise 實例中最先 fulfilled 的。

const p1 = new Promise((resolve, reject) => { setTimeout(() => resolve('p1'), 1000)}) const p2 = new Promise((resolve, reject) => { setTimeout(() => resolve('p2'), 5000)}) Promise.race([p1, p2]).then(ret => { console.log(ret) // 'p1'})

(滑動可查看)

Promise.race 的實現如下:

static race(promises) { return new Promise(function (resolve, reject) { for (let i = 0; i < promises.length; i++) { Promise.resolve(promises[i]).then(function (value) { return resolve(value) }, function (reason) { return reject(reason) }) } })}

(滑動可查看)

Promise.race 的實現源碼

地址:https://repl.it/@morrain2016/Promise

【總結】

剛開始看 Promise 源碼的時候總不能很好的理解 then 和 resolve 函數的運行機理,但是如果你靜下心來,反過來根據執行 Promise 時的邏輯來推演,就不難理解了。這里一定要注意的點是:Promise 里面的 then 函數僅僅是注冊了后續需要執行的代碼,真正的執行是在 resolve 方法里面執行的,理清了這層,再來分析源碼會省力的多。

現在回顧下 Promise 的實現過程,其主要使用了設計模式中的觀察者模式:

  • 通過 Promise.prototype.then 和 Promise.prototype.catch 方法將觀察者方法注冊到被觀察者 Promise 對象中,同時返回一個新的 Promise 對象,以便可以鏈式調用。
  • 被觀察者管理內部 pending、fulfilled 和 rejected 的狀態轉變,同時通過構造函數中傳遞的 resolve 和 reject 方法以主動觸發狀態轉變和通知觀察者。
  • 本系列圖文講解的是 Promise 的思想,實現的內容并不能完全滿足 Promise/A+ 規范的所有要求。

    推薦JavaScript經典實例學習資料文章

    《圖解 Promise 實現原理(一):基礎實現》

    《圖解 Promise 實現原理(二):Promise 鏈式調用》

    《圖解 Promise 實現原理(三):Promise 原型方法實現》

    《實踐教你從零構建前端 Lint 工作流「干貨」》

    《高性能多級多選級聯組件開發「JS篇」》

    《深入淺出講解Node.js CLI 工具最佳實戰》

    《延遲加載圖像以提高Web網站性能的五種方法「實踐」》

    《比較 JavaScript 對象的四種方式「實踐」》

    《使用Service Worker讓你的 Web 應用如虎添翼(上)「干貨」》

    《使用Service Worker讓你的 Web 應用如虎添翼(中)「干貨」》

    《使用Service Worker讓你的 Web 應用如虎添翼(下)「干貨」》

    《前端如何一次性處理10萬條數據「進階篇」》

    《推薦三款正則可視化工具「JS篇」》

    《如何讓用戶選擇是否離開當前頁面?「JS篇」》

    《JavaScript開發人員更喜歡Deno的五大原因》

    《僅用18行JavaScript實現一個倒數計時器》

    《圖文細說JavaScript 的運行機制》

    《一個輕量級 JavaScript 全文搜索庫,輕松實現站內離線搜索》

    《推薦Web程序員常用的15個源代碼編輯器》

    《10個實用的JS技巧「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(一)「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(二)「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(三)「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(四)「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(五)「值得收藏」》

    《細品269個JavaScript小函數,讓你少加班熬夜(六)「值得收藏」》

    《深入JavaScript教你內存泄漏如何防范》

    《手把手教你7個有趣的JavaScript 項目-上「附源碼」》

    《手把手教你7個有趣的JavaScript 項目-下「附源碼」》

    《JavaScript 使用 mediaDevices API 訪問攝像頭自拍》

    《手把手教你前端代碼如何做錯誤上報「JS篇」》

    《一文讓你徹底搞懂移動前端和Web 前端區別在哪里》

    《63個JavaScript 正則大禮包「值得收藏」》

    《提高你的 JavaScript 技能10 個問答題》

    《JavaScript圖表庫的5個首選》

    《一文徹底搞懂JavaScript 中Object.freeze與Object.seal的用法》

    《可視化的 JS:動態圖演示 - 事件循環 Event Loop的過程》

    《教你如何用動態規劃和貪心算法實現前端瀑布流布局「實踐」》

    《可視化的 js:動態圖演示 Promises & Async/Await 的過程》

    《原生JS封裝拖動驗證滑塊你會嗎?「實踐」》

    《如何實現高性能的在線 PDF 預覽》

    《細說使用字體庫加密數據-仿58同城》

    《Node.js要完了嗎?》

    《Pug 3.0.0正式發布,不再支持 Node.js 6/8》

    《純JS手寫輪播圖(代碼邏輯清晰,通俗易懂)》

    《JavaScript 20 年 中文版之創立標準》

    《值得收藏的前端常用60余種工具方法「JS篇」》

    《箭頭函數和常規函數之間的 5 個區別》

    《通過發布/訂閱的設計模式搞懂 Node.js 核心模塊 Events》

    《「前端篇」不再為正則煩惱》

    《「速圍」Node.js V14.3.0 發布支持頂級 Await 和 REPL 增強功能》

    《深入細品瀏覽器原理「流程圖」》

    《JavaScript 已進入第三個時代,未來將何去何從?》

    《前端上傳前預覽文件 image、text、json、video、audio「實踐」》

    《深入細品 EventLoop 和瀏覽器渲染、幀動畫、空閑回調的關系》

    《推薦13個有用的JavaScript數組技巧「值得收藏」》

    《前端必備基礎知識:window.location 詳解》

    《不要再依賴CommonJS了》

    《犀牛書作者:最該忘記的JavaScript特性》

    《36個工作中常用的JavaScript函數片段「值得收藏」》

    《Node + H5 實現大文件分片上傳、斷點續傳》

    《一文了解文件上傳全過程(1.8w字深度解析)「前端進階必備」》

    《【實踐總結】關于小程序掙脫枷鎖實現批量上傳》

    《手把手教你前端的各種文件上傳攻略和大文件斷點續傳》

    《字節跳動面試官:請你實現一個大文件上傳和斷點續傳》

    《談談前端關于文件上傳下載那些事【實踐】》

    《手把手教你如何編寫一個前端圖片壓縮、方向糾正、預覽、上傳插件》

    《最全的 JavaScript 模塊化方案和工具》

    《「前端進階」JS中的內存管理》

    《JavaScript正則深入以及10個非常有意思的正則實戰》

    《前端面試者經常忽視的一道JavaScript 面試題》

    《一行JS代碼實現一個簡單的模板字符串替換「實踐」》

    《JS代碼是如何被壓縮的「前端高級進階」》

    《前端開發規范:命名規范、html規范、css規范、js規范》

    《【規范篇】前端團隊代碼規范最佳實踐》

    《100個原生JavaScript代碼片段知識點詳細匯總【實踐】》

    《關于前端174道 JavaScript知識點匯總(一)》

    《關于前端174道 JavaScript知識點匯總(二)》

    《關于前端174道 JavaScript知識點匯總(三)》

    《幾個非常有意思的javascript知識點總結【實踐】》

    《都2020年了,你還不會JavaScript 裝飾器?》

    《JavaScript實現圖片合成下載》

    《70個JavaScript知識點詳細總結(上)【實踐】》

    《70個JavaScript知識點詳細總結(下)【實踐】》

    《開源了一個 JavaScript 版敏感詞過濾庫》

    《送你 43 道 JavaScript 面試題》

    《3個很棒的小眾JavaScript庫,你值得擁有》

    《手把手教你深入鞏固JavaScript知識體系【思維導圖】》

    《推薦7個很棒的JavaScript產品步驟引導庫》

    《Echa哥教你徹底弄懂 JavaScript 執行機制》

    《一個合格的中級前端工程師需要掌握的 28 個 JavaScript 技巧》

    《深入解析高頻項目中運用到的知識點匯總【JS篇】》

    《JavaScript 工具函數大全【新】》

    《從JavaScript中看設計模式(總結)》

    《身份證號碼的正則表達式及驗證詳解(JavaScript,Regex)》

    《瀏覽器中實現JavaScript計時器的4種創新方式》

    《Three.js 動效方案》

    《手把手教你常用的59個JS類方法》

    《127個常用的JS代碼片段,每段代碼花30秒就能看懂-【上】》

    《深入淺出講解 js 深拷貝 vs 淺拷貝》

    《手把手教你JS開發H5游戲【消滅星星】》

    《深入淺出講解JS中this/apply/call/bind巧妙用法【實踐】》

    《手把手教你全方位解讀JS中this真正含義【實踐】》

    《書到用時方恨少,一大波JS開發工具函數來了》

    《干貨滿滿!如何優雅簡潔地實現時鐘翻牌器(支持JS/Vue/React)》

    《手把手教你JS 異步編程六種方案【實踐】》

    《讓你減少加班的15條高效JS技巧知識點匯總【實踐】》

    《手把手教你JS開發H5游戲【黃金礦工】》

    《手把手教你JS實現監控瀏覽器上下左右滾動》

    《JS 經典實例知識點整理匯總【實踐】》

    《2.6萬字JS干貨分享,帶你領略前端魅力【基礎篇】》

    《2.6萬字JS干貨分享,帶你領略前端魅力【實踐篇】》

    《簡單幾步讓你的 JS 寫得更漂亮》

    《恭喜你獲得治療JS this的詳細藥方》

    《談談前端關于文件上傳下載那些事【實踐】》

    《面試中教你繞過關于 JavaScript 作用域的 5 個坑》

    《Jquery插件(常用的插件庫)》

    《【JS】如何防止重復發送ajax請求》

    《JavaScript+Canvas實現自定義畫板》

    《Continuation 在 JS 中的應用「前端篇」》

    作者:Morrain

    轉發鏈接:https://mp.weixin.qq.com/s/Lp_5BXdpm7G29Z7zT_S-bQ

    總結

    以上是生活随笔為你收集整理的promise用法_图解 Promise 实现原理(四):Promise 静态方法实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。