手写Promise内部原理
Promise/A+规范 (opens new window)是开源健全可互操作的JavaScript Promise 规范,通过阅读PromiseA+规范的文档来实现一个Promise将会事半功倍,有助于我们更好的理解Promise的核心思想。 Promise代表着异步操作的最终结果。与Promise进行交互的主要方式是通过then方法, 它的核心其实是then方法收集回调函数,然后通过reslove或者reject触发所有then收集的回调函数,是一个发布订阅模式。
# PromiseA+规定了如下内容:
# 1.Promise 的相关术语
1.1 promise 是一个带有符合此规范的then方法的对象或者函数。
1.2 thenable 是一个定义了一个then方法的对象或者函数。
1.3 value 是一个任意合法的JavaScript值(包括undefined, thenable,或者promise)。
1.4 exception 是一个使用throw语句抛出的值。
1.5 reason 是一个指出为什么promise被rejected的原因。
# 2.Promise 的具体要求
# 2.1 Promise 的状态
一个 promise 必须是三种状态其中的一种状态:pending,fulfilled或者rejected。
2.1.1 当 promise 处于 pending 状态时:
2.1.1.1 可以转变到
fulfilled或者rejected状态。
2.1.2 当 promise 处于 fulfilled 状态时:
2.1.2.1 一定不能够转变到其他任何一种状态。 2.1.2.2 必须有一个
value,并且这个值一定不能改变。
2.1.3 当promise处于rejected状态时:
2.1.3.1 一定不能够转变到其他任何一种状态。 2.1.3.2 必须有一个
reason,并且这个值不能够改变。
在这里,一定不能改变 意味着不可变的身份(即===),但并不意味着深层不变性。
根据上面 2.1 promise 状态 状态描述信息可以得出以下信息:
- 每个
Promise都有三个状态,pennding等待态,resolve标识变成成功态fulfilled,reject标识变成失败态rejected。 - 一旦成功就不能失败 一旦失败不能成功。
- 当
Promise抛出异常后 也会走失败态。
根据上面2.1 promise 状态的要求,实现代码如下:
// 定义状态枚举
const STATUS = {
pennding: 'PENNDING',
fulfilled: "FULFILLED",
rejected: 'REJECTED'
}
class Promise{
constructor(executor) { // executor就是new Promise((resolve,reject)=>{}) 传入的(reslove,reject)=>{...}函数
this.status = STATUS.pennding // 当前的状态 创建时为pennding
this.value = null // 当前值
this.reason = null // 失败原因
// resolve 函数
const resolve = (value) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.fulfilled // 将状态置为fulfilled
this.value = value
}
}
// reject 函数
const reject = (reason) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.rejected // 将状态置为fulfilled
this.reason = reason
}
}
// 捕获异常 用于处理用户reslove/reject了抛出的错误,例如throw Error('xxxxx')
try {
executor(reslove, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// 成功的回调
if (this.status === STATUS.fulfilled) { // 只有状态为fulfilled时才能执行onFulfilled方法,用户调用resolve时会将状态改为fulfilled
onFulfilled(this.value)
}
// 失败的回调
if (this.status === STATUS.rejected) { // 只有状态为rejected时才能执行onRejected方法,用户调用reject时会将状态改为rejected
onRejected(this.reason)
}
}
}
// case1
const promise = new Promise((resolve,reject)=>{
resolve('success')
reject('error')
})
promise.then(
value=> console.log(value),
reason=> console.log(reason),
)
// => 'success' 先resolve了状态发生了变化,所以后面的reject不会执行
复制代码
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
这样就实现了一个最简单的,能then调用的Promise类。
但是还有很多问题,例如then里面如果是异步代码,resolve或reject就不会执行,因为那个时候状态还是pennding。
这个问题可以用发布订阅模式来解决,在状态是pennding的时候,每次then就把传入的回调收集起来,resolve或reject的时候,把收集的回调全部执行。
实现如下:
// 定义状态枚举
const STATUS = {
pennding: 'PENNDING',
fulfilled: "FULFILLED",
rejected: 'REJECTED'
}
class Promise {
constructor(executor) { // executor就是new Promise((reslove,reject)=>{}) 传入的(reslove,reject)=>{...}函数
this.status = STATUS.pennding // 当前的状态 创建时为pennding
this.value = null // 当前值
this.reason = null // 失败原因
this.onReslovedCallbacks = [] // 存放成功的回调函数队列 ---> 新加的代码
this.onRejectedCallbacks = [] // 存放失败的回调函数队列 ---> 新加的代码
// reslove 函数
const reslove = (value) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.fulfilled // 将状态置为fulfilled
this.value = value
// 执行所有订阅的fulfilled函数
this.onReslovedCallbacks.forEach(fn => fn()) // ---> 新加的代码
}
}
// reject 函数
const reject = (reason) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.rejected // 将状态置为fulfilled
this.reason = reason
// 执行所有订阅的rejected函数
this.onRejectedCallbacks.forEach(fn => fn()) // ---> 新加的代码
}
}
// 捕获异常 用于处理用户resolve/reject了抛出的错误,例如throw Error('xxxxx')
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// 成功的回调
if (this.status === STATUS.fulfilled) { // 只有状态为fulfilled时才能执行onFulfilled方法,用户调用resolve时会将状态改为fulfilled
onFulfilled(this.value)
}
// 失败的回调
if (this.status === STATUS.rejected) { // 只有状态为rejected时才能执行onRejected方法,用户调用reject时会将状态改为rejected
onRejected(this.reason)
}
// 如果是等待状态,就把res,rej的处理回调函数放入对应的队列里 ---> 下面是新加的代码
if (this.status === STATUS.pennding) {
// 放入成功回调队列
this.onResolvedCallbacks.push(() => { // 切片: 将传入的函数用一个新函数包起来,可以在这个新函数里面写统一的额外逻辑(aop)
// 这里可以写额外的逻辑
onFulfilled(this.value)
})
// 放入失败回调队列
this.onRejectedCallbacks.push(() => { // 切片: 将传入的函数用一个新函数包起来,可以在这个新函数里面写统一的额外逻辑(aop)
// 这里可以写额外的逻辑
onRejected(this.reason)
})
}
}
}
// case2
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
setTimeout(() => {
reject('error')
}, 2000)
})
promise.then(
value => {
console.log(value, '1')
},
err => {
console.log(err)
}
)
// => 一秒后:
// success1
复制代码
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
到现在已经实现了最基本的能异步Promise类,但是还有很多规范功能没有,继续往下看 PromiseA+ 规范要让我们实现的功能。
# 2.2 Promise 的 then() 方法
1. 一个Promise必须提供一个then方法去访问当前或者最终的value或者reason。
2. 一个Promise的then方法接受两个参数:onFulfilled 和 onRejected。
Promise.then(onFulfilled, onRejected)
复制代码
2
2.2.1 onFulfilled 和 onRejected 都是可选的参数:
2.2.1.1 如果
onFulfilled不是一个函数,它必须被忽略。 2.2.1.2 如果onRejected不是一个函数,它必须被忽略。
2.2.2 如果 onFulfilled 是一个函数:
2.2.2.1
promise是fulfilled状态时它必须被调用,并且promise的value作为它的第一个参数。 2.2.2.2 它一定不能在promise进入fulfilled状态之前被调用。 2.2.2.3 它一定不能够调用超过一次。
2.2.3 如果 onRejected 时一个函数:
2.2.3.1
promise是rejected状态时它必须被调用,并且promise的reason作为它的第一个参数。 2.2.3.2 它一定不能在promise进入rejected状态之前被调用。 2.2.3.3 它一定不能够调用超过一次。
2.2.4 直到执行上下文堆栈仅包含平台代码之前,onFulfilled 或 onRejected 不能够被调用。
2.2.5 onFulfilled 和 onRejected 必须以函数的形式被调用(即没有this值)。
2.2.6 then 可以在同一个promise被调用多次:
2.2.6.1 当 promise 处于
fulfilled状态时,各个onFulfilled回调必须按其原始调用的顺序执行。 2.2.6.2 当 promise 处于rejected状态时,各个onRejected回调必须按其原始调用的顺序执行。
2.2.7 then 必须返回一个promise:
promise2 = promise1.then(onFulfilled, onRejected);
复制代码
2
2.2.7.1 如果
onFulfilled或onRejected返回一个值x,运行Promise解决程序。 2.2.7.2 如果onFulfilled或onRejected抛出一个意外e,promise2必须以e为reason被rejected。 2.2.7.3 如果onFulfilled不是一个函数并且promise1处于fulfilled状态,promise2必须以与promise1同样的value转变到fulfilled状态。 2.2.7.4 如果onRejected不是一个函数并且promise1处于rejected状态,promise2必须以与promise1同样的reason转变到rejected状态。
根据2.2then方法描述信息可以得出以下信息:
1.每个Promise需要有一个then方法,传入两个回调函数作为参数onFulfilled, onRejected,非必传,但是不会影响下一个then的传值。
2.每次调用then必须返回一个promise2,是一个全新promise的实例,如果promise2里reslove/reject了一个新值x,则把当前值x当参数传递到下一个then的回调函数里。
思考:要想实现这样一个需求,返回的promise必须是一个新的实例,因为promise的状态是不可逆的,将新的promise的reslove和reject处理上一个promise返回的值。而且在没有传onFulfilled 和 onRejected函数,那么就要自己包一层函数并且该函数的返回值是上一个promise返回的值。
代码如下:
// 定义状态枚举
const STATUS = {
pennding: 'PENNDING',
fulfilled: "FULFILLED",
rejected: 'REJECTED'
}
class Promise {
constructor(executor) { // executor就是new Promise((reslove,reject)=>{}) 传入的(reslove,reject)=>{...}函数
this.status = STATUS.pennding // 当前的状态 创建时为pennding
this.value = null // 当前值
this.reason = null // 失败原因
this.onResolvedCallbacks = [] // 存放成功的回调函数队列
this.onRejectedCallbacks = [] // 存放失败的回调函数队列
// resolve 函数
const resolve = (value) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.fulfilled // 将状态置为fulfilled
this.value = value
// 执行所有订阅的fulfilled函数
this.onResolvedCallbacks.forEach(fn => fn())
}
}
// reject 函数
const reject = (reason) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.rejected // 将状态置为fulfilled
this.reason = reason
// 执行所有订阅的rejected函数
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 捕获异常 用于处理用户resolve/reject了抛出的错误,例如throw Error('xxxxx')
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// -->重写了then函数,用promise包起来了
then(onFulfilled, onRejected) {
// 处理onFulfilled, onRejected为空的情况,防止then丢失上一个then返回的值
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : x => x;
onRejected = typeof onRejected == 'function' ? onRejected : err => { throw err }
// 每次调用then都返回一个全新的promise,把之前收集then回调函数的逻辑放到 new Promise()里面
const promise2 = new Promise((resolve, reject) => {
// 成功的回调
if (this.status === STATUS.fulfilled) {
try {
// resolve的返回值传给新的promise的结果
const x = onFulfilled(this.value)
resolve(x)
} catch (err) {
// reject的返回值传给新的promise的失败的结果
reject(err)
}
}
// 失败的回调
if (this.status === STATUS.rejected) {
try {
const x = onRejected(this.reason)
resolve(x) // onRejected返回的普通值会作为下一个then的reslove的值(promise规范)
} catch (err) {
reject(err)
}
}
// 如果是等待状态,就把res,rej的处理回调函数放入对应的队列里
if (this.status === STATUS.pennding) {
// 放入成功回调队列
this.onResolvedCallbacks.push(() => {
// 额外的逻辑
if (this.status === STATUS.fulfilled) {
try {
const x = onFulfilled(this.value)
resolve(x)
} catch (err) {
reject(err)
}
}
})
// 放入失败回调队列
this.onRejectedCallbacks.push(() => {
try {
const x = onRejected(this.reason)
resolve(x)
} catch (err) {
reject(err)
}
})
}
})
// 返回新的promise供下一个then调用
return promise2;
}
}
// case3
const promise = new Promise((reslove, reject) => {
setTimeout(() => {
reslove('success')
}, 1000)
})
promise.then(
value => {
console.log(value, '1')
return 'returnValue'
}
).then(
value => {
console.log(value, '2')
return 'otherValue'
}
).then().then( // 空then不会影响return的值
value => console.log(value, '3')
)
// => 一秒后:
// success1
// returnValue2
// otherValue3
// case4
const promise1 = new Promise((reslove, reject) => {
setTimeout(() => {
reject('error')
}, 1000)
})
promise1.then(
value => { },
err => {
console.log(err, 'err')
throw new Error('出错了')
}
).then(
value => {
console.log(err, 's1')
},
err => {
console.log(err, 'e1')
}
).then().then(
value => {
console.log(err, 's2')
},
err => {
console.log(err, 'e2')
}
)
// => 一秒后:
// error
// Error 出错了
// 后面的不再执行了
复制代码
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
到目前为止已经基本实现了Promise的功能,能多个then链式调用,并且then里面return的值也能正确的传到下一个then,而且then里面throw Error也能正确的打断后面的then。
但是还有一些重要的功能没有,不能跟标准的Promise混用,例如then里面如果return的是Promise实例resolve/reject的值能不能正常传递到下一个then。
# 2.3 Promise 的解决程序
promise解决程序是一个抽象的操作,它把一个 promise 和一个 value 作为输入,我们将这个表示为 [[Resolve]](promise, x)。
如果 x 是一个 thenable ,它将会试图让 promise 采用 x 的状态,前提是x的行为至少有点像一个 promise。否则,它将会用值 x执行promise。
对这些 thenable 的处理使得与 promise 实现方式能够去互相操作。只要它们公开了符合 Promise/A+ 的 then 方法。它还使得 promises/A+ 实现方式能够采用合理的 then 方法去“同化”不一致的实现方式。
为了运行[[Resolve]](promise, x),执行以下步骤:
2.3.1 如果 promise 与 x 是同一个对象,以 Tyeperror 作为 reason 去 reject promise。 2.3.2 如果 x 是一个 promise,使用它的状态:
2.3.2.1 如果
x处于pending状态,promise必须保持pending状态直到x处于fulfilled或者rejected状态。 2.3.2.2 如果x处于fulfilled状态,以相同的value去fulfill promise。 2.3.2.3 如果x处于rejected状态,以相同的reason去reject promise。
2.3.3 否则,如果 x 是一个对象或者函数:
2.3.3.1 让
then作为x.then。 2.3.3.2 如果取属性x.then会导致抛出异常e,则以e为reason reject promise。 2.3.3.3 如果then是一个函数,让x作为this调用它,第一个参数为resolvePromise,第二个参数为rejectPromise,然后:2.3.3.3.1 如果使用
valuey调用resolvepromise时,运行[[Resolve]](promise, y)。 2.3.3.3.2 如果使用reasonr调用rejectPromise时,也用reject promise。 2.3.3.3.3 如果resolvePromise和rejectPromise都被调用了,或多次调用同一参数,那么第一个调用优先,其他的调用都会被忽略。 2.3.3.3.4 如果调用then的过程中抛出了一个意外e。2.3.3.3.4.1 如果
resolvePromise或者rejectPromise被调用了,那么忽略它。 2.3.3.3.4.2 否则,把e作为reason reject promise。2.3.3.4 如果
then不是一个函数,将x作为参数执行promise。2.3.4 如果 x 不是一个对象或者函数,将
x作为参数执行promise。
如果一个参与了 thenable 循环链的 thenable 去 resolve promise,这样 [[Resolve]](promise, thenable) 的递归性质最终会导致[[Resolve]](promise, thenable) 会被再次调用,遵循上述算法将会导致无限递归。我们鼓励去实现(但不是必需的)检测这样的递归,并以 TypeError 作为 reason 去 reject Promise。
# 2.4 Promise 的平台代码
3.1 这里的“平台代码”指的是引擎,环境和 promise 实现代码。
实际上,这个要求保证了 onFulfilled 和 onRejected 将会异步执行,在事件循环之后,用一个新的堆栈来调用它。 这可以通过“宏任务”机制(如 settimeou t或 setimmediate )或“微任务”机制(如 mutationobserver 或 process.nextick)来实现。
由于 Promise 实现被视为平台代码,因此它本身可能包含一个任务调度队列或“trampoline”,并在其中调用处理程序。
3.2 也就是说,在 strict 模式下,这(指的是this)在它们内部将会是 undefined;在 sloppy 模式下,它将会是全局对象。
3.3 如果实现满足所有要求,则实现可能允许 promise2 == promise1。每个实现都应该记录它是否能够生成promise2 == promise1以及在什么条件下。
3.4 一般来说,只有当 X 来自当前的实现时,才知道它是一个真正的promise。本条款允许使用特定于实现的方法来采用已知一致承诺的状态。
3.5 此过程首先存储对 x 的引用,然后测试该引用,然后调用该引用,避免多次访问x.then属性。这些预防措施对于确保访问器属性的一致性非常重要,访问器属性的值可能在两次检索之间发生更改。
3.6 实现方式中不应当在 thenbale 链中的深度设置主观的限制,并且不应当假设链的深度超过主观的限制后会是无限的。只有真正的循环才能导致 TypeError。如果遇到由无限多个不同 thenable 组成的链,那么永远递归是正确的行为。
思考:
在then有可能会return一个新的promise,这个时候需要将这个promise的reslove或reject的值传给下一个then,并且这个promise还有可能是别人实现的promise,要做兼容。
所以需要Promise解决函数它的核心的逻辑是要解析 x 的类型,来决定promise2 走成功还是失败,判断 x 的值决定promise2的关系 来判断有可能x是别人的promise可能别人的promise会出问题。
下面来实现reslovePromise函数
// 解析 x 的类型 来决定promise2 走成功还是失败
// promise2: 当前then里面promise实例
// x: 上一个then的返回值
// resolve,reject: 当前then里面promise的executor
function resolvePromise(promise2, x, resolve, reject) {
// 判断x 的值决定promise2 的关系 来判断有可能x 是别人的promise 可能别人的promise会出问题
if (x == promise2) {
return reject(new TypeError('出错了'))
}
// {}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
// 只有x是对象或者函数才有可能是promise
let called = false; // 表示没调用过成功和失败
try {
let then = x.then; // 取x上的 then方法
if (typeof then == 'function') { // {then:function(){}}
then.call(x, y => { // x.then如果这样写 可能还会走get方法
// y 可能是一个promise, 递归解析y的值 直到他是一个普通值为止
if (called) return;
called = true
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true
reject(r);
});
}else{
resolve(x); // 普通对象{}
}
} catch (e) {
if (called) return;
called = true
reject(e); // 走失败逻辑
}
} else {
// 如果不是 那一定是一个普通值
resolve(x);
}
}
复制代码
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类可以改成这样:
// 定义状态枚举
const STATUS = {
pennding: 'PENNDING',
fulfilled: "FULFILLED",
rejected: 'REJECTED'
}
class Promise{
constructor(executor) { // executor就是new Promise((reslove,reject)=>{}) 传入的(reslove,reject)=>{...}函数
this.status = STATUS.pennding // 当前的状态 创建时为pennding
this.value = null // 当前值
this.reason = null // 失败原因
this.onReslovedCallbacks = [] // 存放成功的回调函数队列
this.onRejectedCallbacks = [] // 存放失败的回调函数队列
// reslove 函数
const reslove = (value) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.fulfilled // 将状态置为fulfilled
this.value = value
// 执行所有订阅的fulfilled函数
this.onReslovedCallbacks.forEach(fn => fn())
}
}
// reject 函数
const reject = (reason) => {
if (this.status === STATUS.pennding) {
this.status = STATUS.rejected // 将状态置为fulfilled
this.reason = reason
// 执行所有订阅的rejected函数
this.onRejectedCallbacks.forEach(fn => fn())
}
}
// 捕获异常 用于处理用户reslove/reject了抛出的错误,例如throw Error('xxxxx')
try {
executor(reslove, reject)
} catch (err) {
reject(err)
}
}
// -->重写了then函数,用promise包起来了
then(onFulfilled, onRejected) {
// 处理onFulfilled, onRejected为空的情况,防止then丢失上一个then返回的值
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : x => x;
onRejected = typeof onRejected == 'function' ? onRejected : err => { throw err }
// 每次调用then都返回一个全新的promise,把之前收集then回调函数的逻辑放到 new Promise()里面
const promise2 = new Promise((reslove, reject) => {
// 成功的回调
if (this.status == STATUS.fulfilled) {
setTimeout(() => { //因为resolvePromise里面用了promise2,这个时候promise2还没实例化完拿不到,所以要用定时器包起来
try {
let x = onFulfilled(this.value); // x可能是一个promise
resolvePromise(promise2, x, resolve, reject);
// resolve(x); // 用then的返回值 作为下一次then的成功结果
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === STATUS.rejected) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status == STATUS.pending) {
// 订阅
this.onResolvedCallbacks.push(() => { // 切片
// todo .. 额外的逻辑
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
})
// 返回新的promise供下一个then调用
return promise2;
}
}
// case5
const promise = new Promise((reslove,reject)=>{
settimeout(()=>{
reslove('success')
},1000)
})
promise.then(
value=> {
console.log(value,'1')
return 'returnValue'
}
).then(
value=> console.log(value, '2')
return 'otherValue'
).then().then( // 空then不会影响return的值
value=> console.log(value, '3')
)
// => 一秒后:
// success1
// returnValue2
// otherValue3
// case6
let promise = new Promise((resolve, reject) => {
resolve('ok')
}).then(data => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data + ' resolved');
}, 2000);
}));
}, 1000)
})
}, err => {
});
promise.then(
data => {
console.log('success', data);
},
err => {
console.log('fail', err);
}
)
// => 2秒后:
// success ok resolved
复制代码
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
至此一个简单的符合A+规范的Promise实现已经完成。理解了这些之后,可以实现一些自己的Promise小功能,例如deferred延迟函数:
Promise.prototype.deferred = function () {
let dfd = {} as any;
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// case7
let dfd = Promise.deferred(); // 延迟对象
setTimeout(()=>{
dfd.resolve('dfd')
},1000)
dfd.promise.then(
data=>{
console.log(data)
},
)
// 一秒后 打印dfd
复制代码
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
也可以实现一下Promise.all方法
Promise.prototype.all = function(values) {
return new Promise((resolve, reject) => {
let arr = [];
let times = 0;
function collectResult(val, key) {
arr[key] = val;
if (++times === values.length) {
resolve(arr);
}
}
for (let i = 0; i < values.length; i++) {
let value = values[i];
if (value && isPromise(value)) {
value.then((y) => {
// 注意:这里要用计数器,不能直接push
collectResult(y, i)
}, reject)
} else {
collectResult(value, i);
}
}
})
}
复制代码
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
完结撒花~
作者:MrShu 链接:https://juejin.cn/post/6903765174109339655 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。