摘要:以下,請(qǐng)求兩個(gè),當(dāng)兩個(gè)異步請(qǐng)求返還結(jié)果后,再請(qǐng)求第三個(gè)此處為調(diào)用后的結(jié)果的數(shù)組對(duì)于來說,只要參數(shù)數(shù)組有一個(gè)元素變?yōu)闆Q定態(tài),便返回新的。
Promise 札記
研究 Promise 的動(dòng)機(jī)大體有以下幾點(diǎn):
對(duì)其 api 的不熟悉以及對(duì)實(shí)現(xiàn)機(jī)制的好奇;
很多庫(比如 fetch)是基于 Promise 封裝的,那么要了解這些庫的前置條件得先熟悉 Promise;
要了解其它更為高級(jí)的異步操作得先熟悉 Promise;
基于這些目的,實(shí)踐了一個(gè)符合 Promise/A+ 規(guī)范的 repromise
本札記系列總共三篇文章,作為之前的文章 Node.js 異步異聞錄 的拆分和矯正。
Promise札記
Generator札記
Async札記
Promise/A+ 核心在實(shí)現(xiàn)一個(gè)符合 Promise/A+ 規(guī)范的 promise 之前,先了解下 Promise/A+ 核心,想更全面地了解可以閱讀 Promise/A+規(guī)范
Promise 操作只會(huì)處在 3 種狀態(tài)的一種:未完成態(tài)(pending)、完成態(tài)(resolved) 和失敗態(tài)(rejected);
Promise 的狀態(tài)只會(huì)出現(xiàn)從未完成態(tài)向完成態(tài)或失敗態(tài)轉(zhuǎn)化;
Promise 的狀態(tài)一旦轉(zhuǎn)化,將不能被更改;
repromise api 食用手冊(cè) Promise.resolve()Promise.resolve() 括號(hào)內(nèi)有 4 種情況
/* 跟 Promise 對(duì)象 */ Promise.resolve(Promise.resolve(1)) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 跟 thenable 對(duì)象 */ var thenable = { then: function(resolve, reject) { resolve(1) } } Promise.resolve(thenable) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 普通參數(shù) */ Promise.resolve(1) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 不跟參數(shù) */ Promise.resolve() // Promise?{state: "resolved", data: undefined, callbackQueue: Array(0)}Promise.reject()
相較于 Promise.resolve(),Promise.reject() 原封不動(dòng)地返回參數(shù)值
Promise.all(arr)對(duì)于 Promise.all(arr) 來說,在參數(shù)數(shù)組中所有元素都變?yōu)闆Q定態(tài)后,然后才返回新的 promise。
// 以下 demo,請(qǐng)求兩個(gè) url,當(dāng)兩個(gè)異步請(qǐng)求返還結(jié)果后,再請(qǐng)求第三個(gè) url const p1 = request(`http://some.url.1`) const p2 = request(`http://some.url.2`) Promise.all([p1, p2]) .then((datas) => { // 此處 datas 為調(diào)用 p1, p2 后的結(jié)果的數(shù)組 return request(`http://some.url.3?a=${datas[0]}&b=${datas[1]}`) }) .then((data) => { console.log(msg) })Promise.race(arr)
對(duì)于 Promise.race(arr) 來說,只要參數(shù)數(shù)組有一個(gè)元素變?yōu)闆Q定態(tài),便返回新的 promise。
// race 譯為競(jìng)爭,同樣是請(qǐng)求兩個(gè) url,當(dāng)且僅當(dāng)一個(gè)請(qǐng)求返還結(jié)果后,就請(qǐng)求第三個(gè) url const p1 = request(`http://some.url.1`) const p2 = request(`http://some.url.2`) Promise.race([p1, p2]) .then((data) => { // 此處 data 取調(diào)用 p1, p2 后優(yōu)先返回的結(jié)果 return request(`http://some.url.3?value=${data}`) }) .then((data) => { console.log(data) })Promise.wrap(fn) —— 回調(diào)函數(shù)轉(zhuǎn) Promise
通過下面這個(gè)案例,提供回調(diào)函數(shù) Promise 化的思路。
function foo(a, b, cb) { ajax( `http://some.url?a=${a}&b=$`, cb ) } foo(1, 2, function(err, data) { if (err) { console.log(err) } else { console.log(data) } })
如上是一個(gè)傳統(tǒng)回調(diào)函數(shù)使用案例,只要使用 Promise.wrap() 包裹 foo 函數(shù)就對(duì)其完成了 promise 化,使用如下:
const promiseFoo = Promise.wrap(foo) promiseFoo(1, 2) .then((data) => { console.log(data) }) .catch((err) => { console.log(err) })
Promise.wrap 的實(shí)現(xiàn)邏輯也順帶列出來了:
Promise.wrap = function(fn) { return funtion() { const args = [].slice.call(arguments) return new Promise((resolve, reject) => { fn.apply(null, args.concat((err, data) => { if (err) { reject(err) } else { resolve(data) } })) }) } }then/catch/done
這幾個(gè) api 比較簡單,合起來一起帶過
Promise.resolve(1) .then((data) => {console.log(data)}, (err) => {console.log(err)}) // 鏈?zhǔn)秸{(diào)用,可以傳一個(gè)參數(shù)(推薦),也可以傳兩個(gè)參數(shù) .catch((err) => {console.log(err)}) // 捕獲鏈?zhǔn)秸{(diào)用中拋出的錯(cuò)誤 || 捕獲變?yōu)槭B(tài)的值 .done() // 能捕獲前面鏈?zhǔn)秸{(diào)用的錯(cuò)誤(包括 catch 中),可以傳兩個(gè)參數(shù)也可不傳實(shí)踐過程總結(jié) 坑點(diǎn) 1:事件循環(huán)
事件循環(huán):同步隊(duì)列執(zhí)行完后,在指定時(shí)間后再執(zhí)行異步隊(duì)列的內(nèi)容。
之所以要單列事件循環(huán),因?yàn)榇a的執(zhí)行順序與其息息相關(guān),此處用 setTimeout 來模擬事件循環(huán);
下面代碼片段中,① 處執(zhí)行完并不會(huì)馬上執(zhí)行 setTimeout() 中的代碼(③),而是此時(shí)有多少次 then 的調(diào)用,就會(huì)重新進(jìn)入 ② 處多少次后,再進(jìn)入 ③
excuteAsyncCallback(callback, value) { const that = this setTimeout(function() { const res = callback(value) // ③ that.excuteCallback("fulfilled", res) }, 4) } then(onResolved, onRejected) { const promise = new this.constructor() if (this.state !== "PENDING") { const callback = this.state === "fulfilled" ? onResolved : onRejected this.excuteAsyncCallback.call(promise, callback, this.data) // ① } else { this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // ② } return promise }坑點(diǎn) 2:this 的指向問題
this.callbackArr.push() 中的 this 指向的是 ‘上一個(gè)’ promise,所以類 CallbackItem 中,this.promise 存儲(chǔ)的是"下一個(gè)" promise(then 對(duì)象)。
class Promise { ... then(onResolved, onRejected) { const promise = new this.constructor() if (this.state !== "PENDING") { // 第一次進(jìn)入 then,狀態(tài)是 RESOLVED 或者是 REJECTED const callback = this.state === "fulfilled" ? onResolved : onRejected this.excuteAsyncCallback.call(promise, callback, this.data) // 綁定 this 到 promise } else { // 從第二次開始以后,進(jìn)入 then,狀態(tài)是 PENDING this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // 這里的 this 也是指向‘上一個(gè)’ promise } return promise } ... } class CallbackItem { constructor(promise, onResolve, onReject) { this.promise = promise // 相應(yīng)地,這里存儲(chǔ)的 promise 是來自下一個(gè) then 的 this.onResolve = typeof(onResolve) === "function" ? onResolve : (resolve) => {} this.onReject = typeof(onRejected) === "function" ? onRejected : (rejected) => {} } ... }more
實(shí)踐的更多過程可以參考測(cè)試用例。有好的意見歡迎交流。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95850.html
摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個(gè)元素都執(zhí)行一次回調(diào)函數(shù)。方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù)。注意對(duì)于空數(shù)組是不會(huì)執(zhí)行回調(diào)函數(shù)的。 轉(zhuǎn)載請(qǐng)注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關(guān)系。ECMA是標(biāo)準(zhǔn),Jav...
摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個(gè)元素都執(zhí)行一次回調(diào)函數(shù)。方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù)。注意對(duì)于空數(shù)組是不會(huì)執(zhí)行回調(diào)函數(shù)的。 轉(zhuǎn)載請(qǐng)注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關(guān)系。ECMA是標(biāo)準(zhǔn),Jav...
摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...
摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...
摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...
閱讀 1445·2021-10-11 11:12
閱讀 3279·2021-09-30 09:46
閱讀 1663·2021-07-28 00:14
閱讀 3160·2019-08-30 13:49
閱讀 2609·2019-08-29 11:27
閱讀 3302·2019-08-26 11:52
閱讀 628·2019-08-23 18:14
閱讀 3465·2019-08-23 16:27