Promise standard

1. Promise

There are many Promise specifications, such as Promise/A, Promise/B, Promise/D, and an upgraded version of Promise/A, Promise/A+. The Promise/A+ specification is used in ES6. Promises/A+ Promises: Promises/A+ Promises: Promises/A+ Promises: Promises/A+ Promises

2. Interpretation of Promise standards

1. The current state of a promise can only be one of pending, depressing and Rejected. The state change can only be pending to depressing or pending to Rejected, and the state change is irreversible. 2. The promise’s then method accepts two optional parameters, representing the promise (onFulfilled, onRejected) when the promise state changes. The then method returns a promise. The then method can be called multiple times by the same promise.

The use of the Promise

const promise = new Promise((resolve) => {
    setTimeout(()=> {
        resolve(1);
    }, 2000);
});
promise.then(a=> alert(a));
Copy the code

An interpretation of the above code:

  • The constructor accepts oneexecutorExecute the function immediately;
  • executorExecute the function immediately to receive oneresolveFunctions;
  • promiseThe object’sthenThe method binding status becomesfulfilledThe callback of,thenMethods can also be called registration functions. Take your time, explained below);
  • resolveWhen a function is called, it triggers a callback registered in the THEN methodpromise);

With everyone can use, so, let’s implement a most simple promise

Make simple promises

Take a look at the code below

function MyPromise(executor){
    var self = this;
    this.status = "pending";
    this.data = "";
    this.resolveArr = [];
    this.rejectArr = [];
    functionResolve (data){self.data = data self.data = datasetTimeout(function(){ self.resolveArr.forEach((fn)=>{ fn(data); }); }, 0); }function reject(){}

    try{
        executor(resolve,reject)
    }catch(err){
        reject(err)
    }
}

MyPromise.prototype.then = function(resolveFn,rejectFn){
    this.resolveArr.push(resolveFn);
    this.rejectArr.push(rejectFn);
}
Copy the code

Let’s explain the above code

  • MyPromise takes an executor as an argument and executes it on instantiation; This executor accepts resolve and reject (comment: same as the native Promise(function(resolve,reject){}));

  • The resolve and reject arguments are defined as a successful and a failed callback, consistent with the original Promise. Resolve (resolve); What does resolve do inside? Resolve does only one thing, traversing the resolveArr defined in the body of the function, then executing each item and passing in the data argument.

ResolveArr (resolveArr, resolveArr, resolveArr, resolveArr, resolveArr, resolveArr);

  • One mounted on the prototype was found at the very end of the codethenMethod that uses this array (as mentioned earlier in this article,thenMethod can be understood as the registration method, how to register method? It was herethenMethods take arguments of two function types (and native ones)PromiseKeep in line); And add the first parameter toresolveArrThe second parameter is added torejectArrIn the. That completes the registration!

Having said that, let’s test if it works:

var test = new MyPromise(function(resolve){
    setTimeout(()=>{
        resolve("Test"); }, 1000); }); test.then((data)=>{ console.log(data); });Copy the code

The running results are as follows:

Again, keep in mind one sentence,resolveWhen a function is called, it triggers a callback registered in the then method, as illustrated in the above example.

After understanding the above case, let’s do optimization slowly

Optimization of a

As mentioned above, the then method returns a promise. The then method can be called multiple times by the same promise. Rewrite the then method:

MyPromise.prototype.then = function(onResolved,onRejected){
    this.resolveArr.push(onResolved);
    this.rejectArr.push(onRejected);
    return this;
}
Copy the code

Just return this at the end of the then. Problem: All functions registered with the THEN method will receive the same value, which is obviously not acceptable and will be optimized later

Optimization of two

As mentioned above, onepromiseThe current state of thepending,fulfilledandrejectedOne of three. State change can only bependingtofulfilledorpendingtorejected. Let’s change what’s inside the functionresolveMethods:

function resolve(data){
  if(self.status==="pending"){
    self.status = "fulfilled";
    setTimeout(function(){ self.resolveArr.forEach((fn)=>{ fn(data); }); }}}, 0)Copy the code

This is a big pity. You only need to judge whether the state is pending before traversing the resolveArr. If so, change the state to fulfilled, and then perform the traversal.

In view of the problems raised by the optimization, to do further optimization

Optimize the above code according to the Promise /A+ specification

The standard reading of the Promise /A+ specification at the beginning of this article mentions (thenMethod returns apromise), then we givethenMethod returns a promise to overwritethenMethods:

MyPromise.prototype.then = function(onResolved,onRejected){
    var self = this;
    return new MyPromise(function(resolve,reject){
        self.resolveArr.push(function(){
            var x = onResolved(self.data);
            if(x instanceof MyPromise){// WhenthenIf a MyPromise is returned, resove will be suspended in the resolveArr queue of the MyPromise, waiting for the MyPromise to execute the corresponding resolve. x.then(resolve,reject) }else{/ / whenthenIf the return value of MyPromise is not a MyPromise, execute resolve and skip to the next onethenProcessing; resolve(x); }}); }); }Copy the code

Again:resolveThe callback function registered in the THEN method is triggered when the function is called

Question: How many MyPromise instances are involved here? Answer: two or three; Why is that? Var x = onResolved(self.data) and determine if x is MyPromise. As we can see from this code, x is the result of onResolved. This is the function registered when the then method is called; When x is also an instance of MyPromise, there are three MyPromise instances involved: the current instance (this),the instance returned by the then method, and the instance returned by the registration function (x).

Analysis of the

For convenience, I call the current instance A and the one returned by the then method B; When A calls the then method, it returns B, and when B initialses, it adds an anonymous function (AResolveFn) to A’s resolveArr. Resolve in A will execute AResolveFn. Will execute the onResolved method we passed in to then and call the result x.

Case 1: when x is not MyPromise

As you can see from the code, resolve(x) is executed directly in this case; Resolve (‘ resolve ‘, ‘then’, ‘then’, ‘then’, ‘then’); Testing:

var test = new MyPromise(function(resolve){
    setTimeout(()=>{
        resolve("Test"); }, 1000); }); test.then((data)=>{ console.log(data);return "The test 2"
}).then((data)=>{
    console.log(data);
});
Copy the code

Test results:

Case two: when x is MyPromise

From the code, when x is MyPromise, B’s resolve is directly used as x’s registration method. If x’s resolve is executed, x’s then resolve will be triggered, and B’s then resolve will be triggered. The process is as follows :A resolve > A then resolve > X then resolve > B then resolve, so as to achieve asynchronous chain passing;

Testing:

var test = new MyPromise(function(resolve){
    setTimeout(()=>{
        resolve("Test"); }, 1000); }); test.then((data)=>{ console.log(data);return new MyPromise(function(resolve){
        setTimeout(()=>{
            resolve("The test 2");
        },1000)
    })
}).then((data)=>{
    console.log(data);
});
Copy the code

Test results:

Optimization for state changes

All of these are normal conditions; That is, when you register a function with then, it’s always in the pending state; This is very depressing. However, for some special scenarios, when you use the then method, the state will be fulfilled, which is very depressing, like this:

var test = new MyPromise(function(resolve,reject){
    setTimeout(function(){
        resolve("test")
    },1000);
});

setTimeout(function(){
    test.then(function(data){ console.log(data); }); }, 2000).Copy the code

In this case, resolveArr must be an empty array when the resolve method is called without registering the then method. This state is very depressing. It is impossible to say that when you register with the THEN method, the implementation side will be given to you, which will also violate the standard of Promise.

Optimized THEN method

MyPromise.prototype.then = function(onResolved,onRejected){
    var self = this;
    if(self.status==="fulfilled") {return new MyPromise(function(resolve,reject){
            var x = onResolved(self.data);
            if(x instanceof MyPromise){
                x.then(resolve,reject)
            }else{ resolve(x); }}); }if(self.status==="pending") {return new MyPromise(function(resolve,reject){
            self.resolveArr.push(function(){
                var x = onResolved(self.data);
                if(x instanceof MyPromise){
                    x.then(resolve,reject)
                }else{ resolve(x); }}); }); }}Copy the code

This is a big pity. When the state is fulfilled, resolve will not be performed and the then registered function will not be triggered. Here, skip this layer and go straight to onResolved and continue. The above principle is understood, here understanding should not be particularly difficult, here will not do too much explanation, it is not clear if the message to me!

That’s pretty much it, but I’m going to add a promise static method

Promise static method

Promise there are a lot of static method, in all, as Promise.. Promise. Race, then we use the above his own implementation of MyPromise to add a static method to try:

MyPromise.all = function(promiseArr){
    return new MyPromise(function(resolve){
        var length = promiseArr.length;
        var resultIndex = 0;
        var resultArr = [];
        promiseArr.forEach((promise)=>{
            promise.then(function(data){
                resultArr.push(data);
                resultIndex++;
                if(resultIndex===length){ resolve(resultArr); }}); }); }); }Copy the code

If the principle is understood, it is not difficult to implement it. Here, I will not explain it. Let’s test it directly:

var test1 = new MyPromise(function(resolve){
    setTimeout(function(){
        resolve("test1")}, 1000)}); vartest2 = new MyPromise(function(resolve){
    setTimeout(function(){
        resolve("test2")}, 1500)}); vartest3 = new MyPromise(function(resolve){
    setTimeout(function(){
        resolve("test3")}, 1200)});Copy the code

The results are as follows:

conclusion

About the promise content here is about the same, usually also relatively few published articles, always afraid of their summary is not good, I hope to bring you help!