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

What is the basic usage of Promise

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "what is the basic usage of Promise". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "what is the basic usage of Promise"?

Basic usage

1. Grammar

New Promise (function (resolve, reject) {...} / * executor * /)

When building a Promise object, you need to pass in an executor function, and the main business processes are executed in the executor function.

The executor function is called immediately when the Promise constructor is executed, and when the resolve and reject functions are passed as arguments to the executor,resolve and reject functions, the state of the promise is changed to fulfilled (complete) or rejected (failure), respectively. Once the state changes, it will not change again, and this result can be obtained at any time.

When the resolve function is called in the executor function, the callback function set by promise.then is triggered, while the callback function set by promise.catch is triggered when the reject function is called.

It is worth noting that Promise is used to manage asynchronous programming, it itself is not asynchronous, new Promise will immediately execute the executor function, but we usually handle an asynchronous operation in the executor function. For example, in the following code, 2 is printed at first.

Let p1 = new Promise (() = > {setTimeout (()) = > {console.log (1)}, 1000) console.log (2)}) console.log (3) / / 2 31

Promise uses the callback function delay binding technology. When the resolve function is executed, the callback function has not been bound, so the execution of the callback function can only be delayed. What exactly does that mean? Let's first look at the following example:

Let p1 = new Promise ((resolve,reject) = > {console.log (1)) Resolve ('rowing in waves') console.log (2)}) / / then: set the method p1.then for post-processing of success or failure (result= > {/ / p1 delayed binding callback function console.log ('success' + result)}, reason= > {console.log ('failure' + reason)}) console.log (3) / / 1 / / 2 / / 3 / / successful rowing in waves

When new Promise, first execute the executor function, print out 1, 2 Magi promise triggers the micro task when executing resolve, or continue to execute the synchronous task, when executing p1.then, store two functions (these two functions have not been executed yet), then print out 3, at this time, the synchronous task is completed, and finally execute the micro task just now, thus implementing the successful method in .then.

two。 Error handling

Errors in the Promise object are bubbly in nature and are passed backwards until they are handled by the onReject function or caught by the catch statement. With this bubbling feature, there is no need to catch exceptions separately in each Promise object.

To encounter a then, execute a successful or failed method, but if this method is not defined in the current then, defer to the next corresponding function:

Function executor (resolve Reject) {let rand = Math.random () console.log (1) console.log (rand) if (rand > 0.5) {resolve ()} else {reject ()} var p0 = new Promise (executor) var p1 = p0.then ((value) = > {console.log ('succeed-1') return new Promise (executor)}) var p2 = p1.then ((value) = > {console.log (' succeed-2) ') return new Promise (executor)}) p2.catch ((error) = > {console.log (' error') Error)}) console.log (2)

This code has three Promise objects: p0~p2. No matter which object throws an exception, you can catch the exception through the last object p2.catch. In this way, you can merge all the errors of the Promise object into a single function, thus solving the problem that each task needs to handle the exception separately.

In this way, we eliminate nested calls and frequent error handling, which makes the code we write more elegant and more consistent with human linear thinking.

3. Promise chain call

We all know that you can connect multiple Promise together to represent a series of different steps. The key to achieving this approach lies in the following two inherent behavior characteristics of Promise:

Every time you call then on Promise, it creates and returns a new Promise, which we can link

Regardless of the value returned by the completion callback (the first argument) called from then, it is automatically set to the completion of the linked Promise (in the first point).

First, explain what this paragraph means through the following example, and then introduce the execution process of the chained call in detail:

Let p1=new Promise ((resolve,reject) = > {resolve (100) / / determines that the successful method will be executed in the next then}) / / connects p1 let p2=p1.then (result= > {console.log ('success 1' + result) return Promise.reject (1) / / returns a new Promise instance, which determines that the current instance fails So decide that the failed method in the next then will be executed}, reason= > {console.log ('failure 1' + reason) return 200}) / / connect p2 let p3=p2.then (result= > {console.log ('success 2' + result)}, reason= > {console.log ('failure 2' + reason)}) / / success 1 100 / / failure 2 1

We complete the first promise p2 created and returned by calling then by returning Promise.reject (1). The then call to p2 accepts the completion value from the return Promise.reject (1) statement at run time. Of course, p2.then has created another new promise, which can be stored with the variable p3.

The success or failure of the instance from new Promise depends on whether the execution of the executor function is determined by resolve or reject, or an exception error occurs in the execution of the executor function, both of which will change the state of the instance to failure.

P2 executes the status of the new instance returned by then and determines which method in the next then will be executed. There are the following situations:

Whether it is a successful method execution or a failed method execution (two methods in then), any execution that throws an exception will change the state of the instance to failure.

If a new Promise instance (such as Promise.reject (1) in the previous example) is returned in the method, the result of this instance is successful or failed, which also determines whether the current instance succeeds or fails.

The rest is basically to make the instance successful, and the result returned by the method in the previous then will be passed to the method in the next then.

Let's look at another example:

New Promise (resolve= > {resolve (a) / / error / / the execution of this executor function has an exception error and decides that the next then failure method will be executed}) .then (result= > {console.log (`success: ${result} `) return result*10}, reason= > {console.log (` failure: ${reason} `) / / when executing this sentence, no exception occurs or a failed Promise instance is returned So the next then success method will be executed / / there is no return here and will return undefined}) .then (result= > {console.log (`success: ${result} `)}, reason= > {console.log (` failure: ${reason} `)}) / / failure: ReferenceError: an is not defined / / success: undefined

4. Async & await

From some of the above examples, we can see that although using Promise can well solve the problem of callback hell, this approach is full of Promise's then () method. If the processing flow is complex, then the whole code will be full of then, the semantics is not obvious, and the code can not well represent the execution process.

The implementation of async/await, a new asynchronous programming method in ES7, is based on Promise. To put it simply, the async function returns the Promise object, which is the syntax sugar of generator. Many people think that async/await is the ultimate solution for asynchronous operations:

The syntax is concise, more like synchronous code, and more in line with ordinary reading habits.

Improve the code organization of serial execution of asynchronous operations in JS and reduce the nesting of callback

Error trapping using try/catch cannot be customized in Promise, but errors can be handled as if they were synchronous code in Async/await.

However, there are some disadvantages, because await transforms asynchronous code into synchronous code, and the use of await if multiple asynchronous code has no dependencies can lead to performance degradation.

Async function test () {/ / if the following code does not have a dependency, you can use the Promise.all method / / if there is a dependency, it is actually an example of solving the callback of the url1. Await fetch (url1) await fetch (url2) await fetch (url3)}

Looking at the following code, can you tell what the printed content is?

Let p1 = Promise.resolve (1) let p2 = new Promise (resolve = > {setTimeout (()) = > {resolve (2)}, 1000)} async function fn () {console.log (1) / / when the code reaches this line (first this line), build an asynchronous microtask / / wait for promise to return the result And the code below await is also listed in the task queue let result1 = await p2 console.log (3) let result2 = await p1 console.log (4)} fn () console.log (2) / / 1 2 3 4

If the expression logic on the right side of await is that promise,await will wait for the return result of this promise, the result will only be returned if the returned status is resolved. If promise is in a failed state, await will not receive the returned result, and the code under await will not continue to execute.

Let p1 = Promise.reject (100) async function fn1 () {let result = await p1 console.log (1) / / this line of code will not execute}

Let's take a look at a more complicated topic:

Console.log (1) setTimeout (() = > {console.log (2)}, 1000) async function fn () {console.log (3) setTimeout () = > {console.log (4)}, 20) return Promise.reject ()} async function run () {console.log (5) await fn () console.log (6)} run () / / need to execute 150ms around for (let item0) I {console.log (7) new Promise (resolve= > {console.log (8) resolve ()}). Then (() = > {console.log (9)}), 0) console.log (10) / / 1 5 3 10 4 7 8 9 2

Before you do this question, readers need to understand:

The technologies based on microtasks are MutationObserver, Promise and many other technologies developed on the basis of Promise. In this paper, resolve () and await fn () are microtasks.

Regardless of the arrival time and the order in which the macro tasks are placed, each time the main thread execution stack is empty, the engine will give priority to the micro-task queue, finish all the tasks in the micro-task queue, and then deal with the macro task.

Next, we analyze it step by step:

First execute the synchronization code, output 1, encounter the first setTimeout, put its callback into the task queue (macro task), and continue to execute

Run run (), print out 5, and move on, encounter await fn (), and put it in the task queue (micro task)

Await fn () the current line of code execution, the fn function will be executed immediately, print out 3, encounter the second setTimeout, put its callback into the task queue (macro task), the code under await fn () will not be executed until the return of Promise success status, so 6 will not be printed.

Continue to execute, encounter for loop synchronization code, need to wait for 150ms, although the second setTimeout has arrived time, but will not execute, encounter the third setTimeout, put its callback into the task queue (macro task), and then print out 10. It is worth noting that the timer delay time of 0 milliseconds can not actually be reached. According to the HTML5 standard, the time for setTimeOut to delay execution is at least 4 milliseconds.

When the synchronization code is finished, when there is no micro task, you will execute the macro task. The setTimeout mentioned above will be executed first and print out 4.

Then execute the next setTimeout macro task, so when you print out 7 new Promise, the executor function will be executed immediately, printing 8, and then when resolve is executed, the micro task will be triggered and 9 will be printed.

Finally, execute the first macro task of setTimeout and print out 2

Common methods

1. Promise.resolve ()

The Promise.resolve (value) method returns a Promise object that has been parsed with a given value. Promise.resolve () is equivalent to the following:

Promise.resolve ('foo') / / is equivalent to new Promise (resolve = > resolve (' foo'))

The parameters of the Promise.resolve method are divided into four cases.

(1) the parameter is a Promise instance

If the parameter is a Promise instance, then Promise.resolve will return the instance intact without any modification.

Const p1 = new Promise (function (resolve, reject) {setTimeout (() = > reject (new Error ('fail')), 3000)}) const p2 = new Promise (function (resolve, reject) {setTimeout (() = > resolve (p1), 1000)}) p2. Then (result = > console.log (result)) .catch (error = > console.log (error) / / Error: fail)

In the above code, p1 is a Promise,3 that becomes rejected after a second. The state of p2 changes after 1 second, and the resolve method returns p1. Because p2 returns another Promise, the state of p2 is invalid, and the state of p2 is determined by the state of p1. Therefore, the following then statements are changed to target the latter (p1). After another 2 seconds, p1 becomes rejected, causing the callback function specified by the catch method to be triggered.

(2) the parameter is not an object with a then method, or is not an object at all

The parameters of the Promise.resolve ("Success"). Then (function (value) {/ / Promise.resolve method are also passed to the callback function. Console.log (value); / / "Success"}, function (value) {/ / will not be called})

(3) without any parameters

The Promise.resolve () method allows you to call a Promise object with no arguments and directly return a resolved state. If you want to get a Promise object, the convenient way is to call the Promise.resolve () method directly.

Promise.resolve () .then (function () {console.log ('two');}); console.log (' one'); / / one two

(4) the parameter is a thenable object

A thenable object refers to an object that has a then method, and the Promise.resolve method converts this object to a Promise object, and then immediately executes the then method of the thenable object.

Let thenable = {then: function (resolve, reject) {resolve (42);}}; let p1 = Promise.resolve (thenable); p1.then (function (value) {console.log (value); / / 42})

2. Promise.reject ()

The Promise.reject () method returns a Promise object with a reason for rejection.

New Promise ((resolve,reject) = > {reject (new Error ("error"));}); / equivalent to Promise.reject (new Error ("error")); / / using method Promise.reject (new Error ("BOOM!")) .catch (error = > {console.error (error);})

It is worth noting that after calling resolve or reject, Promise's mission is complete, and subsequent operations should be placed in the then method, not written directly after resolve or reject. Therefore, it is best to precede them with return statements so that there are no surprises.

New Promise ((resolve, reject) = > {return reject (1); / / subsequent statements will not execute console.log (2);})

3. Promise.all ()

Let p1 = Promise.resolve (1) let p2 = new Promise (resolve = > {setTimeout (()) > {resolve (2)}, 1000)}) let p3 = Promise.resolve (3) Promise.all ([p3, p2, p1]) .then (result = > {/ / the result returned is console.log (result) / / [3,2) in the order in which the instances were written in Array 1]}) .catch (reason = > {console.log ("failure: reason")})

Promise.all generates and returns a new Promise object, so it can use all the methods of the Promise instance. This method returns when all the Promise objects in the promise array become resolve, and the newly created Promise uses the values of these promise.

If any of the parameters promise is reject, the entire Promise.all call is terminated immediately and a new Promise object of reject is returned.

4. Promise.allSettled ()

Sometimes, we don't care about the results of asynchronous operations, we just care about whether those operations are finished. It is useful for ES2020 to introduce the Promise.allSettled () method at this point. If there is no such method, it is troublesome to make sure that all operations are finished. The Promise.all () method cannot do this.

If there is such a scenario: a page has three areas, each corresponding to three independent interface data, and use Promise.all to request three interfaces concurrently. If any one of the interfaces is abnormal, the status is reject, which will cause the data of the three regions in the page to fail to come out. Obviously, this situation is unacceptable, and the emergence of Promise.allSettled can solve this pain point:

Promise.allSettled ([Promise.reject ({code: 500, msg: 'service exception'}), Promise.resolve ({code: 200, list: []}), Promise.resolve ({code: 200, list: []})] .then (res = > {console.log (res) / * 0: {status: "rejected", reason: {… 1: {status: "fulfilled", value: {… } 2: {status: "fulfilled", value: {… } * / / filter out the rejected status and ensure that the page area data renders RenderContent as much as possible (res.filter (el = > {return el.status! = = 'rejected'})}))

Promise.allSettled is similar to Promise.all in that its parameters take an array of Promise and return a new Promise, except that it does not short circuit, that is, when the Promise is all processed, we can get the state of each Promise, regardless of whether the processing is successful or not.

5. Promise.race ()

The effect of the Promise.all () method is "who runs slowly, who executes the callback", then there is another way, "who runs fast, who executes the callback". This is the Promise.race () method, which originally means race. Race is used in the same way as all, taking an array of promise objects as parameters.

Promise.all will not proceed with the later processing until all the object promise has changed to the FulFilled or Rejected state, as opposed to Promise.race, as long as a promise object enters the FulFilled or Rejected state.

/ / execute resolve function timerPromisefy (delay) {return new Promise after milliseconds (resolve = > {setTimeout (()) = > {resolve (delay);}, delay);}) } / / if any promise becomes resolve or reject, the program stops running Promise.race ([timerPromisefy (1), timerPromisefy (32), timerPromisefy (64)]. Then (function (value) {console.log (value); / / = > 1})

The above code creates three promise objects that become FulFilled after 1ms, 32ms, and 64ms, respectively, and after the first 1ms becomes deterministic, the .then registered callback function is called.

6. Promise.prototype.finally ()

ES9 added the finally () method to return a Promise. At the end of the promise, the specified callback function is executed regardless of whether the result is fulfilled or rejected. This provides a way to execute code that needs to be executed after the Promise completes successfully or not. This avoids the need to write the same statement once in then () and once in catch ().

For example, there will be a loading before we send the request, and when our request is sent, we want to turn off the loading regardless of whether the request is wrong or not.

This.loading = true request () .then ((res) = > {/ / do something}) .catch (() = > {/ / log err}) .finally (() = > {this.loading = false})

The callback function of the finally method does not accept any parameters, which indicates that the operation in the finally method should be state-independent and independent of the execution result of the Promise.

Practical application

Suppose there is such a demand: red light 3s once, green light 1s once, yellow light 2s once; how to make the three lights turn on again and again? Three lighting functions already exist:

Function red () {console.log ('red');} function green () {console.log (' green');} function yellow () {console.log ('yellow');}

The complexity of this problem lies in the need for "alternating repetition" to turn on the lights, rather than an one-shot deal that ends with one turn, which we can achieve through recursion:

/ implement let task = (timer, light) = > {return new Promise ((resolve, reject) = > {setTimeout () = > {if (light = 'red') {red ()} if (light =' green') {green ()} if (light = 'yellow') {yellow ()} resolve ()}, timer) with promise })} let step = () = > {task (3000, 'red'). Then () = > task (1000,' green'). Then () = > task (2000, 'yellow'). Then (step)} step ()

It can also be implemented through async/await:

/ / async/await implementation let step = async () = > {await task (3000, 'red') await task (1000,' green') await task (2000, 'yellow') step ()} step ()

Using async/await, you can write asynchronous code in the style of synchronous code, and there is no doubt that async/await 's solution is more intuitive, but an in-depth understanding of Promise is the basis for mastering async/await.

At this point, I believe you have a deeper understanding of "what is the basic usage of Promise". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

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