Introduction and basic usage of Promise

Asynchronous call

asynchronous

The execution environment of JavaScript is single thread.

The so-called single thread refers to that there is only one thread in the JS engine responsible for interpreting and executing JavaScript code, that is, only one task can be completed at a time, and the next task can be executed only after this task is completed, which will "block" other tasks. This task can be called the main thread.

Asynchronous mode can perform multiple tasks together.

Common asynchronous modes are as follows:

  • timer

  • Interface call

  • Event function

In today's article, we will focus on interface calls. In the interface call, we will focus on Promise.

How the interface is called

The common interface calling methods in js are as follows:

  • Native ajax
  • ajax based on jQuery
  • Fetch
  • Promise
  • axios

Dependency analysis of multiple asynchronous calls

  • The result of multiple asynchronous calls, the order may be out of sync.

  • The results of asynchronous calls need to be nested if there is a dependency.

In ES5, when multiple nested callbacks are used, it will lead to too many code levels, which is difficult to maintain and redevelop, and it will lead to the problem of callback hell. Promise in ES6 can solve these two problems.

Promise overview

Promise introduction and advantages

Promise in ES6 is a scheme of asynchronous programming. Syntactically, promise is an object that can get messages for asynchronous operations.

Promise object, which can express asynchronous operations in a synchronous process. The main advantages of using promise are as follows:

  • It can solve the problem of callback hell well (avoiding the nested callback functions).

  • The grammar is very concise. The Promise object provides a concise API that makes it easier to control asynchronous operations.

An example of a callback to hell

Suppose that buying food, cooking and washing dishes are all asynchronous.

But in the real scene, the actual operation process is: after the success of buying vegetables, you can start cooking. Only after the cooking is successful can we start to wash dishes. This involves multiple nested calls, that is, callback hell.

Basic usage of Promise

(1) Use new to instantiate a Promise object and pass a parameter in the constructor of Promise. This parameter is a function that handles asynchronous tasks.

(2) And two parameters are passed in: resolve and reject, which represent the callback function after the asynchronous execution succeeds and the callback function after the asynchronous execution fails;

(3) The return result is processed through promise.then(). p here refers to the Promise instance.

Code examples are as follows:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            // Step 1: interface encapsulation of model layer
            const promise = new Promise((resolve, reject) => {
                // Do asynchronous tasks here (such as ajax request interface). The timer is temporarily used here.)
                setTimeout(function() {
                    var data = { retCode: 0, msg: 'qianguyihao' }; // Data returned by interface
                    if (data.retCode == 0) {
                        // Called when the interface request succeeds
                        resolve(data);
                    } else {
                        // Called when an interface request fails
                        reject({ retCode: -1, msg: 'network error' });
                    }
                }, 100);
            });

            // Step 2: interface call of business layer. The data here is from resolve and reject, which is the data obtained from the interface
            promise.then(data => {
                // Get normal results from resolve
                console.log(data);
            }).catch(data => {
                // Get exception results from reject
                console.log(data);
            });
        </script>
    </body>
</html>

In the above code, when the value of data.retCode returned from the interface is different, you may choose resolve or reject, which is determined by your own business.

Three states of promise object

  • Initialization state (waiting state): pending

  • Success status: fully filled

  • Failure status: rejected

(1) When new Promise() is executed, the state of promise object will be initialized to pending, which is the initialization state. New promise () is a line of code. The contents in brackets are executed synchronously. A function is defined in parentheses and has two parameters: resolve and reject. As follows:

  • If the request succeeds, resolve() is executed, and the promise status is automatically changed to fully filled.

  • If the request fails, execute reject(), and the project status will be automatically changed to rejected

(2) promise.then() method, there are two parameters in parentheses, which respectively represent two functions: function1 and function2:

  • If the promise status is full filled (meaning: if the request succeeds), the content in function1 will be executed

  • If the project status is rejected (that is, if the request fails), the content in function2 is executed

In addition, two methods, resolve() and reject(), can pass parameters to promise.then().

The complete code is as follows:

    let promise = new Promise((resolve, reject) => {
        //After entering, the status is pending
        console.log('111');  //This line of code is synchronized
        //Start to perform asynchronous operation (start here, write asynchronous code, such as ajax requestor to start timer)
        if (Asynchronous ajax Request successful) {
            console.log('333');
            resolve('haha');//If the request succeeds, write resolve(), and the promise status will be automatically changed to full filled
        } else {
            reject('555');//If the request fails, write reject(), and the project status will be automatically changed to rejected
        }
    })
    console.log('222');

    //Call then() of promise
    promise.then((successMsg) => {
            //If promise is full filled, execute the code here
            console.log(successMsg, 'Succeed');
        }
        , (errorMsg) => {
            //If the project status is rejected, execute the code here
            console.log(errorMsg, 'failed');

        }
    )

Handle multiple Ajax requests (chained calls) based on Promise [important]

In actual development, we often need to request multiple interfaces at the same time. For example, after requesting the data data1 of interface 1, you need to continue to request interface 2 and get data2 according to the data of data1, and then continue to request interface 3 according to the data of data2.

This scenario is actually a multi-layer nested call of the interface. With promise, we can write multiple nested calls in a linear way, which is very elegant.

That is to say, Promise can improve the original multi-level nested call to chain call.

Code example: (multiple Ajax requests, chained calls)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              Send Ajax request based on Promise
            */
            function queryData(url) {
                var promise = new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // Deal with normal conditions
                            resolve(xhr.responseText); // xhr.responseText is the data obtained from the interface
                        } else {
                            // Handling exceptions
                            reject('Interface request failed');
                        }
                    };
                    xhr.responseType = 'json'; // Set the data type returned
                    xhr.open('get', url);
                    xhr.send(null); // Request interface
                });
                return promise;
            }
            // Send multiple ajax requests and ensure the order
            queryData('http://localhost:3000/api1')
                .then(
                    data1 => {
                        console.log(JSON.stringify(data1));
                        // After requesting interface 1, continue to request interface 2
                        return queryData('http://localhost:3000/api2');
                    },
                    error1 => {
                        console.log(error1);
                    }
                )
                .then(
                    data2 => {
                        console.log(JSON.stringify(data2));
                        // After requesting interface 2, continue to request interface 3
                        return queryData('http://localhost:3000/api3');
                    },
                    error2 => {
                        console.log(error2);
                    }
                )
                .then(
                    data3 => {
                        // Get data returned by interface 3
                        console.log(JSON.stringify(data3));
                    },
                    error3 => {
                        console.log(error3);
                    }
                );
        </script>
    </body>
</html>

The above example is very classic and needs to be read several times.

Function return value of return

The return value after return has two situations:

  • Case 1: return Promise instance object. The returned instance object calls the next then.

  • Case 2: return normal value. The normal value returned is passed directly to the next then and received through the parameter of the function in the then parameter.

Let's explain these two situations in detail.

Case 1: return Promise instance object

Here's an example: (in this case, it's similar to the last Ajax chained call)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              Send Ajax request based on Promise
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // Deal with normal conditions
                            resolve(xhr.responseText);
                        } else {
                            // Handling exceptions
                            reject('Interface request failed');
                        }
                    };
                    xhr.responseType = 'json'; // Set the data type returned
                    xhr.open('get', url);
                    xhr.send(null); // Request interface
                });
            }
            // Send multiple ajax requests and ensure the order
            queryData('http://localhost:3000/api1')
                .then(
                    data1 => {
                        console.log(JSON.stringify(data1));
                        return queryData('http://localhost:3000/api2');
                    },
                    error1 => {
                        console.log(error1);
                    }
                )
                .then(
                    data2 => {
                        console.log(JSON.stringify(data2));
                        // The return here is the Promise instance object
                        return new Promise((resolve, reject) => {
                            resolve('qianguyihao');
                        });
                    },
                    error2 => {
                        console.log(error2);
                    }
                )
                .then(data3 => {
                    console.log(data3);
                });
        </script>
    </body>
</html>

Case 2: return normal value

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              Send Ajax request based on Promise
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // Deal with normal conditions
                            resolve(xhr.responseText);
                        } else {
                            // Handling exceptions
                            reject('Interface request failed');
                        }
                    };
                    xhr.responseType = 'json'; // Set the data type returned
                    xhr.open('get', url);
                    xhr.send(null); // Request interface
                });
            }
            // Send multiple ajax requests and ensure the order
            queryData('http://localhost:3000/api1')
                .then(
                    data1 => {
                        console.log(JSON.stringify(data1));
                        return queryData('http://localhost:3000/api2');
                    },
                    error1 => {
                        console.log(error1);
                    }
                )
                .then(
                    data2 => {
                        console.log(JSON.stringify(data2));
                        // Return normal value
                        return 'qianguyihao';
                    },
                    error2 => {
                        console.log(error2);
                    }
                )
                /*
                    Since the above return is a normal value, who calls then here?
                    The answer is: a new default promise instance will be generated here to call then here to ensure the chain operation can continue.
                */
                .then(data3 => {
                    // data3 here receives the normal value 'qianguyihao'
                    console.log(data3);
                });
        </script>
    </body>
</html>

Common API of Promise: instance method [important]

The API provided by Promise provides the following example methods:

  • promise.then(): get the normal result of the asynchronous task.

  • promise.catch(): get the exception result of asynchronous task.

  • Promise. Finally(): asynchronous tasks are executed whether they are successful or not.

Code examples are as follows.

Writing 1:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            function queryData() {
                return new Promise((resolve, reject) => {
                    setTimeout(function() {
                        var data = { retCode: 0, msg: 'qianguyihao' }; // Data returned by interface
                        if (data.retCode == 0) {
                            // Called when the interface request succeeds
                            resolve(data);
                        } else {
                            // Called when an interface request fails
                            reject({ retCode: -1, msg: 'network error' });
                        }
                    }, 100);
                });
            }

            queryData()
                .then(data => {
                    // Get normal results from resolve
                    console.log('When the interface request is successful, go here');
                    console.log(data);
                })
                .catch(data => {
                    // Get exception results from reject
                    console.log('When the interface request fails, go here');
                    console.log(data);
                })
                .finally(() => {
                    console.log('Whether the interface request is successful or not, it will go here');
                });
        </script>
    </body>
</html>

Style 2: (equivalent to the above style 1)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script>
            function queryData() {
                return new Promise((resolve, reject) => {
                    setTimeout(function() {
                        var data = { retCode: 0, msg: 'qianguyihao' }; // Data returned by interface
                        if (data.retCode == 0) {
                            // Called when the interface request succeeds
                            resolve(data);
                        } else {
                            // Called when an interface request fails
                            reject({ retCode: -1, msg: 'network error' });
                        }
                    }, 100);
                });
            }

            queryData()
                .then(
                    data => {
                        // Get normal results from resolve
                        console.log('When the interface request is successful, go here');
                        console.log(data);
                    },
                    data => {
                        // Get exception results from reject
                        console.log('When the interface request fails, go here');
                        console.log(data);
                    }
                )
                .finally(() => {
                    console.log('Whether the interface request is successful or not, it will go here');
                });
        </script>
    </body>
</html>

Note: the functions of writing 1 and writing 2 are completely equivalent. However, write method 2 takes the code in catch as the second parameter in then.

Common API of Promise: object method [important]

The API provided with Promise provides the following object methods:

  • Promise.all(): concurrent processing of multiple asynchronous tasks. Only when all tasks are executed successfully can the result be obtained.

  • Promise.race(): handle multiple asynchronous tasks concurrently. If one task is executed successfully, the result will be obtained.

Here is a detailed introduction.

Example of Promise.all() code

Code example:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              Encapsulate Promise interface call
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // Handle normal results
                            resolve(xhr.responseText);
                        } else {
                            // Handling abnormal results
                            reject('Server error');
                        }
                    };
                    xhr.open('get', url);
                    xhr.send(null);
                });
            }

            var promise1 = queryData('http://localhost:3000/a1');
            var promise2 = queryData('http://localhost:3000/a2');
            var promise3 = queryData('http://localhost:3000/a3');

            Promise.all([promise1, promise2, promise3]).then(result => {
                console.log(result);
            });
        </script>
    </body>
</html>

Example of Promise.race() code

Code example:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <script type="text/javascript">
            /*
              Encapsulate Promise interface call
            */
            function queryData(url) {
                return new Promise((resolve, reject) => {
                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState != 4) return;
                        if (xhr.readyState == 4 && xhr.status == 200) {
                            // Handle normal results
                            resolve(xhr.responseText);
                        } else {
                            // Handling abnormal results
                            reject('Server error');
                        }
                    };
                    xhr.open('get', url);
                    xhr.send(null);
                });
            }

            var promise1 = queryData('http://localhost:3000/a1');
            var promise2 = queryData('http://localhost:3000/a2');
            var promise3 = queryData('http://localhost:3000/a3');

            Promise.race([promise1, promise2, promise3]).then(result => {
                console.log(result);
            });
        </script>
    </body>
</html>

After you understand these contents, you have mastered the basic usage of Promise.

Tags: Javascript JSON network JQuery

Posted on Wed, 08 Apr 2020 01:56:20 -0700 by Spreegem