Asynchronous solutions

There are two execution models of tasks in js: synchronous mode and asynchronous mode.

  • Synchronization mode: the next task B waits for the completion of the previous task A before executing. The execution order of tasks is consistent with the sorting order of tasks.

  • Asynchronous mode: each task has one or more callback functions. After the previous task A ends, the callback function of task A is executed instead of the next task B. The latter task B is executed before the end of task A. The execution order of tasks is inconsistent with the sorting order of tasks.

The implementation of asynchrony depends on some special syntax rules. On the whole, the asynchronous scheme has gone through the following four stages of evolution: callback function - > promise - > Generator - > async/await. Promise, Generator and async/await are new asynchronous solutions that have been slowly developed after ES2015 and have some disruptive features.

Callback function period

Event listening: the execution order of a task has nothing to do with the code writing order, only with whether or not the click event is triggered

Publish subscribe: the timing of task execution is closely related to the occurrence of an event.

 

Callback function: callback hell leads to the destruction of readability and maintainability

 Promise 

Tell me about Promise (three states and two processes)

The Promise object is a proxy object. It accepts the executor you pass in as an input parameter, allowing you to bind the success and failure of asynchronous tasks to the corresponding processing methods respectively. A Promise instance has three states:

• pending status, indicating in progress. This is an initial state after the Promise instance is created;
• completed (resolved) status, indicating successful completion. This is the state reached after we call resolve in the actuator;
• rejected status, indicating that the operation failed or was rejected. This is the status reached after we call reject in the actuator;
The state of Promise instance can be changed, but it can only be changed once. When our instance state is switched from pending to rejected, it can no longer be reversed to fully. Otherwise, the same is true. When the Promise status is resolved, the on fulfilled function in the then method input parameter will be triggered; When the state of Promise is rejected, the onrejected function of its corresponding then method input parameter will be triggered.

What are the common methods of Promise? What do they do?

Promise has the following methods:
• promise All (iterable): this method returns a new promise object. The promise object will be triggered successfully only when all the promise objects in the iterable parameter object are successful. Once any promise object in an iterable fails, the failure of the promise object will be triggered immediately.

var p1 = Promise.resolve('1 Contestant No');
var p2 = '2 Contestant No';
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "3 Contestant No");
}); 
Promise.all([p1, p2, p3]).then(values => { 
  console.log(values); //  ["1 Contestant No", "2 Contestant No", "3 Contestant No"]
});

Usage scenario: to perform an operation, you need to rely on the data requested from multiple interfaces, and there is no interdependent relationship between these interfaces. Promise All(), and it will not operate until all the interface requests are successful.

let promise1 = new Promise((resolve) => {
        setTimeout(() => {
            resolve('promise1 Operation successful');
            console.log('1')
        }, 3000);
    });
   
    let promise2 = new Promise((resolve) => {
        setTimeout(() => {
            resolve('promise1 Operation successful');
            console.log('2')
        }, 1000);
    });

    Promise.all([promise1, promise2]).then((result) => {
        console.log(result);
    });

• promise Race (iterable): when any child promise in the iterable parameter succeeds or fails, the parent promise will immediately use the success return value or failure details of the child promise as parameters to call the corresponding processing function bound by the parent promise and return the promise object.

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "1 Contestant No"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 50, "2 Contestant No"); 
});

// Here, because player 2 returns earlier, the return value shall be subject to player 2
Promise.race([p1, p2]).then(function(value) {
  console.log(value); //  "2 Contestant No"
});
let promise1 = new Promise((resolve) => {
        setTimeout(() => {
            resolve('promise1 Operation successful');
            console.log('1')
        }, 3000);
    });

    let promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('promise1 operation failed');
            console.log('2')
        }, 1000);
    });

    Promise.race([promise1, promise2])
        .then((result) => {
            console.log(result);
        })
        .catch((error) => {
            console.log(error);
        })

 

1s later, promise2 enters the rejected state. Because the state of an instance has changed, promise Race () is executed immediately, and it doesn't care if it changes in other instances.

  • Promise Reject (reason): returns a promise object in failed status, and passes the given failure information to the corresponding processing method
  • Promise Resolve (value): it returns a promise object, but the status of this object is determined by the value you pass in. There are two situations:
    • If an object with then method is passed in (we call it thenable object), the final state of the returned Promise object is determined by the then method execution
    • Otherwise, the returned Promise object will be in the state of completed, and the value here will be used as the input parameter of on fulfilled specified in the then method

Real problem analysis

The processing function in Promise is an asynchronous task

const promise = new Promise((resolve,reject) =>{
        console.log(1);
        resolve();
        console.log(2);
    })
    promise.then(()=>{
        console.log(3);
    })
    console.log(4);

The task passed in from the then method is an asynchronous task. The function of the call resolve() is to set the Promise status from pending to fully. This new status will let Promise know that "the task in my then method is ready for execution" - note that "it is ready for execution", rather than "it will be executed immediately". After all, as an asynchronous task, its basic accomplishment is to wait until the synchronous code is executed. Therefore, the output of the number 3 ranks last.

The state of a Promise object can only be changed once

const promise = new Promise((resolve,reject) =>{
        resolve('1st time resolve')
        console.log('resolve General logic after 1');
        reject('error')
        resolve('2nd time resolve');
        console.log('resolve General logic after 2');
    })
    promise.then((res)=>{
        console.log('then:',res);
    }).catch((err)=>{
        console.log('catch',err);
    })

In this code, the initial state of promise is pending. In the first line of the function body, we use resolve to set it to the fully completed state. After this switch is completed, all subsequent attempts to make further state switching will not take effect, so the subsequent reject and resolve will be ignored directly; It should be noted that we ignore the reject and resolve after the first resolve, rather than ignoring all the code behind it. So console The sentence "log" ("ordinary logic after resolve") can still be executed normally. As for why it is output before "then: the first resolve", the reason is the same as the previous question~

Promise value penetration

Promise.resolve(1)
  .then(Promise.resolve(2))
  .then(3)
  .then()
  .then(console.log)

The then method allows us to pass in two parameters: onFulfilled (handler in success state) and onRejected (handler in failure state).

You can pass both, or you can only pass the former or the latter. However, in any case, the input parameters of the then method can only be functions. If you want to give it some messy things, it will "turn its face and disown people".

Specifically, in our question, the first then method passed in a Promise object, and then said, "I don't know"; the second then method passed in a number, and then continued to say "I don't know"; the fourth one simply didn't wear anything, and then said "undefined, goodbye"; until the fifth parameter, a function was passed in, and then cried: "finally, I can handle it! ", so only the last input parameter takes effect.

During this process, we initially resolve the value and pass through one invalid then call after another, as if these then calls were transparent and nonexistent. Therefore, this situation is also vividly called "value penetration" of Promise.

Instance

There are now three requests, request A, request B, and request C. Request C shall take the data returned from request B as A parameter, and request B shall take the data returned from request A as A parameter.

Callback writing

$.ajax({
        success:function(res1){
            //------request B start----
            $.ajax({
                success:function(res2){
                    //----request C start---
                    $.ajax({
                        success:function(res3){
                        }
                    });
                    //---request C finish---
                }    
            });
            //------request B finish-----
        }
    });
    //------request A finish---------

promise writing

 

let promise = new Promise((resolve, reject) => {
        if (true) {
            //Call operation success method
            resolve('Operation successful');
        } else {
            //Call operation exception method
            reject('Abnormal operation');
        }
    });

    //then Processing operation succeeded, catch Processing operation exception
    promise.then(requestA)
        .then(requestB)
        .then(requestC)
        .catch(requestError);

    function requestA() {
        console.log('request A success');
        return 'Next is the request B';
    }

    function requestB(res) {
        console.log('Results of the previous step:' + res);
        console.log('request B success');
        return 'Next is the request C';
    }

    function requestC(res) {
        console.log('Results of the previous step:' + res);
        console.log('request C success');
    }

    function requestError() {
        console.log('request was aborted');
    }

 

 

 

Tags: Interview

Posted by Azeryk on Mon, 30 May 2022 23:40:21 +0530