Promise
相關的一些實現,本身最近也在看ES6
的一些內容,因而打算本身也整理一下,提高一下理解;Promise
的人,若是你沒有了解或使用過Promise
,建議先看一下 阮一峯 ECMAScript6 入門 之Promise。Promise
Promise
是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果;Promise
對象表明一個異步操做,有三種狀態:pending
(進行中)、fulfilled
(已成功)和rejected
(已失敗)。Promise
對象的狀態改變,只有兩種可能:從pending
變爲fulfilled
和從pending
變爲rejected
。Promise
Promise
// Promise構造函數接收一個executor函數,executor函數執行完同步或異步操做後,調用它的兩個參數resolve和reject
const promise = new Promise(function(resolve, reject) {
/*
若是操做成功,調用resolve並傳入value
若是操做失敗,調用reject並傳入reason
*/
})
複製代碼
fulfilled
的回調函數數組rejected
的回調函數數組const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const NewPromise = function(executor) {
const _this = this;
_this.status = PENDING; // 狀態
_this.data = undefined; // 值
_this.onResolvedCallback = []; // fulfilled的回調函數數組
_this.onRejectedCallback = []; // rejected的回調函數數組
// 成功
function resolve(value) { ... }
// 失敗
function reject(reason) { ... }
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
複製代碼
resole
和reject
resole
是成功的調用,須要不狀態修改成fulfilled
,而後當前的值設爲傳入的值,遍歷執行onResolvedCallback
中的回調。// 成功
function resolve(value) {
只有pending狀態才能轉換爲fulfilled / rejected
setTimeout(function() { // 異步執行全部的回調函數
if (_this.status === PENDING) {
_this.status = FULFILLED;
_this.data = value;
_this.onResolvedCallback.forEach(callback => callback(value));
}
});
}
複製代碼
reject
的實現和resolve
相似,只是狀態修改成rejected
及執行onRejectedCallback
。// 失敗
function reject(reason) {
setTimeout(function() { // 異步執行全部的回調函數
if (_this.status === PENDING) {
_this.status = REJECTED;
_this.data = reason;
_this.onRejectedCallback.forEach(callback => callback(reason));
}
});
}
複製代碼
Promise
,你能夠像使用Promise
同樣使用它,但尚未添加其餘的方法。// 測試
const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11)
})
複製代碼
then
方法Promise
對象有一個then
方法,用來註冊在這個Promise
狀態肯定後的回調,then
方法須要寫在原型鏈上(爲何要寫在原型上不清楚的可能須要補一下JavaScript
基礎了)。在Promise/A
標準中,明確規定了then
要返回一個新的對象,因此在咱們的實現中也返回一個新對象。// then掛載到原型上
NewPromise.prototype.then = function(onResolved, onRejected) {
const _this = this;
if ( typeof onResolved !== 'function') {
onResolved = function(value) { return value }
}
if ( typeof onRejected !== 'function') {
onRejected = function(reason) { throw reason }
}
// 公共判斷
const common = function (data, resolve, reject) {
// 考慮到有可能throw,咱們將其包在try/catch塊裏
try {
let value = _this.status === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
// 公共判斷
const pendingCommon = function (data, flag, resolve, reject) {
// 考慮到有可能throw,咱們將其包在try/catch塊裏
try {
let value = flag === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
if (_this.status === PENDING) {
return new NewPromise(function(resolve, reject) {
_this.onResolvedCallback.push((value) => {
pendingCommon(value, FULFILLED, resolve, reject);
})
_this.onRejectedCallback.push((reason) => {
pendingCommon(reason, REJECTED, resolve, reject);
})
})
} else { // resolve / reject
return new NewPromise(function (resolve, reject) {
setTimeout(function () {
common(_this.data, resolve, reject)
})
})
}
}
複製代碼
resolve
方法再次完善rosolve
的值是不是Promise
,若是是Promise
繼續執行.then
方法。// 成功
function resolve(value) {
// value 若是是Promise繼續執行.then
+ if (value instanceof Promise) {
+ return value.then(resolve, reject)
+ }
...
}
複製代碼
catch
方法Promise
的異常錯誤。// catch方法
NewPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
複製代碼
finally
方法finally()
方法用於指定無論Promise
對象最後狀態如何,都會執行的操做。// finally
NewPromise.prototype.finally = function (fun) {
return this.then((value) => {
// f(); return value;
// Promise.resolve會等f()的函數執行完再返回結果
return NewPromise.resolve(fun()).then(() => value);
}, (err) => {
return NewPromise.resolve(fun()).then(() => {
throw err;
});
});
};
複製代碼
resolve
方法Promise
對象,實例的狀態爲fulfilled
。NewPromise.resolve = function(value) {
if (value instanceof Promise) return value;
if (value === null) return null;
// 判斷若是是promise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判斷是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new NewPromise(then.call(value)); // 執行value方法
}
} catch (e) {
return new NewPromise( (resolve, reject) =>{
reject(e);
});
}
}
return new NewPromise( (resolve, reject) =>{
resolve(value);
});
}
複製代碼
reject
方法Promise
對象,實例的狀態爲rejected
。實現和resolve
方法相似,最後return改成reject
。NewPromise.reject = function(reason) {
...
return new NewPromise( (resolve, reject) =>{
reject(reason);
});
}
複製代碼
all
方法Promise.all
方法用於將多個 Promise 實例,包裝成一個新的Promise
實例;方法的參數能夠不是數組,但必須具備Iterator
接口,且返回的每一個成員都是Promise
實例。// all
NewPromise.all = function(promises) {
return new NewPromise(function(resolve, reject) {
const result = []
// 判斷參數屬否是數組
promises = Array.isArray(promises) ? promises : []
const len = promises.length - 1;
promises.forEach((promise, index) => {
promise.then(value => {
result.push(value)
if(index === len) {
resolve(result)
}
}, reject)
})
})
}
複製代碼
race
方法Promise.race()
方法一樣是將多個Promise
實例,包裝成一個新的Promise
實例。Promise.race()
的狀態就跟着改變。那個率先改變的Promise
實例的返回值,就傳遞給Promise.race()
的回調函數。// race
NewPromise.race = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
promises.forEach(promise => {
promise.then(resolve, reject)
})
})
}
複製代碼
deferred
方法// defered
NewPromise.deferred = function() {
const dfd = {}
dfd.promise = new NewPromise(function(resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
複製代碼
allSettled
方法Promise.allSettled()
方法接受一組Promise
實例做爲參數,包裝成一個新的Promise
實例,只有等到全部這些參數實例都返回結果,無論是fulfilled仍是rejected,包裝實例纔會結束。返回一個包含全部結果的數組。NewPromise.allSettled = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
let len = promises.length;
const argslen = len;
if (len === 0) return resolve([]);
let args = Array.prototype.slice.call(promises);
function resolvePromise(index, value) {
if(typeof value === 'object') { // 傳入的是不是object
const then = value.then;
if(typeof then === 'function'){
then.call(value, function(val) {
args[index] = { status: 'fulfilled', value: val};
if(--len === 0) {
resolve(args);
}
}, function(e) {
args[index] = { status: 'rejected', reason: e };
if(--len === 0) {
reject(args);
}
})
}
}
}
for(let i = 0; i < argslen; i++){
resolvePromise(i, args[i]);
}
})
}
複製代碼
// 測試
const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11);
resolve(123);
})
複製代碼
then
測試promise.then(val => {
console.log('val', val)
})
複製代碼
catch
測試const promise = new NewPromise(function(resolve, reject) {
console.log('ss', 11);
reject('errr')
})
promise.catch(err => {
console.log('err', err)
})
複製代碼
finally
測試const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
}).catch(err => {
console.log('err', err)
}).finally(() => {
console.log('finally')
})
複製代碼
resolve
測試const resolved = NewPromise.resolve(1);
resolved.then(val => {
console.log('resolved', val)
})
複製代碼
reject
測試const rejected = NewPromise.reject(-1);
rejected.catch(val => {
console.log('rejected', val)
})
複製代碼
all
測試const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
}).catch(err => {
console.log('err', err)
})
複製代碼
allSettled
測試const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.allSettled([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
})
複製代碼
/*
* @Author: detanx
* @Date: 2020-05-11 17:39:52
* @Last Modified by: detanx
* @Last Modified time: 2020-05-11 17:39:52
*/
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const NewPromise = function(executor) {
const _this = this;
_this.status = PENDING;
_this.data = undefined;
_this.onResolvedCallback = [];
_this.onRejectedCallback = [];
// 成功
function resolve(value) {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
setTimeout(function() { // 異步執行全部的回調函數
if (_this.status === PENDING) {
_this.status = FULFILLED;
_this.data = value;
_this.onResolvedCallback.forEach(callback => callback(value));
}
})
}
// 失敗
function reject(reason) {
setTimeout(function() { // 異步執行全部的回調函數
if (_this.status === PENDING) {
_this.status = REJECTED;
_this.data = reason;
_this.onRejectedCallback.forEach(callback => callback(reason));
}
})
}
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// then
NewPromise.prototype.then = function(onResolved, onRejected) {
const _this = this;
if ( typeof onResolved !== 'function') {
onResolved = function(value) { return value }
}
if ( typeof onRejected !== 'function') {
onRejected = function(reason) { throw reason }
}
// 公共判斷
const common = function (data, resolve, reject) {
// 考慮到有可能throw,咱們將其包在try/catch塊裏
try {
let value = _this.status === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
// 公共判斷
const pendingCommon = function (data, flag, resolve, reject) {
// 考慮到有可能throw,咱們將其包在try/catch塊裏
try {
let value = flag === FULFILLED
? onResolved(data)
: onRejected(data)
if( value instanceof Promise) {
value.then(resolve, reject)
}
resolve(value)
} catch (error) {
reject(error)
}
}
if (_this.status === PENDING) {
return new NewPromise(function(resolve, reject) {
_this.onResolvedCallback.push((value) => {
pendingCommon(value, FULFILLED, resolve, reject);
})
_this.onRejectedCallback.push((reason) => {
pendingCommon(reason, REJECTED, resolve, reject);
})
})
} else { // resolve / reject
return new NewPromise(function (resolve, reject) {
setTimeout(function () {
common(_this.data, resolve, reject)
})
})
}
}
NewPromise.resolve = function(value) {
if (value instanceof Promise) return value;
if (value === null) return null;
// 判斷若是是promise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判斷是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new NewPromise(then.call(value)); // 執行value方法
}
} catch (e) {
return new NewPromise( (resolve, reject) =>{
reject(e);
});
}
}
return new NewPromise( (resolve, reject) =>{
resolve(value);
});
}
NewPromise.reject = function(value) {
if (value instanceof Promise) return value;
if (value === null) return null;
// 判斷若是是promise
if (typeof value === 'object' || typeof value === 'function') {
try {
// 判斷是否有then方法
let then = value.then;
if (typeof then === 'function') {
return new NewPromise(then.call(value)); // 執行value方法
}
} catch (e) {
return new NewPromise( (resolve, reject) =>{
reject(e);
});
}
}
return new NewPromise( (resolve, reject) =>{
reject(value);
});
}
// catch方法
NewPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
// defered
NewPromise.deferred = function() {
const dfd = {}
dfd.promise = new NewPromise(function(resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
// all
NewPromise.all = function(promises) {
return new NewPromise(function(resolve, reject) {
const result = []
promises = Array.isArray(promises) ? promises : []
const len = promises.length - 1;
promises.forEach((promise, index) => {
promise.then(value => {
result.push(value)
if(index === len) {
resolve(result)
}
}, reject)
})
})
}
// race
NewPromise.race = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
promises.forEach(promise => {
promise.then(resolve, reject)
})
})
}
// allSettled
NewPromise.allSettled = function (promises) {
return new NewPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
let len = promises.length;
const argslen = len;
if (len === 0) return resolve([]);
let args = Array.prototype.slice.call(promises);
function resolvePromise(index, value) {
if(typeof value === 'object') {
const then = value.then;
if(typeof then === 'function'){
then.call(value, function(val) {
args[index] = { status: 'fulfilled', value: val};
if(--len === 0) {
resolve(args);
}
}, function(e) {
args[index] = { status: 'rejected', reason: e };
if(--len === 0) {
reject(args);
}
})
}
}
}
for(let i = 0; i < argslen; i++){
resolvePromise(i, args[i]);
}
})
}
// 測試
// const promise = new NewPromise(function(resolve, reject) {
// console.log('ss', 11)
// // resolve(123)
// reject('errr')
// // throw 'ree'
// })
// promise.catch(val => {
// console.log('val', val)
// })
// const promise1 = new NewPromise(function(resolve, reject) {
// console.log('ss', 11)
// resolve(123)
// // reject('errr')
// })
// const rejected = NewPromise.reject(-1);
// rejected.catch(val => {
// console.log('rejected', val)
// })
// console.log('resolved', resolved)
const resolved = NewPromise.resolve(1);
const rejected = NewPromise.reject(-1);
const resolved1 = NewPromise.resolve(17);
const p = NewPromise.all([resolved, resolved1, rejected]);
p.then((result) => {
console.log('result', result)
}).catch(err => {
console.log('err', err)
})
複製代碼
阮一峯 ECMAScript 6 入門
22 道高頻 JavaScript 手寫面試題及答案es6