I’ll make a Promise to you after a certain amount of time.
ES6 uses the Promise/A+ specification. Before implementing the Promise, you need to know the Promise/A+ specification (promisesaplus.com/).
We can write A simple Promise library based on the Promise/A+ specification.
Each step is as detailed as possible, so the code is very long and verbose.
1. Basic methods to implement promises
-
Promise is a class that passes an Executor function with two arguments: resolve and reject. Call resolve for success, reject for failure
-
Promise has three states: the default state is pending, successful Resolved, and Failed
Using the example
let Promise = require('./Promise'); // Promise is a class that passes an executor function, which we call an execution function. This function takes resolve and reject, which are also functions. A call to resolve means success, and a call to reject means failurelet promise = new Promise(function(resolve,reject){// Call pending resolve(resolve,reject){'ok');
reject('faild');
});
// thenIs a prototypical method that accepts two arguments, a successful callback and a failed callback promise.then(function(data){// Resolve executes successfully, reject executes failed console.log(data); },function(err){
console.log(err);
});Copy the code
Implement the corresponding Promise library code
functionPromise(executor) {// Promise needs to receive an executor functionlet self = this;
self.status = 'pending'; // Default is pending state self.value = undefined; Self. reason = undefined; // Cause of failurefunctionResolve (value) {// Why is resolve successfulif(self.status === 'pending'Self. value = value; self.value = value; // Save the reason for success self.status ='resolved'; // Change status to successful state}}functionReject (reason) {// Reject is passed inif(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected'; } } try { executor(resolve, reject); Resolve and reject} catch (e) {// If the executor executes an exception, the promise is a reject(e); / /}}thenTo pass in a successful callback and a failed callback promise.prototype.then =function(onFufilled,onRejected){
letself = this; // Call the successful callback if it succeeds and pass in the successful valueif(self.status === 'resolved'){
onFufilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = PromiseCopy the code
2. Asynchronous Promise
Asynchronous code can be written internally within a New Promise, and the resulting instance can be then multiple times
-
Use two arrays to store successful and failed callbacks and execute them when called
Using the example
let Promise = require('./Promise');
let promise = new Promise(function(resolve,reject){
setTimeout(function(){
resolve('ok'); }, 1000)}); / / when callingthenWhile the possible state is still pending, we need to set thethenThe callback functions in the resolve or reject call are reserved and promise.then(function(data){
console.log(data);
},function(err){
console.log(err);
});
promise.then(function(data){
console.log(data);
},function(err){
console.log(err);
});Copy the code
Implement the corresponding Promise library code
function Promise(executor) {
self.status = 'pending'; self.value = undefined; self.reason = undefined; + self.onResolvedCallbacks = []; + self.onrejectedCallbacks = []; // Where the failed callback is storedfunction resolve(value) {
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved'; + / / in turn perform the success callback, the self. The onResolvedCallbacks. ForEach (item = > item ()); }}function reject(reason) {
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected'; + / / failed to perform in the callback, the self. The onRejectedCallbacks. ForEach (item = > item ()); } } } Promise.prototype.then =function(onFufilled,onRejected){
if(self.status === 'rejected'){
onRejected(self.reason);
}
+ if(self.status === 'pending') {+ / / if it is waiting for the state, success and failure of the callback on the array + self. OnResolvedCallbacks. Push (function(){ + onFufilled(self.value); +}); + self.onRejectedCallbacks.push(function(){ + onRejected(self.reason); +}); +}}Copy the code
3.Promise chain call
-
If the current promise is already in a successful callback and an exception occurs to return this, the current promise state cannot be changed to the failure stage! So promise implements the chain call, and instead of returning this, returns a new Promise.
-
Executing a callback
-
If a normal value is returned, the result is passed to the next successful callback for then
-
If an error occurs, it will be caught by the next failed callback for then
-
If you return a promise and see if that promise succeeds or fails, then is called the next time
So write a resolvePromise method, the most important method in promises, that resolves the result returned by THEN
-
-
Some people might succeed and fail and call at the same time, but if you call both of them, the one that’s called with the first one is not allowed to call at the same time.
Using the example
promise.then(function(data){
throw Error('Wrong'); // Now that the promise has succeeded, it won't fail againreturn 'renee'
}).then(null,function(err){// How can we fail if the same promise is returned? So you must return a new promise console.log(err); })Copy the code
Implement the corresponding Promise library code
Promise.prototype.then = function(onFufilled,onRejected){
let self = this;
+ letpromise2; / / promise2 forthen// Call the successful callback if it succeeds and pass in the successful valueif(self.status === 'resolved'){
- onFufilled(self.value);
+ promise2 = new Promise(function(resolve,reject){+ try{+ // If an exception occurs, set the promise2 state to the failed state +letx = onFufilled(self.value); + // write a method resolvePromise, Is to parse the return value, through analyzing the status of let promise2 into success or failure states + resolvePromise (promise2, x, resolve, reject); + }catch(e){ + reject(e); +} +})}if(self.status === 'rejected'){
- onRejected(self.reason);
+ promise2 = new Promise(function(resolve,reject){
+ try{
+ let x = onRejected(self.reason);
+ resolvePromise(promise2,x,resolve,reject);
+ }catch(e){
+ reject(e)
+ }
+ })
}
if(self.status === 'pending'){
+ promise2 = new Promise(function(resolve,reject){
self.onResolvedCallbacks.push(function(){
- onFufilled(self.value);
+ try{
+ letx = onFufilled(self.value); + resolvePromise(promise2,x,resolve,reject) + }catch(e){ + reject(e); +} +})}); self.onRejectedCallbacks.push(function(){
- onRejected(self.reason);
+ try{
+ letx = onRejected(self.reason); + resolvePromise(promise2,x,resolve,reject) + }catch(e){ + reject(e); +}}); + +})}return promise2;
}Copy the code
functionResolvePromise (promise2, x, resolve, reject) {//x is the result returned if the promise andthenThe return promise is the same, is not scientific, to report an errorif(promise2===x){
return reject(new Error('Circular reference'))}if(x! ==null&&(typeof x ==='object'|| typeof x === 'function')) {letcalled; // whether the call succeeded or failed try{let then=x.then; / / ifthenIt's a function, and it says promise, and we're going to make the promise performif(typeof then= = ='function'){
then.call(x,function(y){
if(called)return; // If called directlyreturn
called=true; // Resolve if the result of resolve is still a promise.function(err){
if(called) return;
called=true;
reject(err)
})
}elseResolve (x)}}catch(e){resolve(x)}}catch(e){if(called) return;
called=true; reject(e); }}elseResolve (x); }}Copy the code
4. Value penetration
-
Then functions can be defined in the specification without passing arguments, which by default passes the result of success and the result of failure down
Using the example
promise.then().then().then(function(data){
console.log(data)
})Copy the code
Implement the corresponding Promise library code
Promise.prototype.then = function(onFufilled, onRejected) {// Fail and success do not pass to a function by default + onFufilled = typeof onFufilled ==='function'? onFufilled:function(value){
+ return value
+ }
+ onRejected = typeof onRejected === 'function'? onRejected:function(err){
+ throw err
+ }Copy the code
5. Test
You can also test the implementation promise specification by installing a plug-in.
NPM (CNPM) i-g Promises - apl-tests Promises - apl-testsCopy the code