首先看一段代碼
setTimeout(function(){
console.log(1)
}, 3000)
setTimeout(function(){
console.log(2)
}, 2000)
setTimeout(function(){
console.log(3)
}, 1000)
此時會輸出 3 2 1, 原本我們是想輸出 1 2 3 的,但是在異步的情況下,我們沒辦法改變異步的順序,這是我們可以用回調(diào)函數(shù)來控制順序,但是又有一個扎心的問題 -- 回調(diào)地獄
這時我們的promise就出場啦,代碼改為:
new Promise(function(resolve, reject){
setTimeout(function(){
console.log(1)
resolve()
}, 3000)
})
.then(function(data){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log(2)
resolve()
}, 2000)
})
})
.then(function(data){
return new Promise(function(resolve, reject){
setTimeout(function () {
console.log(3)
resolve()
}, 1000)
})
})
在瀏覽器預覽: 隔3秒輸出1,再隔2秒輸出2,再隔1秒輸出3
這樣就符合我們預期的想法了
來看看代碼, 先new一下 證明我們第一步應該創(chuàng)建構造函數(shù) Promise(callback) ,接著后面有 then(fn) ,于是我們可以斷定 Promise.prototype.then = fn() {} , 于是根據(jù)執(zhí)行情況,我們可以把執(zhí)行順序捋一捋
Promise -> 接收的函數(shù)立即執(zhí)行 -> then(fn) (保存參數(shù)函數(shù)) -> resolve() -> then內(nèi)部的回調(diào)函數(shù)
我們再來看看,promomise里面有resolve和reject 那就可以看出promise有兩種狀態(tài),但這兩種只是判斷成功或者失敗,所以我們還需要一個初始狀態(tài)。 故: pending / fulfilled / rejected 這三種狀態(tài)
接著看代碼,看著注釋,就可以大致明白啦
var PENDING = 'PENDING';
var FULFILLED = 'FULFILLED';
var REJECTED = 'REJECTED';
// 1: 構造函數(shù)Promise
function Promise(fn) {
// 2. 構造函數(shù)內(nèi)初始 狀態(tài)Pending 和 value
this.status = PENDING; // 狀態(tài)是待發(fā)狀態(tài)
this.value = null; // 初始值
this.deffered = []; // 下一個 要執(zhí)行的Promise是誰,子promise
// 3.構造函數(shù)內(nèi)調(diào)用函數(shù)(apply參數(shù)是數(shù)組,call參數(shù)是一個個,調(diào)用函數(shù)改變this指向, bind不會立即調(diào)用,只是改變this)
fn.call(this, this.resolve.bind(this), this.reject.bind(this));
}
// 4. 結束回調(diào)函數(shù), 執(zhí)行then Promise.prototype.then 是函數(shù)
// 5. then函數(shù)內(nèi)不需要保存起成果或者失敗的函數(shù)
Promise.prototype = {
constructor: Promise, // 改變回來原型鏈
then: function(onfulfilled, onrejected) {
// 保存該函數(shù)
var obj = {
onfulfilled: onfulfilled,
onrejected: onrejected
}
// 新來一個Promise對象,讓其存儲這些
// 并且能根據(jù)不同的Promise去then
obj.promise = new this.constructor(function(){});
// 保存起接下來的promise
// console.log(this)
// console.log(obj.promise)
// 建立上一個與下一個primise之間的關系
if(this.status === PENDING) {
this.deffered.push(obj);
}
// 保證不報錯, 未來不能return自己 需要換人
return obj.promise; // 下一個then的哥們
},
// 定義成功和失敗的回調(diào)函數(shù), 改變狀態(tài), 記錄數(shù)據(jù)結果, 執(zhí)行后續(xù)的行為
resolve: function(data) {
this.status = FULFILLED;
this.value = data;
// 執(zhí)行后續(xù)的行為
this.done();
},
reject: function(err) {
this.status = REJECTED;
this.value = err;
// 執(zhí)行后續(xù)的行為
this.done();
},
// 執(zhí)行后續(xù)的行為
done: function() {
// 讓這些this.deffered(子promise得到執(zhí)行)
this.deffered.forEach(task => this.handler(task));
},
handler: function(task) {
// 判斷當前執(zhí)行的狀態(tài)是怎樣, 調(diào)用對應的函數(shù)
var status = this.status;
var value = this.value;
var p;
switch(status) {
case FULFILLED:
p = task.onfulfilled(value);
break;
case REJECTED:
p = task.onrejected(value);
break;
}
// 如果 p是一個promise的話,我們需要讓他們繼續(xù)執(zhí)行
// 把后續(xù)(task.promise)的deffer 交給這個p
if(p && p.constructor === Promise) {
// 是一個promise
// 把下一個作為then鏈接的deffer 移交給deffered
p.deffered = task.promise.deffered;
}
},
}
我們按照思路先寫一個demo
var PENDING = 'PENDING'
var FULFILLED = 'FULFILLED'
var REJECTED = 'REJECTED'
// 1 構造函數(shù)Promise
function Promise(fn) {
this.status = PENDING; // 初始化狀態(tài)
// 2 構造函數(shù)內(nèi)調(diào)用函數(shù)
this.value = null; // 初始值
this.deffered = []; // 下一個執(zhí)行的Promise執(zhí)行是誰
// 3 構造函數(shù)內(nèi)初始 狀態(tài)Pending 和 value
fn()
}
// 4 結束回調(diào)函數(shù)后執(zhí)行then -> Promise.prototype.then 是函數(shù)
// 5 then函數(shù)內(nèi)部需要保存起成功或者失敗的函數(shù)
Promise.protope = {
// 定義成功和失敗的回調(diào)函數(shù),改變狀態(tài),記錄數(shù)據(jù)結果, 執(zhí)行后續(xù)的行為
resolve: function(data) {
this.status = FULFILLED;
this.value = dat
},
constructor: Promise, // 改變回來原型鏈
then: function() {
}
}