-
Notifications
You must be signed in to change notification settings - Fork 0
/
myPromise.js
177 lines (167 loc) · 5.7 KB
/
myPromise.js
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// 等待
const PENDING = 'pending'
// 成功
const FULFILLED = 'fulfilled'
// 失败
const REJECTED = 'rejected'
/**
* 传入值否为函数
* @param {*} value 传入value
* @returns boolean
*/
const isFunction = value => typeof value === 'function'
/**
* 传入值类型是否为对象
* @param {*} value 传入值
* @returns boolean
*/
const isObject = value => Object.prototype.toString.call(value) === '[object Object]'
class MyPromise {
/**
* 初始化函数
* @param { Function } executor 执行函数
*/
constructor(executor) {
// 保存异步操作执行结果
this.result = null
// 记录当前Promise状态
this.state = PENDING
// 用于记录then函数的参数信息
this.callbacks = []
// 用于记录constructor的参数执行状态
let isExecuted = false
/**
* 用于限制函数执行次数
* @param {Function} fn 需要限制的函数
* @returns 若isExecuted为true则函数不会执行
*/
const executedHandler = fn => result => {
if (isExecuted) return
isExecuted = true
isFunction(fn) && fn(result)
}
/**
* 通过传递状态生成onFulfilled或者onRejected函数
* @param {*} state 需要生成的函数其状态
* @returns onFulfilled | onRejected
*/
const resultHandler = state => result => {
// 若当前状态已经被修改则不可修改状态
if (this.state !== PENDING) return
// 修改状态为执行成功
this.state = state
// 保存操作成功结果
this.result = result
// 将数组中的函数在微任务队列中运行
queueMicrotask(this._runAllCallbacks)
}
/**
* 异步操作成功时调用
* @param {*} value 操作成功结果
* @returns void
*/
const onFulfilled = resultHandler(FULFILLED)
/**
* 异步操作失败时调用
* @param {*} reason 错误信息
* @returns void
*/
const onRejected = resultHandler(REJECTED)
/**
* 处理resolve传入参数信息
* @param {*} value resolve传入参数
*/
const resolvePromise = value => {
// 传入value为当前对象时,抛出异常
if (value === this) {
return onRejected(new TypeError('Chaining cycle detected for promise'))
}
// 当前value为MyPromise则执行函数
if (value instanceof MyPromise) {
return value.then(onFulfilled, onRejected)
}
// 当value值为对象的时候
if (isObject(value) || isFunction(value)) {
try {
// 如果value包含一个then字段
const then = value.then
// 如果then为一个函数
if (isFunction(then)) {
// 进入一个新的MyPromise对象
return new MyPromise(then.bind(value)).then(onFulfilled, onRejected)
}
} catch (error) {
// 如果抛出异常则调用reject函数
return onRejected(error)
}
}
// 若为其他类型则直接调用resolve函数
onFulfilled(value)
}
try {
// 执行外部传入参数
executor(executedHandler(resolvePromise), executedHandler(onRejected))
} catch (error) {
// 若executor抛出异常则调用reject函数
executedHandler(onRejected)(error)
}
}
/**
* 添加状态改变时的回调函数
* @param {*} onFulfilled FULFILLED状态回调函数
* @param {*} onRejected FULFILLED状态的回调函数
*/
then(onFulfilled, onRejected) {
// 创建回调信息
const callback = { onFulfilled, onRejected }
// 当前状态为等待中
if (this.state === PENDING) {
// 保存回调信息到callbacks数组中
this.callbacks.push(callback)
return
}
// 在微任务队列中执行当前任务
queueMicrotask(() => this._runCallback(callback))
}
/**
* 执行callbacks数组中保存的
*/
_runAllCallbacks = () => {
// 循环调用数组元素执行
this.callbacks.forEach(this._runCallback)
// 完成后清空数组
this.callbacks = []
}
/**
* 执行then传入的函数信息
* @param {object} callback 需要执行的回调函数信息
* @param {*} callback.onFulfilled 成功状态下回调函数
* @param {*} callback.onRejected 失败状态下回调函数
*/
_runCallback = ({ onFulfilled, onRejected }) => {
// 成功状态
if (this.state === FULFILLED) {
// 若onFulfilled为函数,则传入result作为参数执行
isFunction(onFulfilled) && onFulfilled(this.result)
}
// 失败状态
if (this.state === REJECTED) {
// 若onRejected为函数,则传入result作为参数执行
isFunction(onRejected) && onRejected(this.result)
}
}
}
const p = new MyPromise((resolve, reject) => {
resolve({
then: resolve => resolve('aaa')
})
resolve('bbb')
})
p.then(
data => {
console.log('data: ', data)
},
err => {
console.log('err: ', err)
}
)