[Front-end Notes] Handwritten Promise, follow the tutorial to easily understand Promise

Promise is a new implementation solution in ES6 to solve asynchronous programming. With async and awiat, you can write asynchronous tasks more elegantly and Achieve synchronous execution. Promise means promise, which promises to return the result of the operation at a certain time in the future

A few simple examples of Promise:

let p = new Promise((resolve, reject) => {
    
    
    console.log(1);
    setTimeout(() => {
    
    
        resolve('then');
    }, 3000);
});

let p1 = new Promise(); // TypeError: Promise resolver undefined is not a function

p.then(res => console.log(1)); // '1', 3s -> 'then'

This example can get the following features of Promise:

  • new Promise will be executed immediately and receive a 必传 function as parameter

  • There are 2 parameters in the received function

  • The value needs to be obtained usingthenmethod

let p2 = new Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
})
console.log('p2', p2); // { PromiseState: 'fulfilled', PromiseResult: '成功' }

let p3 = new Promise((resolve, reject) => {
    
    
    reject('失败')
    resolve('成功')
})
console.log('p3', p3); // { PromiseState: 'rejected', PromiseResult: '失败' }

let p4 = new Promise((resolve, reject) => {
    
    
    throw('报错'); // { PromiseState: 'rejected', PromiseResult: '失败' }
})
console.log('p4', p4);

This example can get the following features of Promise:

  • has three states: initialpending, successfulfullfilled, rejectedrejected, and the status can only be changed from , irreversible or pending changes to fulfilledrejected
  • resolve changes the state to fulfilled, reject changes the state to rejected
  • Once the state changes from pending to fulfilled or rejected it will not change again

1. Define the initial structure based on the previous summary

// 定义promise的状态
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    // 接收一个函数作为参数
    constructor(executor) {
    
    
        // 初始状态为pending
        this.status = PENDING;
        // new Promise后立即执行,接收2个参数
        executor(resolve, reject);
    }
    // 获取结果的函数
    then() {
    
    }
}

According to the second example, we can see that the error thrown in p3 is also caused by rejected, so the structure is optimized:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        // 新增try-catch捕获错误,出错时将状态转变为rejected
+       try {
    
    
         	executor(resolve, reject);   
+       } catch (error) {
    
    
            reject(error);
+       }
    }
    then() {
    
    }
}

2. Implement resolve and reject methods

In the previous example, we already know that the function passed inpromise receives 2 parameters, that is, resolve and reject, their role is to change the status of promise.

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        try {
    
    
+           executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
+	resolve() {
    
    }
+   reject() {
    
    }
    then() {
    
    }
}

The state can only change from pending to fullfilled and rejected, and it is irreversible:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        try {
    
    
            executor(this.resolve, this.reject);
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
	resolve() {
    
    
        // 状态为pending才改变状态
+       if (this.status === PENDING) {
    
    
+          this.status = FULLFILLED;
+       }
  	}
  	reject() {
    
    
        // 状态为pending才改变状态
+    	if (this.status === PENDING) {
    
    
+      		this.status = REJECTED;
+    	}
  	}
  	then() {
    
    }
}

According to the example, you can see that parameters can be passed when calling resolve and reject, and finally the result can be obtained by calling then .

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        // 保存结果,最终返回
+       this.value = null;
        try {
    
    
            executor(this.resolve, this.reject);
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
+	resolve(value) {
    
    
        // 状态为pending才改变状态
        if (this.status === PENDING) {
    
    
          	this.status = FULLFILLED;
+           this.value = value;
        }
  	}
+  	reject(reason) {
    
    
        // 状态为pending才改变状态
    	if (this.status === PENDING) {
    
    
      		this.status = REJECTED;
+           this.value = reason;
    	}
  	}
  	then() {
    
    }
}

3. Implement the then method

The then method returns a Promise. It requires at most two parameters: the success and failure callback functions of the Promise (the failure callback function is optional) - MDN

// 接收两个参数
then(onFullfilled, onRejected) {
    
    
    // 返回一个Promise
    return new _Promise((resolve, reject) => {
    
    });
}

Because the then method returned promise, and promise has then method, so it can be called in a chain, for example:

let p = new Promise((resolve, reject) => {
    
    
    resolve(1);
});
p.then(res => {
    
    
    console.log(res);
    return res += 1;
}).then(res => {
    
    
    console.log(res);
    return res *= res;
}).then(res => {
    
    
    console.log(res);
}); // 1,2,4

Let’s first look at the execution results of the native method:

let p = new Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功

// 反过来
let p = new Promise((resolve, reject) => {
    
    
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

new PromiseWhen , it receives two parameters, which are callback functions to change the state to fullfilled and rejected respectively. The then method also receives two parameters, which are callback functions for the success and failure of promise. So according to the result, we can know that the then method is executing the corresponding method according to the status of promise

// 接收两个参数
then(onFullfilled, onRejected) {
    
    
    // 如果状态为fullfilled,调用成功回调并将resolve时带来的参数传入并执行
+   if (this.status === FULLFILLED) {
    
    
+       onFullfilled(this.value);
+   }
    // 如果状态为rejected,调用失败回调并将reject时带来的参数传入并执行
+   if (this.status === REJECTED) {
    
    
+       onRejected(this.value);
+   }
    // 返回一个Promise
    return new _Promise((resolve, reject) => {
    
    });
}

For the time being, the basic functions are available. Let’s test it:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
       	this.status = PENDING;
       	this.value = null;
        try {
    
    
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
	resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
          	this.status = FULLFILLED;
           	this.value = value;
        }
  	}

  	reject(reason) {
    
    
    	if (this.status === PENDING) {
    
    
      		this.status = REJECTED;
           	this.value = reason;
    	}
  	}

    then(onFullfilled, onRejected) {
    
    
      	if (this.status === FULLFILLED) {
    
    
           onFullfilled(this.value);
      	}

       	if (this.status === REJECTED) {
    
    
           onRejected(this.value);
       	}

        return new _Promise((resolve, reject) => {
    
    });
    }
}

// 测试代码
let p = new _Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功
// 反过来
let p = new _Promise((resolve, reject) => {
    
    
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

Just like native execution, success! However, some details are ignored, such as:

// 原生
let p = new Promise((resolve, reject) => {
    
    
    resolve('成功');
})
p.then(
    null, // 或undefined
    error => console.log(error)
); // 无输出无报错

// 自己实现的
let p = new _Promise(resolve => {
    
    
    resolve('成功');
});
p.then(
    null,
    error => console.log(error)
); // onFullfilled is not a function

Because our implementation in thethen method is to directly execute the passed-in function. When the parameter is not a function because there is no processing, if the parameter that is not a function is executed as a function, an error will naturally be reported. , so add processing to the parameters in the then function

then(onFullfilled, onRejected) {
    
    
    // 判断如果传入的参数类型不为function,就给它赋值为一个函数
+   onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
+   onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

    if (this.status === FULLFILLED) {
    
    
       onFullfilled(this.value);
    }

    if (this.status === REJECTED) {
    
    
       onRejected(this.value);
    }

    return new _Promise((resolve, reject) => {
    
    });
}

After modification, I executed the previous code again and found that no error was reported.

4. Implement asynchronous

So far, there is nothing special that can be seen in the code, which means that the code will be executed synchronously and normally. But in fact it is impossible to execute them all synchronously in order. As we all know, JavaScript has an event loop mechanism, which divides events into two categories: 同步任务 and 异步任务. Next, we need to a>异步任务 is processed, why? For example:

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    
    
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

// 应用到自己实现的上
console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,4,3

is explained in MDN. The operation of promise will be regarded as asynchronous execution. All promise are asynchronous and the same as setTimeout(action, 10) is particularly similar. Then we use ``setTimeout` to simulate asynchronous.

then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

    if (this.status === FULLFILLED) {
    
    
+       setTimeout(() => {
    
    
           	onFullfilled(this.value); 
+       });
    }

    if (this.status === REJECTED) {
    
    
+       setTimeout(() => {
    
    
			onRejected(this.value);
+       });
    }

    return new _Promise((resolve, reject) => {
    
    });
}

Re-execute the previous code and find that the output sequence has correctly output 1,2,3,4

5. Handle collection callbacks

According to the previous step, we can know thatpromise and its operations are asynchronous. So what happens if I also write asynchronous events in promise? If you understand事件循环, you should know it, but I’ll mention it here

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);

Use事件循环 to explain the execution process of the above code:

  1. Execute synchronization taskconsole.log(1);, output "1"
  2. new Promise()Execute immediately, execute the synchronous taskconsole.log(2); and output "2", encounter an asynchronous tasksetTimeout and add it to the macro task queue (asynchronous tasks are divided into macro tasks Tasks and microtasks, promise的回调 is a microtask)
  3. encountersp.then(), and adds its callback to the microtask queue
  4. Execute synchronization taskconsole.log(3); and output "3"
  5. The main thread execution stack is cleared to look for asynchronous task execution. It is found that there are both macro tasks and micro tasks, and the micro tasks are executed first.
  6. Execute microtaskthen callback, at this timepromise the status ispendingnot executed
  7. Execute synchronization taskconsole.log(4); and output "4"
  8. After the microtask is executed, the macrotask is executed, and the synchronization task is executedconsole.log(4); and "4" is output.
  9. Callresolve(5);, at this timepromise status changes, execute the corresponding callback, and output "5"

So the output is:1,2,3,4,5

Go to _promise` to view the execution results:

console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

found that the execution result output was one less 5, and 5 was printed by the callback of executing then, so it can be guessed that then was not executed. The execution in our then is based on status judgment, that is to say, only when the promise status is FULLFILLED or to see if it is a problemREJECTED will be executed. Print the execution resultsstatus

console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        console.log(p.status);
        resolve(5);
        console.log(p.status);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4,pending,fullfilled

Continue to use事件循环 to sort out the execution process:

  1. Execute synchronization taskconsole.log(1), output "1"
  2. new Promise()Execute immediately, perform synchronization taskconsole.log(2);, output "2"
  3. Encountered an asynchronous tasksetTimeoutAdd to macro task queue
  4. Encountered an asynchronous taskthen回调, added to the microtask queue
  5. Execute synchronization taskconsole.log(3);, and output "3"
  6. The main thread execution stack is cleared to look for asynchronous task execution. It is found that there are both macro tasks and micro tasks, and the micro tasks are executed first.
  7. Execute microtaskthen callback, at this timepromise the status ispendingno execution result
  8. After the microtask is executed, the macrotask is executed, and the synchronization task is executedconsole.log(4); and "4" is output.
  9. Executeconsole.log(p.status);, output "pending"
  10. 执行resolve(5);promiseChange in statusfullfilled
  11. Executeconsole.log(p.status);, output "fullfilled"

Observing the execution process, we can find that when the status of promise is pending, the then method implemented by ourselves is No corresponding processing was done. Maybe this is causing the problem of not being implemented. So what should we do when the status is pending?

then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
+   if (this.status === PENDING) {
    
    
        // TODO: 状态为pending时应该做什么
+   }

    if (this.status === FULLFILLED) {
    
    
       	setTimeout(() => {
    
    
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
    
    
       	setTimeout(() => {
    
    
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {
    
    });
}

Here we continue to understand the execution order. The then function is executed synchronously, and to obtain the result, you need to call resolve or reject. So how can we ensure that then方法在获取到结果后才执行呢?解决办法就是 collects callbacks`.

When the status ofpromise ispending, we first collect the callbacks and wait until execution resolve or When a>reject, take out the corresponding callback and execute it together.

1. Create an array collection callback. After all, there may be multiple callbacks.
class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        // 收集成功的回调
+       this.fullfilledCallbacks = [];
        // 收集失败的回调
+       this.rejectedCallbacks = [];

        try {
    
    
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
          	this.reject(error);
        }
	}
}
2. Collect callbacks in the then method
then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
    // 状态为pending时收集依赖
   	if (this.status === PENDING) {
    
    
+       this.fullfilledCallbacks.push(onFullfilled);
+       this.rejectedCallbacks.push(onRejected);
   	}

    if (this.status === FULLFILLED) {
    
    
       	setTimeout(() => {
    
    
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
    
    
       	setTimeout(() => {
    
    
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {
    
    });
}
3. Execute callbacks in resolve and reject methods

When executes resolve() or reject(), the corresponding saved callback array will be traversed (saved when executing then ) and pass the parameters into execution.

resolve(value) {
    
    
    if (this.status === PENDING) {
    
    
        this.status = FULLFILLED;
        this.value = value;
        // 执行收集的回调
+       this.fullfilledCallbacks.forEach(callback => callback(value));
    }
}

reject(reason) {
    
    
    if (this.status === PENDING) {
    
    
        this.status = REJECTED;
        this.value = reason;
        // 执行收集的回调
+       this.rejectedCallbacks.forEach(callback => callback(reason));
    }
}

The overall code is as follows:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
    
    
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
          	this.reject(error);
        }
	}
    resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
            this.status = FULLFILLED;
            this.value = value;
            this.fullfilledCallbacks.forEach(callback => callback(value));
        }
    }

    reject(reason) {
    
    
        if (this.status === PENDING) {
    
    
            this.status = REJECTED;
            this.value = reason;
            this.rejectedCallbacks.forEach(callback => callback(reason));
        }
    }
    then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        if (this.status === PENDING) {
    
    
            this.fullfilledCallbacks.push(onFullfilled);
            this.rejectedCallbacks.push(onRejected);
        }

        if (this.status === FULLFILLED) {
    
    
            setTimeout(() => {
    
    
                onFullfilled(this.value); 
            });
        }

        if (this.status === REJECTED) {
    
    
            setTimeout(() => {
    
    
                onRejected(this.value);
            });
        }

        return new _Promise((resolve, reject) => {
    
    });
    }
}

Executed the previously tested code again and found that the callback of the then function was triggered. But if you are careful, you can still find that after printing the promise status, the resolve is executed synchronously and the callback is triggered. This is obviously wrong. What we expect is to simulate asynchronous are executed asynchronously. So here we useresolve and rejectsetTimeout

resolve(value) {
    
    
    if (this.status === PENDING) {
    
    
+       setTimeout(() => {
    
    
           	this.status = FULLFILLED;
        	this.value = value;
        	this.fullfilledCallbacks.forEach(callback => callback(value)); 
+       });
    }
}

reject(reason) {
    
    
    if (this.status === PENDING) {
    
    
+       setTimeout(() => {
    
    
            this.status = REJECTED;
        	this.value = reason;
        	this.rejectedCallbacks.forEach(callback => callback(reason));
+       });
    }
}

Test the output result again and you will find that the output is consistent with the original one.

4. Test multiple executions of the then method

Nativepromise can be called multiple timesthen, and you can also test your own implementation

// 原生
const p = new Promise((resolve, reject) => {
    
    
    setTimeout(() => {
    
    
        resolve('success')
    }, 2000);
})
p.then(value => {
    
    
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

// 自己实现的
const p = new _Promise((resolve, reject) => {
    
    
    setTimeout(() => {
    
    
        resolve('success')
    }, 2000);
})
p.then(value => {
    
    
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

No problem, you’re basically done! the last one leftpromise链式调用

6. Implement chain calls

First, let’s use a simple example to explain what chain calls are.

class Person {
    
    
    constructor() {
    
    
        this.name = '';
    }
    setName(name) {
    
    
        this.name = name;
        return this;
    }
    sayHello() {
    
    
        console.log(`hello,我叫${
      
      this.name}`);
        return this;
    }
}
// 使用
let p = new Person();
p.setName('哈哈哈').sayHello(); // hello,我叫哈哈哈

The core of the chain call is the abovereturn this. When we call p.setName(), it will return its own instance, and there are two methods setName and sayHello on the instance, so it can always < /span> call it. .setName() or .sayHello()

Go back to our then method and you will find that one new _Promise() has been returned in advance. BecausePromiserequiresthen to return apromise. So this is why the then method can be called in a chain. I still don’t understand that I can take the above paragraph seriously immediately.

Extension: In the past, when Ajax was used to send requests, then callbacks also existed, and callback hell occurred due to infinite nested callbacks of then. The solution was to use Promise-based asyncandawaitSyntactic sugar

In nativePromise we use chain calls like this:

let p = new Promise((resolve, reject) => {
    
    
    resolve(1);
});
p.then(res => {
    
    
    console.log(res);
    return res + 1;
}).then(res => {
    
    
    console.log(res);
});
// 1,2

If you apply the same code to your own implementation_Promise, you will find that there is a problem, because ourthen method has not been perfected yet, and the returned There is nothing in a>method. _Promise. Then we will improve thisthen

1. First move the content to the returned Promise
then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        return new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(onFullfilled);
                this.rejectedCallbacks.push(onRejected);
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    onFullfilled(this.value); 
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    onRejected(this.value);
                });
            }
        });
    }
}
2. Encapsulate the function that handles the content returned by Promise
function resolvePromise(promise2, x, resolve, reject) {
    
    
    // 不能返回自身
    if (x === promise2) {
    
    
        throw Error('不能返回自身');
    }
    // 如果是Promise
    if (x instanceof _Promise) {
    
    
        // 状态为pending
        if (x.status === PENDING) {
    
    
            // 收集回调等待执行
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        // 状态为fullfilled,调用resolve执行
        } else if (x.status === FULLFILLED) {
    
    
            resolve(x.value);
        // 状态为rejected,调用reject执行
        } else {
    
    
            reject(x.value);
        }
    // 如果是thenable对象(具有then属性)
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    
    
        let then = null;
        try {
    
    
            // 有then属性,赋值
            then = x.then;
        } catch (error) {
    
    
            // 获取不到then报错就调用reject
            reject(error);
        }
        // 如果then是个函数,就以promise相同方式调用
        if (typeof then === 'function') {
    
    
			let called = false; // 避免多次调用
            try {
    
    
                then.call(
                    x,
                    res => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
    
    
                        // 防止多次调用
                         if (called) {
    
    
                            return;
                        }
                        called = true;
                        // 出错就调用reject
                        reject(error);
                    }
                )
            } catch (error) {
    
    
                // 防止多次调用
                if (called) {
    
    
                    return;
                }
                called = true;
                // 出错就调用reject
                reject(error);
            }
        } else {
    
    
            // 否则就是个正常值,执行调用resolve
            resolve(x);
        }
    // 否则直接调用resolve
    } else {
    
    
        resolve(x);
    }
}
3. Modify the logic in the then method
then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        let promise2 = new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }
	});
    return promise2;
}

Next, test: (just find an example)

// 原生
const p1 = new Promise((resolve, reject) => {
    
    
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    
    
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    
    
    console.log(res);
    return new Promise((resolve, reject) => {
    
    
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    
    
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => {
    
     }, err => {
    
    
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

// 自己实现的_Promise
const p1 = new _Promise((resolve, reject) => {
    
    
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    
    
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    
    
    console.log(res);
    return new _Promise((resolve, reject) => {
    
    
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    
    
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => {
    
     }, err => {
    
    
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

So far, I have implemented my own based on the nativePromise

Complete code:
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
    
    
    if (x === promise2) {
    
    
        throw Error('不能返回自身');
    }
    if (x instanceof _Promise) {
    
    
        if (x.status === PENDING) {
    
    
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        } else if (x.status === FULLFILLED) {
    
    
            resolve(x.value);
        } else {
    
    
            reject(x.value);
        }
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    
    
        let then = null;
        try {
    
    
            then = x.then;
        } catch (error) {
    
    
            reject(error);
        }
        if (typeof then === 'function') {
    
    
            let called = false;
            try {
    
    
                then.call(
                    x,
                    res => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        reject(error);
                    }
                )
            } catch (error) {
    
    
                if (called) {
    
    
                    return;
                }
                called = true;
                reject(error);
            }
        } else {
    
    
            resolve(x);
        }
    } else {
    
    
        resolve(x);
    }
}

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
    
    
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
            this.reject(error);
        }
    }
    resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
            setTimeout(() => {
    
    
                this.status = FULLFILLED;
                this.value = value;
                this.fullfilledCallbacks.forEach(callback => callback(value));
            })
        }
    }

    reject(reason) {
    
    
        if (this.status === PENDING) {
    
    
            setTimeout(() => {
    
    
                this.status = REJECTED;
                this.value = reason;
                this.rejectedCallbacks.forEach(callback => callback(reason));
            })

        }
    }

    then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

        let promise2 = new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(() => {
    
    
                    try {
    
    
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
    
    
                    try {
    
    
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }
        });
        return promise2;
    }
}

Reference for this article: https://juejin.cn/post/7043758954496655397

For more detailed and complete code (including comments), please refer to the above link

Guess you like

Origin blog.csdn.net/qq_43398736/article/details/126917836