1、基礎框架
promiser的建構函式接收一個引數是executor函式,並且傳入兩個引數:resolve,reject。分別是非同步操作成功的回撥函式和非同步操作失敗後的回撥函式。
promise有三個狀態 等待(pending) 成功態 (fulfilled) 失敗態(rejected)
預設情況是 pending -> fulfilled
pending -> rejected
fulfilled不能和rejected相互轉化複製程式碼
下面來看一下程式碼具體的實現:
function Promise(executor){
let self = this;
self.status = 'pending'
self.value = undefined;
self.reason = undefined;
self.onResolvedCallbacks = []; //非同步時,存放成功的回撥函式
self.onRejectedCallbacks = []; //非同步時,存放失敗的回撥函式
// 只有狀態是pending 參能進行狀態的轉化
function resolve(value) {
if(self.status === 'pending'){
self.value = value;
self.status = 'fulfilled';
self.onResolvedCallbacks.forEach(function (fn) {
fn(); //成功時呼叫迴圈呼叫成功的函式執行
});
}
}
function reject(reason) {
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(function (fn) {
fn();//失敗時呼叫迴圈呼叫失敗的函式執行
})
}
}
try{
executor(resolve, reject); // 如果執行這個executor執行時候丟擲異常 應該走下一個then的失敗
}catch(e){
reject(e);// 出錯了
}
}複製程式碼
2、then方法
每個promise例項上都有一個then方法,then方法接受兩個引數,onFulfilled和onRejected。判斷狀態成功的時候(fulfilled),呼叫onFulfilled函式,把成功的值傳回。判斷狀態失敗的時候(rejected),呼叫onRejected失敗函式,把失敗的值傳回。
如果狀態是pending,代表是非同步執行,把onFulfilled和onRejected函式存起來,executor裡resolve函式和reject函式執行的時候再呼叫。
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
if (self.status === 'fulfilled'){
onFulfilled(self.value);
}
if (self.status === 'rejected'){
onRejected(self.reason);
}
if( self.status === 'pending'){
//非同步的實現
self.onResolvedCallbacks.push(function () {
onFulfilled(self.value);
});
self.onRejectedCallbacks.push(function () {
onRejected(self.reason);
})
}}
複製程式碼
3、then方法鏈式呼叫
- promise每次呼叫then後,返回一個新的promise(then方法成功後 返回的是一個新的promise,這個返回的promise會被執行,如果返回的promise是成功的,會把這個結果傳遞到外層的下一個then中)
- 如果返回的是promise 用promise的成功或者失敗 執行下一個then
- 如果返回的是一個普通值 會走外層下一個then的成功
- 如果執行的時候 丟擲異常就會走到下一個次then中的失敗
- then中可以不傳遞引數,如果不傳遞 會透到下一個then中
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled:function (data) { return data }
onRejected = typeof onRejected === 'function' ? onRejected:function (err) { throw err; }
let self = this;
let promise2; //promise2就是我們每次呼叫then後返回的新的promise
promise2 = new Promise(function (resolve,reject) {
if (self.status === 'fulfilled') {
// 這個返回值是成功函式的執行結果
setTimeout(() => {
try{
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
}
if (self.status === 'rejected') {
setTimeout(() => {
try{
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e)
}
},0)
}
if (self.status === 'pending') {
// 預設當前 new Promise executor中是有非同步的
self.onResolvedCallbacks.push(function () {
setTimeout(() => {
try{
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e)
}
}, 0);
});
self.onRejectedCallbacks.push(function () {
setTimeout(() => {
try{
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
})
}
});
return promise2;
}複製程式碼
4、鏈式呼叫的核心方法
核心方法,處理成功或者失敗執行的返回值和promise2的關係
function resolvePromise(promise2,x,resolve,reject) {
// 這個處理函式 需要處理的邏輯韓式很複雜的
// 有可能這個x 是一個promise 但是這個promise並不是我自己的
if(promise2 === x){
return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
}
// 不單單需要考慮自己 還要考慮 有可能是別人的promise let called;
// 文件要求 一旦成功了 不能呼叫失敗
if((x!=null&&typeof x=== 'object') || typeof x === 'function'){
// 這樣只能說 x 可能是一個promise
try{
// x = {then:function(){}}
let then = x.then; // 取then方法
if(typeof then === 'function'){
then.call(x,function (y) {
// resolve(new Promise)
if(!called){called = true;} else{ return;}
resolvePromise(x,y,resolve,reject); // 遞迴檢查promise
},function (r) {
if (!called) { called = true; } else { return; }
reject(r);
});
}else{ // then方法不存在
resolve(x); // 普通值
}
}catch(e){ // 如果取then方法出錯了,就走失敗
if (!called) { called = true; } else { return; }
reject(e);
}
}else{
resolve(x);
}
}複製程式碼
5、catch方法的實現
catch方法其實就是then方法,直接呼叫then方法,成功傳null,失敗把引數傳進去就ok了。
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}複製程式碼
6、finally方法
無論成功還是失敗,都要執行回撥函式,並且把成功或者失敗的值向下傳遞。
Promise.prototype.finally = function (cb) {
return this.then(function (data) {
cb();
return data;
}, function (err) {
cb();
throw err;
});
}複製程式碼
7、reject方法實現
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
})
}複製程式碼
8、resolve方法實現
Promise.resolve = function (value) {
return new Promise(function (resolve, reject) {
resolve(value);
})
}複製程式碼
9、all方法實現
Promise提供了一個 併發的方法 Promise.all 實現併發執行promise.all方法返回的結果是一個promise
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
let arr = []; // 處理資料的方法
let i = 0;
function processData(index, data) {
arr[index] = data; //陣列的索引和長度的關係
if (++i === promises.length) {
// 當陣列的長度 和promise的個數相等時 說明所有的promise都執行完成了
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
if (typeof promise.then == 'function') {
promise.then(function (data) {
processData(i, data); // 把索引和資料 對應起來 方便使用
}, reject)
} else {
processData(i, promise);
}
}
});
}複製程式碼
10、race方法實現
Promise.race傳一個陣列過去,只返回一個結果,哪個快返回哪個。
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
if (typeof promise.then == 'function') {
promise.then(resolve, reject)
} else {
resolve(promise);
}
}
})
}複製程式碼