摘要:以下,請求兩個,當兩個異步請求返還結果后,再請求第三個此處為調用后的結果的數組對于來說,只要參數數組有一個元素變為決定態,便返回新的。
Promise 札記
研究 Promise 的動機大體有以下幾點:
對其 api 的不熟悉以及對實現機制的好奇;
很多庫(比如 fetch)是基于 Promise 封裝的,那么要了解這些庫的前置條件得先熟悉 Promise;
要了解其它更為高級的異步操作得先熟悉 Promise;
基于這些目的,實踐了一個符合 Promise/A+ 規范的 repromise
本札記系列總共三篇文章,作為之前的文章 Node.js 異步異聞錄 的拆分和矯正。
Promise札記
Generator札記
Async札記
Promise/A+ 核心在實現一個符合 Promise/A+ 規范的 promise 之前,先了解下 Promise/A+ 核心,想更全面地了解可以閱讀 Promise/A+規范
Promise 操作只會處在 3 種狀態的一種:未完成態(pending)、完成態(resolved) 和失敗態(rejected);
Promise 的狀態只會出現從未完成態向完成態或失敗態轉化;
Promise 的狀態一旦轉化,將不能被更改;
repromise api 食用手冊 Promise.resolve()Promise.resolve() 括號內有 4 種情況
/* 跟 Promise 對象 */ Promise.resolve(Promise.resolve(1)) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 跟 thenable 對象 */ var thenable = { then: function(resolve, reject) { resolve(1) } } Promise.resolve(thenable) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 普通參數 */ Promise.resolve(1) // Promise?{state: "resolved", data: 1, callbackQueue: Array(0)} /* 不跟參數 */ Promise.resolve() // Promise?{state: "resolved", data: undefined, callbackQueue: Array(0)}Promise.reject()
相較于 Promise.resolve(),Promise.reject() 原封不動地返回參數值
Promise.all(arr)對于 Promise.all(arr) 來說,在參數數組中所有元素都變為決定態后,然后才返回新的 promise。
// 以下 demo,請求兩個 url,當兩個異步請求返還結果后,再請求第三個 url const p1 = request(`http://some.url.1`) const p2 = request(`http://some.url.2`) Promise.all([p1, p2]) .then((datas) => { // 此處 datas 為調用 p1, p2 后的結果的數組 return request(`http://some.url.3?a=${datas[0]}&b=${datas[1]}`) }) .then((data) => { console.log(msg) })Promise.race(arr)
對于 Promise.race(arr) 來說,只要參數數組有一個元素變為決定態,便返回新的 promise。
// race 譯為競爭,同樣是請求兩個 url,當且僅當一個請求返還結果后,就請求第三個 url const p1 = request(`http://some.url.1`) const p2 = request(`http://some.url.2`) Promise.race([p1, p2]) .then((data) => { // 此處 data 取調用 p1, p2 后優先返回的結果 return request(`http://some.url.3?value=${data}`) }) .then((data) => { console.log(data) })Promise.wrap(fn) —— 回調函數轉 Promise
通過下面這個案例,提供回調函數 Promise 化的思路。
function foo(a, b, cb) { ajax( `http://some.url?a=${a}&b=${b}`, cb ) } foo(1, 2, function(err, data) { if (err) { console.log(err) } else { console.log(data) } })
如上是一個傳統回調函數使用案例,只要使用 Promise.wrap() 包裹 foo 函數就對其完成了 promise 化,使用如下:
const promiseFoo = Promise.wrap(foo) promiseFoo(1, 2) .then((data) => { console.log(data) }) .catch((err) => { console.log(err) })
Promise.wrap 的實現邏輯也順帶列出來了:
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
這幾個 api 比較簡單,合起來一起帶過
Promise.resolve(1) .then((data) => {console.log(data)}, (err) => {console.log(err)}) // 鏈式調用,可以傳一個參數(推薦),也可以傳兩個參數 .catch((err) => {console.log(err)}) // 捕獲鏈式調用中拋出的錯誤 || 捕獲變為失敗態的值 .done() // 能捕獲前面鏈式調用的錯誤(包括 catch 中),可以傳兩個參數也可不傳實踐過程總結 坑點 1:事件循環
事件循環:同步隊列執行完后,在指定時間后再執行異步隊列的內容。
之所以要單列事件循環,因為代碼的執行順序與其息息相關,此處用 setTimeout 來模擬事件循環;
下面代碼片段中,① 處執行完并不會馬上執行 setTimeout() 中的代碼(③),而是此時有多少次 then 的調用,就會重新進入 ② 處多少次后,再進入 ③
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 }坑點 2:this 的指向問題
this.callbackArr.push() 中的 this 指向的是 ‘上一個’ promise,所以類 CallbackItem 中,this.promise 存儲的是"下一個" promise(then 對象)。
class Promise { ... then(onResolved, onRejected) { const promise = new this.constructor() if (this.state !== "PENDING") { // 第一次進入 then,狀態是 RESOLVED 或者是 REJECTED const callback = this.state === "fulfilled" ? onResolved : onRejected this.excuteAsyncCallback.call(promise, callback, this.data) // 綁定 this 到 promise } else { // 從第二次開始以后,進入 then,狀態是 PENDING this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // 這里的 this 也是指向‘上一個’ promise } return promise } ... } class CallbackItem { constructor(promise, onResolve, onReject) { this.promise = promise // 相應地,這里存儲的 promise 是來自下一個 then 的 this.onResolve = typeof(onResolve) === "function" ? onResolve : (resolve) => {} this.onReject = typeof(onRejected) === "function" ? onRejected : (rejected) => {} } ... }more
實踐的更多過程可以參考測試用例。有好的意見歡迎交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95850.html
摘要:在年正式發布了,簡稱,又稱為。再次簡寫循環迭代數組每個元素都執行一次回調函數。方法用于調用數組的每個元素,并將元素傳遞給回調函數。注意對于空數組是不會執行回調函數的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
摘要:在年正式發布了,簡稱,又稱為。再次簡寫循環迭代數組每個元素都執行一次回調函數。方法用于調用數組的每個元素,并將元素傳遞給回調函數。注意對于空數組是不會執行回調函數的。 轉載請注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關系。ECMA是標準,Jav...
閱讀 1411·2021-10-11 11:12
閱讀 3244·2021-09-30 09:46
閱讀 1633·2021-07-28 00:14
閱讀 3132·2019-08-30 13:49
閱讀 2581·2019-08-29 11:27
閱讀 3211·2019-08-26 11:52
閱讀 596·2019-08-23 18:14
閱讀 3435·2019-08-23 16:27