Promise 是 JavaScript 中用於異步操做很是重要的一個構造函數,那麼它是怎麼實現的呢?promise
下面用原生 JavaScript 來實現一個簡易版的 Promise,用來實現如下代碼。異步
function Promise(???){
???
return ???
}
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise.then(
val => {
console.log('第一次成功', val);// 輸出 第一次成功 hello
},
val => {
console.log('第一次失敗', val);
}
);
複製代碼
用過 Promise 的朋友都知道,Promise 要接受一個函數 fn 並調用它,Promise 還應該有一個表示狀態( pending, resolved, rejected )的屬性值 status,一個 value 存儲 then 回調時傳的值,還有一個 then 方法。其餘方法暫時不考慮了。函數
function Promise(fn) {
//初始 status 爲 peding
let status = 'pending';
//存儲 then 回調值
let value;
//存儲 then 的兩個參數
let onResolvedCallback;
let onRejectedCallback;
//設置 fn 的 resolve 函數
function resolve(data) {
//將 status 變成 fulfilled
status = 'fulfilled';
//存儲回調函數的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//設置 fn 的 reject 函數
function reject(data) {
//將 status 變成 rejected
status = 'rejected';
//存儲回調函數的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//設置 resolve 或 reject 時的執行體
function toDoThen(onFulfill, onReject) {
//若是是 fulfilled 狀態,表示要執行 then 的第一個函數
if (status === 'fulfilled') {
onFulfill && onFulfill(value);
status = 'pending';
//若是是 rejected 狀態,表示要執行 then 的第二個函數
} else if (status === 'rejected') {
onReject && onReject(value);
status = 'pending';
//若是狀態仍是 peding,表示 resolve 或 reject 還沒執行,那就先把 then 的兩個函數存起來,等 resolve 或 reject 的時候再調用
} else {
onResolvedCallback = onFulfill;
onRejectedCallback = onReject;
}
}
//將 then 獲得的函數傳給 toDoThen
this.then = function(onFulfill, onReject) {
toDoThen(onFulfill, onReject);
};
//執行 fn
fn(resolve, reject);
return this;
}
複製代碼
測試一波測試
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise.then(
val => {
console.log('第一次成功', val);
},
val => {
console.log('第一次失敗', val);
}
);
複製代碼
執行時會打印出 '第一次成功' 和 'hello'ui
若是想要實現如下的代碼,讓第二個 then 的執行函數是根據第一個 then 返回值的布爾值來肯定的。this
promise
.then(
val => {
console.log('第一次成功', val);
return 'world';
},
val => {
console.log('第一次失敗', val);
return false;
}
)
.then(
val => {
console.log('第二次成功', val);
},
val => {
console.log('第二次失敗', val);
}
);
複製代碼
這裏若是要實現鏈式 then,那麼 then 返回的也必須是一個 Promise 對象,並根據第一個 then 的返回值來肯定下一個 then 調用哪一個函數。spa
function Promise(fn) {
//初始 status 爲 peding
let status = 'pending';
//存儲 then 回調值
let value;
//存儲 then 的兩個參數
let onResolvedCallback;
let onRejectedCallback;
//設置 fn 的 resolve 函數
function resolve(data) {
//將 status 變成 fulfilled
status = 'fulfilled';
//存儲回調函數的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//設置 fn 的 reject 函數
function reject(data) {
//將 status 變成 rejected
status = 'rejected';
//存儲回調函數的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//設置 resolve 或 reject 時的執行體
function toDoThen(onFulfill, onReject) {
//若是是 fulfilled 狀態,表示要執行 then 的第一個函數
if (status === 'fulfilled') {
onFulfill && onFulfill(value);
status = 'pending';
//若是是 rejected 狀態,表示要執行 then 的第二個函數
} else if (status === 'rejected') {
onReject && onReject(value);
status = 'pending';
//若是狀態仍是 peding,表示 resolve 或 reject 還沒執行,那就先把 then 的兩個函數存起來,等 resolve 或 reject 的時候再調用
} else {
onResolvedCallback = onFulfill;
onRejectedCallback = onReject;
}
}
this.then = function(onFulfill, onReject) {
return new Promise((resolve, reject) => {
toDoThen(
val => {
let result = onFulfill(val);
//根據第一個 then 的返回值來肯定下一個 then 的調用
result ? resolve(result) : reject(result);
},
err => {
let result = onReject(err);
//根據第一個 then 的返回值來肯定下一個 then 的調用
result ? resolve(result) : reject(result);
}
);
});
};
//執行 fn
fn(resolve, reject);
return this;
}
複製代碼
來執行一下code
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise
.then(
val => {
console.log('第一次成功', val);
return 'world';
},
val => {
console.log('第一次失敗', val);
return false;
}
)
.then(
val => {
console.log('第二次成功', val);
},
val => {
console.log('第二次失敗', val);
}
)
複製代碼
程序會依次輸出 '第一次成功' 'hello' 和 '第二次成功' 'world' 。對象
到此就實現了一個簡易版的 Promise,固然,還有不少地方細節沒有考慮到,實現地很是粗糙。ip