David Yu Blog

Promise 源碼分析

Word count: 1.2kReading time: 6 min
2023/04/25

源碼網址:

https://github.com/YvetteLau/Blog/issues/2

Promise建構子函數

Property

status

Promise的狀態,初始為'pending'

非同步操作成功後為'fulfilled',失敗為'rejected'

resolve

成功後調用的函數

接收一個參數value,

status改為'fulfilled'

reject

失敗後調用的函數

接收一個參數value,定義為Promise的property

status改為'rejected'

onFulfilled

為一陣列,元素是函數

放進等待執行的回調函數(成功)

onRejected

為一陣列,元素是函數

放進等待執行的回調函數(失敗)

Promise.prototype.then定義

接收兩個參數,皆為函數,一個成功時的回調(onFulfilled),一個失敗時的回調(onRejected)

返回一個Promise(範例變數叫promise2)

Promise的非同步操作是,先判定status的狀態

  1. status === FULFILLED

    呼叫成功時的回調函數,引入value當參數,return value賦值給x

    然後執行resolvePromise(promise2, x, resolve, reject)

  2. status ===``REJECTED

    呼叫成功時的回調函數,引入reason當參數,return reason賦值給x

    然後執行resolvePromise(promise2, x, resolve, reject)

  3. status === PENDING

    propertyonFulfilled陣列push進一個非同步操作

    為上面第一點內容

    propertyonRejected陣列push進一個非同步操作

    為上面第二點內容

🔎 註一

程式碼剛開始執行時,由於非同步函數還沒開始,Promise狀態是pending,所以一定都是先跑到3,想不太到跑到1、2的情況

resolvePromise 定義

如同函數名,旨在處理成功時的回調(onFulfilled)所回傳的Promise

resolvePromise(promise2, x, resolve, reject)

接收四個參數,分別為

  1. then()返回的Promise
  2. 成功or失敗回調函數的回傳值
  3. 1的Promise resolve
  4. 1的Promise reject

先判斷promise2 === x

為真的話,執行reject(new TypeError('Chaining cycle'))

後面之後再補看

先引用來源的說明

簡單來說要處理Promise chain的產生

Untitled

模擬執行順序測試

測試1

Untitled

a.then是同步的,在非同步操作之前,過1000ms後,123出現

測試2

在then定義裡面,在實現、拒絕、擱置三種情況的區塊裡面,加入console.log,看看程式碼執行時怎麼跑的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Prom(executor) {
let self = this;
self.status = PENDING;
self.onFulfilled = [];//成功的回调
self.onRejected = []; //失败的回调
//PromiseA+ 2.1
function resolve(value) {
if (self.status === PENDING) {
self.status = FULFILLED;
self.value = value;
self.onFulfilled.forEach(fn => fn());//PromiseA+ 2.2.6.1
}
}

function reject(reason) {
if (self.status === PENDING) {
self.status = REJECTED;
self.reason = reason;
self.onRejected.forEach(fn => fn());//PromiseA+ 2.2.6.2
}
}

try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}

Prom.prototype.then = function (onFulfilled, onRejected) {
//PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
let self = this;
//PromiseA+ 2.2.7
let promise2 = new Prom((resolve, reject) => {
if (self.status === FULFILLED) {
//PromiseA+ 2.2.2
//PromiseA+ 2.2.4 --- setTimeout
console.log('then裡面 FULFILLED')
setTimeout(() => {
try {
//PromiseA+ 2.2.7.1
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
//PromiseA+ 2.2.7.2
reject(e);
}
});
} else if (self.status === REJECTED) {
console.log('then裡面 REJECTED')
//PromiseA+ 2.2.3
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
} else if (self.status === PENDING) {
console.log('then裡面 PENDING')
self.onFulfilled.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
self.onRejected.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
return promise2;
}

function resolvePromise(promise2, x, resolve, reject) {
let self = this;
//PromiseA+ 2.3.1
if (promise2 === x) {
reject(new TypeError('Chaining cycle'));
}
if (x && typeof x === 'object' || typeof x === 'function') {
let used; //PromiseA+2.3.3.3.3 只能调用一次
try {
let then = x.then;
if (typeof then === 'function') {
//PromiseA+2.3.3
then.call(x, (y) => {
//PromiseA+2.3.3.1
if (used) return;
used = true;
resolvePromise(promise2, y, resolve, reject);
}, (r) => {
//PromiseA+2.3.3.2
if (used) return;
used = true;
reject(r);
});

}else{
//PromiseA+2.3.3.4
if (used) return;
used = true;
resolve(x);
}
} catch (e) {
//PromiseA+ 2.3.3.2
if (used) return;
used = true;
reject(e);
}
} else {
//PromiseA+ 2.3.3.4
resolve(x);
}
}

let P1 = new Prom((a, b) => {
setTimeout(() => {
a('123')
}, 1000)
})

P1.then((value) => {
console.log(value)
return '安安' // 此then會返回已實現的Promise
})
.then((value) => {
console.log(value)
})

以下為output

1
2
3
4
then裡面 PENDING    <----同步階段
then裡面 PENDING <----同步階段
123 <----非同步階段
安安 <----非同步階段

此為註一的測試,目前想知道甚麼情況會跑到FULFILLED和REJECTED區塊

改成這樣的話

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let P1 = new Prom((a, b) => {
setTimeout(() => {
a('123')
}, 1000)
})

P1.then((value) => {
console.log(value)
let P2 = new Prom((a, b) => {
setTimeout(() => {
a('465')
}, 1000)
})
return P2
})
.then((value) => {
console.log(value)
})

第一個then改成回傳Promise

output:

1
2
3
4
5
then裡面 PENDING
then裡面 PENDING
123
then裡面 PENDING
465
CATALOG
  1. 1. Promise建構子函數
    1. 1.1. Property
  2. 2. Promise.prototype.then定義
  3. 3. resolvePromise 定義
  4. 4. 模擬執行順序測試
    1. 4.1. 測試1
    2. 4.2. 測試2