Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Promise in JavaScript

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly introduces the relevant knowledge of how to use Promise in JavaScript, the content is detailed and easy to understand, the operation is simple and fast, and has a certain reference value. I believe you will gain something after reading this article on how to use Promise in JavaScript. Let's take a look at it.

Introduction to Promise

Promise, also known as contract, is an asynchronous solution introduced by ES6, which can effectively solve the problem that asynchronous functions are too deeply nested ("callback hell").

What is callback hell?

Suppose there is a need to obtain the specified data of the user, user data 3, which depends on user data 2, and user data 2 depends on user data 1. Therefore, the correct order of data acquisition is as follows: user data 1-> user data 2-> user data 3. The callback function is simulated as follows:

Node interface:

Const router = require ('express'). Router (); const data1 = {data: "user data 1"}; router.get (' / testData1', (req, res) = > {res.json (data1);}) const data2 = {data: "user data 1, user data 2"}; router.get ('/ testData2', (req, res) = > {if (req.query.data = = data1.data) {res.json (data2)) } else {res.status (401). Json ("parameter error");}) router.get ('/ testData3', (req, res) = > {if (req.query.data = data2.data) {res.json ({data: "user data 1, user data 2, user data 3"});} else {res.status (401). Json ("parameter error") }}) module.exports = router

Frontend request code:

/ / simple encapsulated XMLHttpRequest request function const baseUrl = "http://localhost:8888/test";const request = (url, cb) = > {const xhr = new XMLHttpRequest (); xhr.open ('GET', baseUrl + url); xhr.send (); xhr.onreadystatechange = () = > {const {readyState, status, response} = xhr; if (readyState = 4) {if (status > = 200 & & status {console.log (res1)) / / = > {data: 'user data 1'} request (`/ testData2?data=$ {res1.data}`, res2 = > {console.log (res2); / / > {data: 'user data 1, user data 2'} request (`/ testData3?data=$ {res2.data}`, res3 = > {console.log ("data required", res3) / / = > data required {data: 'user data 1, user data 2, user data 3'} / /.... })}))

This code looks big, and if the requirements are complex, I can only use one picture to show it.

The code of this kind of callback nesting a callback is not readable and maintainable, so it is called "callback hell", and the emergence of Promise can solve this problem very well.

Characteristics of Promise

A Promise object has a state that is not affected by the outside world. There are three types of states:

Pending state (in progress (also known as TBD) initial state

Fulfilled status (success (also called cashing))

Rejected status (failure (also known as rejection))

About the status of Promise, the following articles are used successfully and failed

Once the state of the Promise object changes (success or failure), it no longer changes, and is one-way:

Pending (in progress)-> Fulfilled (successful)

Pending (in progress)-> Rejected (failed)

Create a Promise instance

To create a Promise instance, you need the newPromise constructor, which takes a function (processor function) as a parameter. The function receives two parameters, resolve and reject (whatever you want or semantic name). They are two functions that can be used without self-implementation, as follows:

Const p = new Promise ((resolve, reject) = > {}) console.log (p)

You can see that this state defaults to Pending (in progress)

The two parameters (function), resolve and reject, can be called in the handler function (which can be passed), which will change the state of the Promise object:

Const p = new Promise ((resolve, reject) = > {resolve ();}) console.log (p)

When the resolve function is called, the state of the Priomise object is changed to Fulfilled (successful), and when the reject function is called, the state is changed to Rejected (failed)

Then method

The then method of the Promise instance can accept two parameters (both functions) to specify the callback function to be called when the state (success or failure) in the Primise instance changes (and the then method of Promise is an asynchronous micro task):

Const p = new Promise ((resolve, reject) = > {/ / modify the status of p to successful resolve ();}) console.log ("synchronization code"); p.then (() = > {console.log ("successful callback");}, () = > {console.log ("failed callback");})

The results are as follows:

On the contrary, calling the reject function will trigger the second callback function of the then method. If you call both the resolve function and the reject function, it will only be called first (because the state is one-way).

Parameter passing of resolve and reject

After the above tests, we know that the two functions resolve and reject can modify the state and trigger the callback function of the then method of Promise, then the function can pass a parameter, which will be passed to the callback function of the corresponding then method to receive:

Const p = new Promise ((resolve, reject) = > {/ / change the status of p to success and pass a parameter resolve ("ok");}) console.log ("synchronization code"); p.then (/ / here receives the parameter passed by the resolve function res = > {console.log ("successful callback", res) }, / / here receives the parameter passed by the reject function err = > {console.log ("failed callback");})

The results are as follows:

Then () chained call

After learning about the then method, we can slightly modify the top requirement at the beginning:

/ / request function is encapsulated with Promise const baseUrl = "http://localhost:8888/test";const request = (url) = > {/ / returns a Promise instance return new Promise ((resolve, reject) = > {const xhr = new XMLHttpRequest (); xhr.open ('GET', baseUrl + url); xhr.send (); xhr.onreadystatechange = () = > {const {readyState, status, response} = xhr) If (readyState = 4) {if (status > = 200 & & status {console.log (res1); / / {data: 'user data 1'} request (`/ testData2?data=$ {res1.data}`) .then (res2 = > {console.log (res2)) / / {data: 'user data 1, user data 2'} request (`/ testData3?data=$ {res2.data}`). Then (res3 = > {console.log ("data required by demand", res3); / / = > data required by demand {data: 'user data 1, user data 2, user data 3'}})})

After writing it, it seems that it would be better to use the callback function to write it. It seems that Promise still can't solve the problem of callback nesting very well. To change the way of thinking, if we return another Promise instance in the then method, we can call the then method again. Test it in the code:

Const p1 = new Promise ((resolve, reject) = > {resolve ("p1 data");}) / / the p2 here is the p2const p2 = p1.then returned in the successful callback of the p1.then method (/ / the res1 parameter here is the parameter passed by calling resolve ("p1 data") in the processor function of p1 res1 = > {console.log (res1) / / p1 data / / create a new Promise instance here, record as p2 const p2 = new Promise ((resolve, reject) = > {/ / 0.5s and then modify the status setTimeout (() = > {resolve (res1 + ", p2 data");}, 500);}) / / return p2 to return p2 }) const p3 = p2.then (res2 = > {console.log (res2); / / p1 data / / here and above the same const p3 = new Promise ((resolve, reject) = > {setTimeout (()) = > {resolve (res2 + ", p3 data");}) return p3;}) p3.then (res3 = > {console.log (res3)) / / p1 data, p2 data, p3 data})

When you find it feasible, modify the requirement code again:

/ / the p1 here is the Promise instance const p1 = request ("/ testData1") returned by request ("/ testData1"); / / the p2 here is the p2const p2 = p1.then returned by the successful callback of p1.then method (res1 = > {console.log (res1)) / / {data: 'user data 1'} / / call the request method to record the returned Promise instance as p2 const p2 = request (`/ testData2?data=$ {res1.data}`); / / return p2 to return p2;}) const p3 = p2.then (res2 = > {console.log (res2)) / / {data: 'user data 1, user data 2'} / / the same as above const p3 = request (`/ testData3?data=$ {res2.data}`); return p3;}) p3.then (res3 = > {console.log ("data required by demand", res3); / / data required by demand {data: 'user data 1, user data 2, user data 3'}})

The requirements are implemented, but the code is a little redundant and can be simplified as follows:

Request ("/ testData1") .then (res1 = > {console.log (res1); / / {data: 'user data 1'} / / the return value of the request method directly returns the Promise instance return request (`/ testData2?data=$ {res1.data}`);}) .then (/ / the successful callback of the Promise instance returned by the last then method on this successful callback res2 = > {console.log (res2)) / / {data: 'user data 1, user data 2'} / / synonymous return request (`/ testData3?data=$ {res2.data}`);}). Then (/ / similarly res3 = > {console.log ("data required by demand", res3); / / data required by demand {data: 'user data 1, user data 2, user data 3'}})

The above code format is like a chain, so it is also called "chain call".

The return value of then ()

After the above code test, the then method can return any value except the Promise object, and the return is converted to a Promise object, and the internal state depends on the return value:

Const p1 = new Promise (resolve = > resolve ()); p1.then (() = > {/ / here is equivalent to return undefined}). Then (res1 = > {console.log (res1); / / undefined return "hello";}) .then (res2 = > {console.log (res2); / / hello return {name: Zhang San};}). Then (res3 = > {console.log (res3)) / / {name: "Zhang San"} / / returns the status of the Promise object is also successful return new Error ("error object");}) .then (res4 = > {console.log (res4 instanceof Error); / / true console.log (res4.message); / / error object / / throws an error and the status of the Promise object is failed throw "thorw error" }) .then (() = > {}, err = > {console.log (err); / / thorw error}) catch method

The chained call using the then method above can solve the problem of too deep nesting of callbacks, but the failed callback processing between requests has not been handled yet. The second callback of the then method is to specify the failed callback, but generally does not use this callback to handle the error, but uses the catch method to fail, using the format as follows:

P1.then (/ /...) .then (/ /...) .catch (err = > {/ / this catch can catch errors / / handling errors} on this call chain) finally method

In addition to the catch method, there is naturally a finally method. The finally method has the same function as finally in try...catch...finally. The format is as follows:

P.then (/ /...) .then (/ /...) .catch (err = > {/ / this catch method can catch errors / / processing errors} on this call chain) .finally (() = > {/ / the callback specified in the finally executes / / clears the loading, resets the state.}) the Promise method Promise.resolve ()

Immediately returns a Promise object whose status is Fulfilled. Parameters can be passed, and the parameters will be accepted by the callback (asynchronous micro task) of the then method of the returned Promise instance:

Const p = Promise.resolve ("Promise.resolve"); p.then (res = > console.log (res)); / / Promise.resolve

You can also use Promise.resolve () to create a micro task:

Console.log ("synchronization Code"); setTimeout (() = > console.log ("setTimeout"), 0); const p = Promise.resolve ("Promise.resolve"); p.then (res = > console.log (res))

The results are as follows:

Promise.reject ()

Same as Promise.resolve (), except that the returned state is the Promise object of Rejected (also a micro task)

Console.log ("synchronization Code"); setTimeout (() = > console.log ("setTimeout"), 0); const p = Promise.reject ("Promise.reject"); p.then () .catch (err = > console.log ("Promise.reject")); Promise.all ()

Promise.all receives an iterable type of Promise (that is, iterable objects store Promise instances. Array, Map, and Set all belong to the iterable type of ES6). Promise.all waits for all Promise objects to complete (or the first to fail) and returns different parameters according to the given parameters.

Const p1 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p1 data"), 1500);}) const p2 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p2 data"), 1000);}) const p3 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p3 data"), 1500);}) / print data p1.then (res = > console.log (res)) sequentially / / print p1 datap2.then after 0.5s (res = > console.log (res)); / / print p2 datap3.then after 1.0s (res = > console.log (res)); / / print p3 dataconst proArray = [p1, p2, p3] after 1.5s; Promise.all (proArray) .then (resList = > {console.log (resList)) Print data after 1.5 seconds ['p1 data','p2 data','p3 data']}) .catch (err = > {/ / if a failed state occurs in the `Promise.all` method, then this parameter will be the parameter (if any) returned by the failed state console.error ("error:", err);})

The specificity of the Promise.all () method can be used to send multiple requests at the same time, as shown in the following example:

Node interface:

Const getRandom = () = > Math.random () * 9 + 1 setrouter.get ('/ testData4', (req, res) = > {let n = req.query.n; const random = getRandom (); / / timer simulates interface response time difference setTimeout () = > {res.json (`1st ${+ + n} request ${random} `);}, random * 50);})

The front end sends multiple requests:

Const proArray = []; for (let I = 0; I

< 10; i++) { // 将10个请求方法返回的Promsie对象添加到proArray数组中 proArray.push(request(`/testData4?n=${i}`));}Promise.all(proArray).then(resList =>

{for (const res of resList) {/ / the returned result of each request console.log (res);}}) Promise.allSettled ()

The Promise.allSettled () method is similar to Promise.all () except that the successful callback of the then method will be triggered by the accepted appointment object whether it succeeds or fails. Each appointment will return an object status property to represent the status, and value represents the value of the successful callback. If the status is failed, the value of the failed callback is stored in the reason attribute:

Const p1 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p1 data"), 500);}) const p2 = new Promise ((resolve, reject) = > {/ / p2 Promise instance status modified to failed setTimeout (() = > reject ("p2 err"), 1000);}) const proArray = [p1, p2]; Promise.allSettled (proArray) .then (resList = > {console.log (resList); / / (2) [{… }, {... }] for (const res of resList) {const {status, value, reason} = res; if (reason) {console.log (`failure: ${status} because: ${reason}`); / / failure: rejected, because: p2 err} else {console.log (`success: ${status}, data: ${value}`) / / success: fulfilled, data is: p1 data}}) .catch (err = > {/ / the failed callback console.error ("error:", err) of p2 will not be captured here;}) Promise.race ()

Promise.race () and Promise.all () are similar, both accept a parameter that can be iterated, but the difference is that

The state change of Promise.race () is not affected by the state of all parameters. Once a Promise in the iterator is resolved or rejected, the returned Promise will resolve or reject.

Const p1 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p1 data"), 500);}) const p2 = new Promise ((resolve, reject) = > {setTimeout (() = > reject ("p2 err"), 1000);}) const proArray = [p1, p2]; Promise.race (proArray) .then (res = > {console.log (res); / / p1 data}) .catch (err = > {console.error (err);}) async and awaitasync function functions

Async functions are functions declared using the async keyword (also known as asynchronous functions). There is no difference between async functions and ordinary functions:

/ / function declaration async function asyncFn1 () {console.log ("asyncFn1");} / / function expression const asyncFn2 = async () = > {console.log ("asyncFn2");} asyncFn1 (); asyncFn2 (); / / call immediately (async () = > {console.log ("asyncFn3");}) (); await

The await operator is used to wait for a Promise object, which can only be used in async function. Using async+await, you can "change" asynchronous code like synchronous code:

Const p = new Promise ((resolve, reject) = > {setTimeout (() = > {resolve ("data");}, 1000);}); / / async function async function asyncFn () {console.log ("asyncFn function starts to execute"); / / await waits for the state of the Promise object on the right to become a function and returns its value const res = await p; console.log (res); / / data console.log ("asyncFn function is finished") } / / call asyncFn ()

The above code will first output "asyncFn function execution", wait about 1 second to output "data", and then output "asyncFn function execution is finished"

Note: the asynchronous function does not block the execution of the main thread, it is asynchronous:

Const p = new Promise ((resolve, reject) = > {setTimeout (() = > {resolve ("data");}, 1000);}); / / async function async function asyncFn () {console.log ("asyncFn function starts to execute"); const res = await p; console.log (res); console.log ("asyncFn function is finished");} console.log ("hello"); asyncFn (); console.log ("javascript")

After waiting for about 1 second, the above code execution result is as follows:

Based on the above code execution result, we find that the await key in the asynchronous function waits for the return value of the Promise object on the right, and the later code will not be executed until the wait is over. Using this feature, we can implement a Thread.sleep () method similar to Java in JavaScript, as follows:

Const sleep = async time = > new Promise (resolve = > setTimeout (resolve, time)); (async () = > {console.log ("1"); await sleep (1000); console.log ("2"); await sleep (500); console.log ("2.5");}) ()

After understanding the use of async and await, we can use asynchronous functions to complete our initial requirements:

/ / request function is encapsulated with Promise const baseUrl = "http://localhost:8888/test";const request = (url) = > {/ / returns a Promise instance return new Promise ((resolve, reject) = > {const xhr = new XMLHttpRequest (); xhr.open ('GET', baseUrl + url); xhr.send (); xhr.onreadystatechange = () = > {const {readyState, status, response} = xhr) If (readyState = 4) {if (status > = 200 & & status {/ / processing res1 error}); if (res1?.data) {const res2 = await request (`/ testData2?data=$ {res1.data}`) .catch (err = > {/ / processing res2 error}) If (res2?.data) {const res3 = await request (`/ testData3?data=$ {res2.data}`) .catch (err = > {/ / processing res3 error});}} Asynchronous functions are also applicable to some static methods of Promise const p1 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p1 data"), 500) }) const p2 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p2 data"), 1000);}) const p3 = new Promise ((resolve, reject) = > {setTimeout () = > resolve ("p3 data"), 1500);}) const proArray = [p1, p2, p3]; async function asyncFn () {const list = await Promise.all (proArray); console.log (list); / / ['p1 data','p2 data','p3 data']} asyncFn () For await...of

Multiple Promise objects are stored in an array. We can get them through Promise.all or wait for their return values through loops. We use loops:

Const p1 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p1 data"), 1500);}) const p2 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p2 data"), 1000);}) const p3 = new Promise ((resolve, reject) = > {setTimeout (() = > resolve ("p3 data"), 1500);}) const proArray = [p1, p2, p3] Async function asyncFn () {for (const pro of proArray) {/ / Don't forget await const res = await pro; console.log (res);}} asyncFn ()

At the beginning of ES9, a new syntax is that for await..of can automatically wait for items in each loop.

Async function asyncFn () {for await (const item of proArray) {console.log (item);}} asyncFn (); this is the end of the article on "how to use Promise in JavaScript". Thank you for reading! I believe you all have a certain understanding of "how to use Promise in JavaScript". If you want to learn more, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report