理解Promise 實現原理
阿新 • • 發佈:2019-02-18
實現基本呼叫
/**
* @desc 自定義promiseL類,模擬實現promise物件
* @param {function} excutor 使用者在初始化Promise物件時傳入的函式
*/
function PromiseL (excutor) {
let self = this
self.status = 'padding' //預設等待狀態
self.value = undefined //狀態成功時的value
self.reason = undefined //狀態為失敗時的error 資訊
//因為是非同步呼叫 所以需要把callback快取起來
self.resolvedCallBackArr = [] //成功的回撥函式
self.rejectedCallBackArr = [] //失敗的回撥函式
/**
* @desc 使用者觸發成功的時候的回到
* @param {all} value 使用者傳入的引數 未知型別
*
*/
function resolve (value) {
//如果函式執行成功,則修改狀態為成功,
if (self.status == 'padding') {
self.value = value
self.status = 'resolved'
//遍歷呼叫回撥函式
self.resolvedCallBackArr.forEach(callback => callback(self.value))
}
}
/**
* @desc 使用者觸發rejcet時呼叫的函式
* @param {[type]} reason 錯誤資訊 未知
* @return {[type]} [description]
*/
function reject (reason) {
//如果狀態失敗 更改狀態和賦值
if (self.status == 'padding') {
self.reason = reason
self.status = 'rejected'
self.rejectedCallBackArr.forEach(callback => callback(self.reason))
}
}
//只要有錯誤 就走tra catch
//使用者第一次傳入的函式同步執行
try {
excutor(resolve, reject)
} catch (e) {
reject(e)
}
// console.log(excutor)
}
/**
* @desc 在例項上擴充套件then方法
* @param {function} onFulfiled 使用者傳入的成功會調函式
* @param {function} onRejected 使用者傳入的失敗回撥函式
* 方法思路:
* 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入
* 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入
* 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫
* @return {[type]} [description]
*/
PromiseL.prototype.then = function (onFulfiled, onRejected) {
let self = this
//根據狀態呼叫函式
if (self.status == 'resolved') {
onFulfiled(this.value)
}
if (self.status == 'rejected') {
onRejected(self.reason)
}
//如果是非同步 先將回調函式快取
if (self.status == 'padding') {
self.resolvedCallBackArr.push(onFulfiled)
self.rejectedCallBackArr.push(onRejected)
}
}
實現錯誤處理,返回一個 PromiseL
物件例項
捕捉錯誤處理不是和理解,寫出來也感覺不對,暫時先擱置,後期考證
/**
* @desc 自定義promiseL類,模擬實現promise物件
* @param {function} excutor 使用者在初始化Promise物件時傳入的函式
*/
function PromiseL (excutor) {
let self = this
self.status = 'padding' //預設等待狀態
self.value = undefined
self.reason = undefined
//因為是非同步呼叫 所以需要把callback快取起來
self.resolvedCallBackArr = [] //成功的回撥函式
self.rejectedCallBackArr = [] //失敗的回撥函式
/**
* @desc 使用者觸發成功的時候的回到
* @param {all} value 使用者傳入的引數 未知型別
*
*/
function resolve (value) {
//如果函式執行成功,則修改狀態為成功,
if (self.status == 'padding') {
self.value = value
self.status = 'resolved'
//遍歷呼叫回撥函式
self.resolvedCallBackArr.forEach(callback => callback(self.value))
}
}
/**
* @desc 使用者觸發rejcet時呼叫的函式
* @param {[type]} reason 錯誤資訊 未知
* @return {[type]} [description]
*/
function reject (reason) {
//如果狀態失敗 更改狀態和賦值
if (self.status == 'padding') {
self.reason = reason
self.status = 'rejected'
self.rejectedCallBackArr.forEach(callback => callback(self.reason))
}
}
//只要有錯誤 就走tra catch
try {
excutor(resolve, reject)
} catch (e) {
reject(e)
}
// console.log(excutor)
}
/**
* @desc 在例項上擴充套件then方法
* @param {function} onFulfiled 使用者傳入的成功會調函式
* @param {function} onRejected 使用者傳入的失敗回撥函式
* 方法思路:
* 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入
* 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入
* 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫
* 4.實現功能,返回一個PromiseL的例項
* @return {undefined}
*/
PromiseL.prototype.then = function (onFulfiled, onRejected) {
let self = this
//用來儲存返回的PromiseL例項
let promise2
//根據狀態呼叫函式
if (self.status == 'resolved') {
// onFulfiled(this.value)
return promise2 = new PromiseL((resolve, reject) => {
let x = onFulfiled(this.value)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
}
if (self.status == 'rejected') {
return promise2 = new PromiseL((resolve, reject) => {
let x = onRejected(self.reason)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
}
//如果是非同步 先將回調函式快取
if (self.status == 'padding') {
//如果狀態時padding 分別在程式池儲存reolve和reject的函式 等使用者觸發的時候呼叫
return promise2 = new PromiseL((resolve, reject) => {
self.resolvedCallBackArr.push(() => {
let x = onFulfiled(self.value)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
self.rejectedCallBackArr.push(() => {
let x = onRejected(self.reason)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
})
}
}
/**
* @desc 當函式有報錯 最後捕捉錯誤
* @param {Function} fn 方法呼叫時的回撥函式
* @return {object} return 一個promiseL的例項
*/
PromiseL.prototype.catch = function (fn) {
// console.log(fn)
return this.then(null,fn)
}
實現 Promise.all
方法
/**
* @desc 自定義promiseL類,模擬實現promise物件
* @param {function} excutor 使用者在初始化Promise物件時傳入的函式
*/
function PromiseL (excutor) {
let self = this
self.status = 'padding' //預設等待狀態
self.value = undefined
self.reason = undefined
//因為是非同步呼叫 所以需要把callback快取起來
self.resolvedCallBackArr = [] //成功的回撥函式
self.rejectedCallBackArr = [] //失敗的回撥函式
/**
* @desc 使用者觸發成功的時候的回到
* @param {all} value 使用者傳入的引數 未知型別
*
*/
function resolve (value) {
//如果函式執行成功,則修改狀態為成功,
if (self.status == 'padding') {
self.value = value
self.status = 'resolved'
//遍歷呼叫回撥函式
self.resolvedCallBackArr.forEach(callback => callback(self.value))
}
}
/**
* @desc 使用者觸發rejcet時呼叫的函式
* @param {[type]} reason 錯誤資訊 未知
* @return {[type]} [description]
*/
function reject (reason) {
//如果狀態失敗 更改狀態和賦值
if (self.status == 'padding') {
self.reason = reason
self.status = 'rejected'
self.rejectedCallBackArr.forEach(callback => callback(self.reason))
}
}
//只要有錯誤 就走tra catch
try {
excutor(resolve, reject)
} catch (e) {
reject(e)
}
// console.log(excutor)
}
/**
* @desc 在例項上擴充套件then方法
* @param {function} onFulfiled 使用者傳入的成功會調函式
* @param {function} onRejected 使用者傳入的失敗回撥函式
* 方法思路:
* 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入
* 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入
* 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫
* 4.實現功能,返回一個PromiseL的例項
* @return {undefined}
*/
PromiseL.prototype.then = function (onFulfiled, onRejected) {
//進行引數為空的處理
onFulfiled = typeof onFulfiled == 'function' ? onFulfiled : data => data
onRejected = typeof onRejected == 'function' ? onRejected : err => err
let self = this
let promise2
//根據狀態呼叫函式 resolved 成功態
if (self.status == 'resolved') {
// onFulfiled(this.value)
return promise2 = new PromiseL((resolve, reject) => {
// 錯誤處理 如果有錯誤 直接進入then的reject狀態
try {
let x = onFulfiled(this.value)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (e) {
reject(e)
}
})
}
//根據狀態呼叫函式 rejected 失敗態
if (self.status == 'rejected') {
return promise2 = new PromiseL((resolve, reject) => {
// 錯誤處理 如果有錯誤 直接進入then的reject狀態
try {
let x = onRejected(self.reason)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (e) {
reject(e)
}
})
}
//如果是非同步 先將回調函式快取
if (self.status == 'padding') {
//如果狀態時padding 分別在程式池儲存reolve和reject的函式 等使用者觸發的時候呼叫
return promise2 = new PromiseL((resolve, reject) => {
self.resolvedCallBackArr.push(() => {
let x = onFulfiled(self.value)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
self.rejectedCallBackArr.push(() => {
let x = onRejected(self.reason)
//判斷 返回的是promise物件或者是值分別處理
if (x instanceof PromiseL) {
x.then(resolve, reject)
} else {
resolve(x)
}
})
})
}
}
/**
* @desc 當函式有報錯 最後捕捉錯誤
* @param {Function} fn 方法呼叫時的回撥函式
* @return {object} return 一個promiseL的例項
*/
PromiseL.prototype.catch = function (fn) {
// console.log(fn)
return this.then(null,fn)
}
/**
* @desc 傳入多個promise物件
* @param {array} promiseLs 陣列內部為多個Promise例項物件
* @return {Promise} 返回一個PromiseL物件例項,通過then拿到最後的結果
*/
PromiseL.all = function (promiseLs) {
return new PromiseL(function (resolve, reject) {
let result = [] //最終的結果
let i = 0 //當前完成的數量
/**
* @desc 當子promise執行成功的回撥函式
* @param {number} index 當前執行的是那一個promise物件
* @return {[type]} [description]
*/
let resolved = function (index) {
return function (data) {
result[index] = data
i++
if (i == promiseLs.length) {
// 所有的promises都執行完畢
resolve(result)
}
}
}
//遍歷所有的物件,呼叫他們的then方法進行處理
for (let j = 0, len = promiseLs.length; j < len; j++) {
promiseLs[j].then(resolved(j), err => {
reject(err)
})
}
})
}