Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
One, foreword
In the previous article, I translated and understood the whole Promise A+ specification;
At the beginning of this article, will be based on the Promise A+ specification, on our simple version of the Promise source code for functional improvement;
This article will implement Promise’s support for asynchronous operations;
Two, the previous review
In the first few articles, combined with the use of the Promise basic function introduction and simple analysis, handwritten a simple version of the Promise source code, mainly covering the following points:
- Promise is a class;
- When a promise is used, the executor executor is passed in and executed immediately;
- The Executor parameters are two functions that describe the state of a Promise instance;
- Resolve indicates success, and a value can be passed.
- Reject indicates failure. You can pass in a reason.
- Each Promise instance has a THEN method;
- Once a promise state has occurred, it cannot be changed.
- Promise has three states: a success state, a failure state, and a wait state (default).
Brief version of the source code is as follows:
const PENDING = 'PENDING'; / / wait state
const DULFILLED = 'DULFILLED'; / / success
const REJECTED = 'REJECTED'; / / failure mode
class Promise{
// The executor executor function is passed in when instantiated through a new Promise
constructor(executor){
this.value = undefined; // Save the reason for success, which will be passed in when ondepressing is called in then
this.reason = undefined; // Save the reason for the failure, which will be passed in when ondepressing is called in then
this.state = PENDING; // Promise state, default wait state
// Reslove succeeds, reject fails, and executor is passed
const reslove = (value) = >{
// Wait state --> Success state
if(this.state === PENDING){
this.value = value
this.state = DULFILLED; }}const reject = (reason) = >{
// Wait state --> failed state
if(this.state === PENDING){
this.reason = reason
this.state = REJECTED; }}// Execute the executor executor function immediately, using the try... catch... To catch exceptions;
try{
executor(reslove, reject);
}catch(e){
reject(e) Reject (reject) reject (reject}}// Define the then method: onFulfilled and onRejected;
// According to the Promise state, perform onFulfilled or onRejected;
then(onFulfilled, onRejected){
// Call ondepressing and pass in success value
if(this.state === DULFILLED){
onFulfilled(this.value)
}
// In failed state, execute onRejected and pass in failed reason
if(this.state === REJECTED){
onRejected(this.reason)
}
}
}
module.exports = Promise;
Copy the code
Third, ask questions
One of the main uses of Promise is to handle asynchronous operations, allowing developers to use synchronous programming to handle asynchronous operations, which can better solve/avoid callback hell than the previous callback method, and at the same time reverse control.
1. Test the native Promise
Perform asynchronous operations using native Promises:
let promise = new Promise((resolve, reject) = >{
setTimeout(() = >{
resolve('ok');
}, 1000)
})
promise.then((value) = >{
console.log('success', value)
},(reson) = >{
console.log('err',reson)
})
// success ok
Copy the code
2. Test handwritten promises
// Introduce handwritten promise.js
let promise = new Promise((resolve, reject) = >{
setTimeout(() = >{
resolve('ok');
}, 1000)
})
promise.then((value) = >{
console.log('success', value)
},(reson) = >{
console.log('err',reson)
})
Copy the code
The implementation result will not output any content. That is, the successful callback onFulfilled and the failure callback onRejected in then are not executed.
3. Problem analysis
Analysis of execution process:
- When the new Promise completes, the executor executor function is immediately executed and the timer is started.
- Promise. then is executed. The current PROMISE instance state is pending and no operation is performed.
- 1 second later, the definer callback executes, calling resolve to update the current PROMISE instance state to a successful state;
Cause of the problem:
- Reslove is called after the timer is 1 second, and then has been executed.
- Therefore, the current promise source code does not support asynchronous operations, need to achieve support for asynchronous operations;
4. Solutions
- Use queues to collect callbacks from the then method first.
- When the resolve or REJECT status is updated, the corresponding callback function can be executed.
This “collect first, execute later” function is in line with the subscription publishing mode;
Implement Promise’s support for asynchronous operations
1. Event subscription: Collect callback functions
- When a Promise performs an asynchronous operation, the state is PENDING;
- At this point, two queues (arrays) are required to collect the success/failure callback separately;
class Promise{
constructor(executor){
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = []; // Collection success callback
this.onRejectedCallbacks = []; // Collect failed callback
// ...
}
then(onFulfilled, onRejected){
// Collect success/failure callback when performing asynchronous operation
if(this.state === PENDING){
this.onResolvedCallbacks.push(() = >{
onFulfilled(this.value) / / the incoming value
})
this.onRejectedCallbacks.push(() = >{
onRejected(this.value) / / the incoming value})}// ...}}Copy the code
This completes the event subscription operation for the success/failure callback function;
2. Event publishing: Perform callback processing based on state
When the resolve or reject functions in a Promise are called, the corresponding callback processing is performed based on the state:
class Promise{
constructor(executor){
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const reslove = (value) = >{
if(this.state === PENDING){
this.value = value
this.state = DULFILLED;
// Event publish operation
this.onResolvedCallbacks.forEach(fn= >fn())
}
}
const reject = (reason) = >{
if(this.state === PENDING){
this.reason = reason
this.state = REJECTED;
// Event publish operation
this.onRejectedCallbacks.forEach(fn= >fn())
}
}
// ...
}
// ...
}
Copy the code
This is equivalent to event publishing in subscription publishing mode;
3. Test support for asynchronous operations
let promise = new Promise((resolve, reject) = >{
setTimeout(() = >{
resolve('ok');
}, 1000)
})
promise.then((value) = >{
console.log('success', value)
},(reson) = >{
console.log('err',reson)
})
// success ok
Copy the code
Five, the end
This article mainly implemented Promise’s support for asynchronous operations, mainly involving the following points:
- Test Promise’s support for asynchronous operations;
- Analyze current Promise code issues and solutions;
- Use publish and subscribe idea to support asynchronous operation.
- Promise tests for asynchronous operations;
Next, chain calls that implement promises;