Asynchronous and promise

Time:2020-10-31

introduction

In 16 years, I shared a promise in the company. I still remember that it was the first time to share, which was quite nervous. At that time, I mainly shared the use and basic principle of promise, and then I shared it with students from wireless department again.
Looking back, I don’t think it’s perfect, because my implementation method at that time was similar to the implementation of the simplified Q library, and I didn’t fully follow the promise / A + specification. After such a long period of learning and accumulation, to explain their new understanding.

The cause of promise

Before promise, when multiple dependent asynchronous operations are written out, nesting will appear. The so-called callback region is inconvenient to maintain in projects that need cooperation. Asynchronous operations can’t directly catch exceptions and need to be handled in callbacks. There are many shortcomings. Then, long-term optimization is started, such as Q, Bluebird, and defer in JQ, Later, the ES6 standard implemented promise, but its chained writing method is still not beautiful. In order to make the code more elegant, it can visually synchronize the command-based writing code. With the CO of TJ God and the generator, it seems perfect. However, in order to be elegant, it needs to introduce the co library, which is a little expensive. Later, the ES7 standard was directly implemented, namely the so-called async and await syntax sugar

Promise definition

Now let’s get to the point. What is promise? In short, promise stands for commitment, and the technical term stands for the end result of an asynchronous operation.
From the code level, promise is a class that can be used to create instances. Each instance encapsulates some methods, and maintains some states and values. By using these States, values and methods, the commitment in the real process can be expressed in code.

Promise use

Promise mainly provides methods such as then, catch, all, race, resolve and reject. How to use these methods will not be described in detail, because it takes up a long time and many other blogs have repeatedly described them. It is recommended to explain the usage of API in the introduction of Ruan Yifeng ES6, which is detailed and comprehensive.
For specific applications, because the project in work is based on Vue technology stack, promise will be used to operate asynchronously in combination with Axios. In addition, m station is based on PWA. Promise is involved in the event processing of service worker declaration cycle, and some are used when writing node tools. Promise is used to encapsulate asynchronous API operation callbacks, Thus, the asynchronous API callback logic is directly put into the then method for processing.

Realization of promise

The codes based on promise / A + specification can be unified with each other. Although the code forms may be different, the principles are similar.
First of all, promise constructors need some states and methods, because these maintained States and values are needed when executing instance then logic. What is highlighted is that promise’s state machine is unidirectional and the state is unidirectional.
The state transition can only be pending – > fulfilled or pending – > rejected.

//Constructor initialization logic
     Let that = this; // cache this
    //The default state is pending
    that.status = 'pending';
    //This variable contains the result of this promise
    that.value = undefined;
    //Store all successful callback functions
    that.onResolvedCallbacks = [];
    //It stores all the failed callback functions
    that.onRejectedCallbacks = [];

The internal resolve and reject logic is as follows: change the state of the state machine and trigger the execution of the commitment logic

function resolve(value) {
        //Change the state to execute the successful callback logic of then registration
        if (that.status == 'pending') {
            //Solve the problem of resolve new promise
            if(value!=null &&value.then&&typeof value.then == 'function'){
              return value.then(resolve,reject);
            }
            that.status = 'fulfilled';
            that.value = value;
            that.onResolvedCallbacks.forEach(item=>item(that.value));
        }
    }
     function reject(reason) {
            //Change the state to execute the failed callback logic registered by then or the failure logic registered in catch
            if (that.status == 'pending') {
                that.status = 'rejected';
                that.value = reason;
                that.onRejectedCallbacks.forEach(item=>item(that.value));
            }
        }

The initialization logic has been described above. Next, we will focus on the most frequently used then method. The implementation of the compact version is shown below

PPromise.prototype.then = function (onFulfilled, onReject) {
    //If the logic of success and failure is not passed, the value will be passed through to the next then method
     onFulfilled = isFunction(onFulfilled) ?onFulfilled:val =>val;
     onReject = isFunction(onReject) ?onReject:reason => {throw reason;}
     let self = this,promise2;
     switch (self.status){
         case 'fulfilled':
             promise2 = new Promise((resolve,reject) =>{
                 let x = onFulfilled(self.value);
                 if(x instanceof Promise){
                    //Then logic is executed recursively until internal then is executed, and outer PROMISE2 is resolved
                     x.then(resolve,reject)
                 }else{
                     resolve(x);
                 }
             });
             break
         case 'rejected':
             promise2 = new Promise((resolve,reject) =>{
                 let x = onReject(self.value);
                 if(x instanceof Promise){
                     x.then(resolve,reject)
                 }else{
                     resolve(x);
                 }
             })
             break
         case 'pending':
             promise2 = new Promise((resolve,reject) =>{
                 self.onResolvedCallbacks.push(function(){
                     let x = onFulfilled(self.value);
                     if(x instanceof Promise){
                         x.then(resolve,reject)
                     }else{
                         resolve(x);
                     }
                 });
                 self.onRejectedCallbacks.push(function(){
                     let x = onReject(self.value);
                     if(x instanceof Promise){
                         x.then(resolve,reject)
                     }else{
                         resolve(x);
                     }
                 });
             });
     }
     return promise2;
 }

All method implementation

function sentry(times,cb){
  let result = [],count=0;
  return function(i,data){
    result[i] = data;
    if(++count==times){
      cb(result);
    }
  }
}
Promise.all = function(promises){
 return new Promise((resolve,reject) => {
   //The purpose of using the closure mechanism is to determine whether the promises are executed completely
   let done = sentry(promises.length,resolve);
   for(let i=0;i<promises.length;i++){
     promises[i].then(data =>{
       done(i,data);
     },reject);
   }
 });
}

Resolve implementation

Promise.resolve = function(value){
  return new Promise(function(resolve){
    resolve(value);
  });
}

Race implementation

Promise.race = function(promises){
  return new Promise((resolve,reject) =>{
    for(let i=0;i<promises.length;i++){
      promises[i].then(resolve,reject);
    }
  });
}

Promise source code of their own implementation

Asynchronous elegant writing

Asynchronous operation is transformed into promise after promise, and elegant writing method is realized by combining async

let Promise = require('bluebird');
let readFile = Promise.promisify(require('fs').readFile);
async function read() {
  let a = await readFile('./1.txt','utf8');
  let b = await readFile('./2.txt','utf8');
  let c = await readFile('./3.txt','utf8');
  console.log(c);
  return 'ok';
}

read().then(data => {
  console.log(data);
});

summary

Everything is not achieved overnight, but has a development process to gradually become perfect. I will sit down and record my study and add some personal thinking. If you have any questions or mistakes in this article, you are welcome to make an exchange.

Reference link
https://promisesaplus.com/
https://segmentfault.com/a/11…

Recommended Today

Array of algorithms — sum of three numbers

Sum of three numbers difficultysecondary Here is an array of N integersnums, judgmentnumsAre there three elements a, B, C in a such that a + B + C = 0? Please find all triples that satisfy the condition and do not repeat.be careful:The answer cannot contain duplicate triples. Example:Given array nums = [- 1, 0, […]