I think the hardest part of implementing promises is the chain call. Here’s an example of a Promise chain call:
(new Promise(resolve= > {
resolve(1)
})).then(data= > {
console.log(data)
return new Promise(
resolve= > setTimeout(() = > resolve(2), 100)
)
}).then(data= > {
console.log(data)
return Promise.resolve(3)
}).then(data= > console.log(data))
Copy the code
The code above prints: 1,2,3. A chain call is an asynchronous operation performed sequentially, passing the data returned from the then of the previous Promise to the next Promise. Before we move on, you can try implementing the Promise chain call yourself.
implementation
1 supports non-chained invocation
Let’s first implement a non-chained call to MyPromise that satisfies the following call:
// Case 1: output 1.
(new MyPromise(resolve= > {
resolve(1)
})).then(data= > console.log(data));
// Case 2: output 2.
(new MyPromise(resolve= > {
setTimeout(() = > resolve(2), 100)
})).then(data= > console.log(data))
Copy the code
The implementation code is as follows:
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
class MyPromise {
constructor(fn) {
this.status = PENDING
this.data = null
fn(this._resolve.bind(this))}_resolve(data) {
if (this.status === PENDING) {
this.status = FULFILLED
this.data = data
this.callback && this.callback(data)
}
}
then(fulfilledCallback) {
switch (this.status) {
case PENDING: // For case 1
this.callback = fulfilledCallback
break;
case FULFILLED: // For case 2
fulfilledCallback(this.data)
break; }}}Copy the code
2 supports chained invocation
Satisfy the following call:
// outputs: 1,2,3
(new MyPromise(resolve= > {
resolve(1)
})).then((data) = > {
console.log(data)
return new MyPromise(
resolve= > setTimeout(() = > resolve(2), 100)
)
}).then((data) = > {
console.log(data)
return
}).then((data) = > {
console.log(data)
})
Copy the code
To support chained calls, then should also return a MyPromise object. And the returned MyPromise object is attached to another MyPromise object in the callback. We just rewrite the then function. The code implementation is as follows:
then(fulfilledCallback) {
return new MyPromise((resolve, reject) = > {
const fulfilled = () = > {
const res = fulfilledCallback(this.data)
return this.resolvePromise(res, resolve, reject)
}
switch (this.status) {
case PENDING:
this.callback = fulfilled
break;
case FULFILLED:
fulfilled()
break; }})}resolvePromise(fulfillRes, resolve, reject) {
if(fulfillRes instanceof MyPromise) {
// Pass resolve's data down
fulfillRes.then(resolve, reject)
} else {
resolve(fulfillRes)
}
}
Copy the code
At this point, the chain call of Promise is implemented. The complete code is as follows:
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
class MyPromise {
constructor(fn) {
this.status = PENDING
this.data = null
fn(this._resolve.bind(this))}_resolve(data) {
if (this.status === PENDING) {
this.status = FULFILLED
this.data = data
this.callback && this.callback(data)
}
}
then(fulfilledCallback) {
return new MyPromise((resolve, reject) = > {
const fulfilled = () = > {
const res = fulfilledCallback(this.data)
return this.resolvePromise(res, resolve, reject)
}
switch (this.status) {
case PENDING:
this.callback = fulfilled
break;
case FULFILLED:
fulfilled()
break; }})}// Implement chain core code
resolvePromise(fulfillRes, resolve, reject) {
if(fulfillRes instanceof MyPromise) {
// Pass resolve's data down
fulfillRes.then(resolve, reject)
} else {
resolve(fulfillRes)
}
}
}
Copy the code
Recommended reading
“Starting with a Promise interview question that keeps me up at night, an in-depth analysis of the Promise implementation details” : juejin.cn/post/694531… . The article details the implementation of Promise.