Promise实现
Promise
方法是可以非常基础但是又非常重要的API,今天就一步一步刨析Promise 来完成
# 什么是Promise
- Promise是异步回调的一种解决方案。在传统的异步实现方案中都是通过回调来解决的。
- 但是过多的回调难以维护,也会形式一种所称“地狱嵌套” 的状态。
- Promise 可以使用then链来解决这个问题。但是又不是尽善尽美的。过多的then链也会给使用者带来困扰
- 解决下来我们一起探究下Promise到底如何实现吧
# 基础辅助函数
# 1.
const PromiseStatus = {
Pending: 'Pending',
Fulfilled: 'Fulfilled',
Rejected: 'Rejected'
}
1
2
3
4
5
2
3
4
5
- 上述代码分别表示Promise的三种状态
- Promise中状态不可逆的,只能是从等待 => 成功/ 等待 => 失败。 一旦状态修改后不可再变化
# 2.
const isObject = (value) =>
Object.prototype.toString.call(value) === '[object Object]'
const isPromise = (obj) =>
(isObject(obj) || typeof obj === 'function') && typeof obj.then === 'function'
1
2
3
4
2
3
4
- 上述代码为了判断是否是对象 或是 是否是Promise
# 3.
/**
* @author lihh
* @description 深度解析promise 返回值
* @param p 表示上次的promise 实例
* @param preValue 上一次的值
* @param resolve then 返回promise中的 resolve
* @param reject then返回promise中的 reject
*/
const depthResolvePromise = (p, preValue, resolve, reject) => {
// 如果是返回value 跟实例是同一个的话 直接报错
if (p === preValue) {
throw new TypeError('the same instance cannot be referenced cyclically ')
}
// 判断是否是对象 如果不是对象的话 直接执行resolve
if (isObject(preValue) || typeof preValue === 'function') {
const then = preValue.then
// 如果then属性不是函数的话,直接执行resolve
if (typeof then === 'function') {
// 从这几话中可以得到 .then 作为一个新的Promise的状态,成功与否取决于内部返回Promise的状态
try {
then.call(
preValue,
(y) => {
depthResolvePromise(p, y, resolve, reject)
},
(r) => {
depthResolvePromise(p, r, resolve, reject)
}
)
} catch (e) {
reject(e)
}
} else {
resolve(preValue)
}
} else {
resolve(preValue)
}
}
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
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
- 上述的代码主要是为了进一步解析promise,有可能Promise实例返回内容还是一个Promise实例
- 上述代码中如果是被异常捕获到,直接执行reject函数
- 如果
preValue
不是promise 实例的话,统一直接resolve函数。都是成功的状态(无论返回值是null/ undefined等都作为成功的状态) - 一直递归调用函数
depthResolvePromise
直到解析成为一个非promise实例的普通值为止
# Promise构造函数
function Promise(execution) {
// 成功状态的值
this.value = ''
// 失败的值
this.reason = ''
// 表示每个promise 实例的状态
this.state = PromiseStatus.Pending
// 为了应对异步情况。 保存onFulfilled/ onRejected 方法
this.fulfilledCallback = []
this.rejectedCallback = []
// 构造函数的resolve 方法
const resolveFn = (value) => {
if (value instanceof Promise) {
return value.then(resolveFn, rejectFn)
}
if (this.state !== PromiseStatus.Pending) return
this.value = value
this.state = PromiseStatus.Fulfilled
this.fulfilledCallback.forEach((fn) => fn(this.value))
}
// 构造函数的reject方法
const rejectFn = (reason) => {
if (this.state !== PromiseStatus.Pending) return
this.reason = reason
this.state = PromiseStatus.Rejected
this.rejectedCallback.forEach((fn) => fn(this.reason))
}
try {
execution(resolveFn, rejectFn)
} catch (e) {
rejectFn(e)
}
}
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
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
上述代码是Promise 构造函数执行的代码
首先一点,Promise构造函数是一个同步执行的过程,是then方法是异步的。所以不要弄混了
如果执行构造函数期间发生异常了,捕获到后,直接执行reject方法
可能用户使用Promise。调用resolve方法的时候,传递的还是一个promise实例。这个时候需要特殊的判断,如下记:
if (value instanceof Promise) { return value.then(resolveFn, rejectFn) }
1
2
3属性
fulfilledCallback
以及rejectedCallback
为了应对异步情况。因为执行then的时候,promise实例状态还没有修改,所以需要优先保存
# Promise.prototype.then
/**
* @author lihh
* @description Promise then方法 本身是一个微任务
* @param onFulfilled 成功状态的回调
* @param onRejected 失败状态的回调
*/
Promise.prototype.then = function (onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') onFulfilled = (x) => x
if (typeof onRejected !== 'function')
onRejected = (err) => {
throw err
}
// 状态resolve/ rejected 的场合
if ([PromiseStatus.Fulfilled, PromiseStatus.Rejected].includes(this.state)) {
// 此处代表返回的一个新的实例
const p = new Promise((resolve, reject) => {
queueMicrotask(() => {
try {
const r =
this.state === PromiseStatus.Fulfilled
? onFulfilled(this.value)
: onRejected(this.reason)
depthResolvePromise(p, r, resolve, reject)
} catch (e) {
reject(e)
}
})
})
return p
}
// 状态是pending 的场合
const p = new Promise((resolve, reject) => {
this.fulfilledCallback.push((value) => {
queueMicrotask(() => {
try {
const r = onFulfilled(value)
depthResolvePromise(p, r, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.rejectedCallback.push((reason) => {
queueMicrotask(() => {
try {
const r = onRejected(reason)
depthResolvePromise(p, r, resolve, reject)
} catch (e) {
reject(e)
}
})
})
})
return p
}
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
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
- 首先then函数的成功回调以及失败的回调,可以不进行传值
- 针对状态是:
fulfilled
,rejected
,pending
进行不同的处理 - 但是then方法一定会返回一个全新的promise。因为promise状态不可逆的
# Promise.prototype.finally
Promise.prototype.finally = function (fn) {
try {
fn()
return this.then(null, null)
} catch (e) {
const callback = () => {
throw e
}
return this.then(callback, callback)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- finally 实现原理就是不同的场合 调用then方法
- 如果finally函数调用过程中有异常抛出,后续的会进行异常处理。其余的场合无论finally会返回什么样的结构,都不会改变其promise状态
# Promise.prototype.catch
Promise.prototype.catch = function (fn) {
// catch 执行的逻辑就是then 只执行error的分支
return this.then(null, fn)
}
1
2
3
4
2
3
4
catch方法其实就是
then
函数的另一种实现
# Promise.abort
自己添加的方法,在原生的Promise中并没有,可以中断promise的执行
/**
* @author lihh
* @description promise中断方法
* @param userPromise 用户自己promise
*/
Promise.abort = function (userPromise) {
let abort
const innerPromise = new Promise((_, reject) => {
abort = reject
})
const racePromise = Promise.race([userPromise, innerPromise])
racePromise.abort = abort
return racePromise
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
其实就是利用了函数
race
的原理,返回第一个成功/ 失败的状态
# Promise.resolve
/**
* @author lihh
* @description 直接返回一个具有成功状态的promise
* @param params 传递参数
* @returns {Promise}
*/
Promise.resolve = function (params) {
return new Promise((resolve) => {
resolve(params)
})
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
默认就是一个成功的状态promise
# Promise.reject
/**
* @author lihh
* @description 直接返回一个具有失败状态的 promise
* @param params 传递参数
* @returns {Promise}
*/
Promise.reject = function (params) {
return new Promise((_, reject) => {
reject(params)
})
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
默认就是一个失败的promise
# Promise.race
/***
* @author lihh
* @description 返回一个promise的状态,无论是成功还是失败
* @param allPromise 表示所有的promise
*/
Promise.race = function (allPromise = []) {
return new Promise((resolve, reject) => {
let i = 0
for (; i < allPromise.length; i += 1) {
const item = allPromise[i]
if (!isPromise(item)) {
return resolve(item)
} else {
item.then(resolve, reject)
return
}
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 返回第一个成功或是失败的结果
- mdn解释
# Promise.any
/**
* @author lihh
* @description 一旦出现一个可兑现状态,就是可兑现的状态,如果全都不可兑现,就是rejected状态
* @param allPromise 表示所有的promise
*/
Promise.any = function (allPromise) {
return new Promise((resolve, reject) => {
let count = 0
const rejectedCallback = () => {
count += 1
if (count >= allPromise.length) {
reject('[AggregateError: All promises were rejected]')
}
}
let i = 0
for (; i < allPromise.length; i += 1) {
const item = allPromise[i]
if (!isPromise(item)) {
return resolve(item)
} else {
item.then(
(res) => {
return resolve(res)
},
() => {
rejectedCallback()
}
)
}
}
})
}
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
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
- 如果一旦有任意一个promise的状态是成功状态,该结果就会被返回
- 如果所有的promise状态都失败了,则返回失败的状态
- mdn解释
# Promise.allSettled
/**
* @author lihh
* @description 批量执行promise数组 无论是成功还是失败都会返回 最后返回一个promise 返回结构是:{status: 'fulfilled/ rejected', value}
* @param allPromise 传递参数
*/
Promise.allSettled = function (allPromise = []) {
return new Promise((resolve) => {
let count = 0
const resultArr = []
const callback = (index, value, status) => {
resultArr[index] = {status, value}
count += 1
if (count >= allPromise.length) {
resolve(resultArr)
}
}
allPromise.forEach((item, index) => {
if (!isPromise(item)) {
callback(index, item, 'fulfilled')
} else {
item.then(
(res) => {
callback(index, res, 'fulfilled')
},
(err) => {
callback(index, err, 'rejected')
}
)
}
})
})
}
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
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
- 执行所有的promise 无论是成功状态还是失败的状态 都会以指定的格式返回
- mdn解释
# Promise.all
/**
* @author lihh
* @description 多个promise 同时发出请求,如果全部成功结果 以数组的形式全部返回
* @param promiseAll promise 数组
* @returns {Promise} 返回的promise
*/
Promise.all = function (promiseAll = []) {
return new Promise((resolve, reject) => {
const resultArr = []
let count = 0
const callback = (index, res) => {
count += 1
resultArr[index] = res
if (count >= promiseAll.length) {
resolve(resultArr)
}
}
for (let i = 0; i < promiseAll.length; i += 1) {
const p = promiseAll[i]
if (!isPromise(p)) {
callback(i, p)
} else {
p.then((res) => {
callback(i, res)
}, reject)
}
}
})
}
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
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
- 如果所有的promise 都是成功状态,会以数组的形式进行返回
- 一旦有一个状态是rejected状态。立马执行失败的操作
- mdn解释