preface

In fact, there are many articles about Promise and asycn and await on the Internet, but since I was still confused after reading a lot of them, I decided to write an article of my own as a reading note after reading “JavaScript Advanced Programming 4th Edition”.

In fact, after reading the book, I found that I did not understand the function of promise.resolve () before, and basically solved the “Ren Governor two veins” after reading it, so students in the same situation can choose to directly read the book, or… Then look!

There’s a lot of code, but the code below is super simple.

So the story starts with why promises are made

In fact, in terms of the front end, it is an asynchronous function and needs to take the return value to do things is basically Ajax requests, of course, according to the international convention of articles are used to setTimeout instead.

Ok, so the thing is, now we have an asynchronous operation, and we want to use the data after it executes:

// Let x = 3 setTimeout(() => x += 4,1000) console.log(x)Copy the code

To do this, add a callback function to the asynchronous operation and use the result as an input parameter to do whatever you want:

let x = 3 setTimeout(() => callback(x += 4), 1000) function callback(result) {console.log(result)}Copy the code

Ok, to get straight to the point, there are two main drawbacks to this approach:

  1. Callbacks need to be defined in advance, and if you suddenly want to do something else with the data, you have to add functionality to the same callback, which can be uncomfortable if the data is changed within the callback.
  2. If the asynchronous return value depends on another asynchronous return value, then you have to nest the callback. This is the legendary callback hell. As the code gets more complex, it can be a nightmare to maintain.
// Assuming you still get the value 7, Let x setTimeout(() => callback1(x = 3), Function callback2(result) {setTimeout(() => callback1(result += 4), 1000)} function callback2(result) {console.log(result)}Copy the code

Now that it’s over, let Promise sort it out.

Three states of Promise

Promise is a constructor that is instantiated by new, and it must pass in a function when instantiated, otherwise an error will be reported.

Let p2 = new Promise(()=>{}) console.log(p2) // Promise {<pending>}Copy the code

In the book, they call promises expiration dates, so let’s call them expiration dates, too, because I think it’s a little easier to understand.

The instantiated date has three states:

  • To be determined (Pengding)
  • To solve (resolved | | fullfilled)
  • I don’t like it!

It’s like an egg. All you need to know is that it can be in one of three states: it’s waiting to be eaten (in its original form), and then it can either hatch into a chicken, or it can become an omelette, and it’s impossible to reverse that state, just like it can’t become an omelette after becoming a chicken. In the end, you just need to know how to get into these three states. To demonstrate:

  1. Solution status:
// The function takes two arguments, Let p2 = new Promise((resolve, resolve, Resolve ()}) console.log(p2) {<resolved> Promise (' resolved ')Copy the code
  1. Declined to state
Let p2 = new Promise((resolve, reject) => {reject()}) console.log(p2) // Promise {<reject >}Copy the code
  1. Pending state
Let p2 = new Promise((resolve, reject) => {}) console.log(p2) // Promise {<pending>}Copy the code

Both resolve and reject accept a single value, which is easy to understand: resolve and reject accept whatever value is put in this contract, so it’s undefined. Okay

Let p1 = new Promise((resolve, reject) => {resolve(123)}) console.log(p1) // Promise {<resolved>} : Let p1 = new Promise((resolve, resolve, Reject) => {reject(321)}) console.log(p1) // Promise {<reject >} : 321Copy the code

Resolve (” desired value “); resolve(” desired value “);

let x = 3 let p1 = new Promise((resolve, reject) => { setTimeout(() => resolve(x += 4), 1000)}) console.log(p1) // Promise {<pending>} Resolve) setTimeout(console.log, 1000, p1) // Promise {<resolved>} : SetTimeout (() => callback(x += 4), 1000)Copy the code

Now that we have a valid contract, we need to figure out how to use it later, but until then, we can think of a way to solve the first drawback of using callback functions: the need to define the function; Obviously with Promise, we don’t have to define anything extra, but we take this contract p1 with the value that we want, and we can take it wherever we want.

Then, back to the beginning, our goal is to get a value, not a contract, so a contract gives us some way to manipulate the value of a contract, namely the legendary then and catch.

Then ((result)=>{console.log(result) // 7 (output after 1 SEC) // then(result)=>{console.log(result) // 7 (output after 1 SEC) //Copy the code

Then takes two functions. The first function takes the value of the settlement period, and the second takes the value of the rejection period, like this:

Let p2 = new Promise((resolve, reject) => {setTimeout(() => reject(7)), Then ((result) => {console.log(result) // will not execute}, (result) => {console.log(result) // 7 (1 second after output)}) // or catch p2.catch((result) => {console.log(result) // 7 (1 second after output)}) P2. catch((result) => {console.log(new Error(result)) // Error: 7 (output after 1 second)})Copy the code

‘Then’ and ‘catch’ are executed after 1 second. ‘Resolve’ and ‘reject’ are executed after 1 second. The transfer of values can be understood as a pipeline: Resolve passes to the first then function, reject passes to the second then function or catch. As for how to achieve I think can be ignored;

Resolve () I think it’s important and practical to use a promise.resolve ()

onPromise.resolve()

Basic usage

In fact, it is easy to understand, it is a value of other types to a term, return a settlement contract, the next two term instances are actually the same, they return a settlement contract undefined.

let p1 = new Promise((resolve) => { resolve() })  // 
let p2 = Promise.resolve()
Copy the code

To quote from the book:

Resolve (3)) // Promise {resolved} : 3

Resolve (4, 5, 6)) // Promise {resolved} : 4

Note: When the package is thrown an error, it becomes a rejection contract:

special

The above is the basic usage, but it has another important function: it is like an empty wrapper when passed in a contract. Resolve () is empty package empty package empty package empty package:

Resolve (p1) console.log(p1 === p2) // true // or let p3 =  Promise.resolve(Promise.resolve(Promise.resolve(p2))) console.log(p3 === p2) // trueCopy the code

Now you can actually do the chain call of the term, but with promise.reject ()

Promise.reject()

The basic usage is the same: return a rejection period. The difference is that, unlike promise.resolve (), which is an empty wrapper, it returns the term passed in:

Let p1 = promise.resolve (7) let p2 = promise.reject (p1) console.log(p2) // Promise <rejected> : {Promise: <resolve> : 7}Copy the code

Term about the chain call, solve callback hell

In fact, when you understand a point, you understand:

Promise.prototype.then() returns a new contract instance, which is generated by the promise.resolve () wrapper.

Just like jQuery, how to chain calls, each method returns a jQuery object is not enough.

Resolve () ¶ The Promise. Resolve () method defaults to the Promise. Resolve () method returns no value or returns a string. Originally secretly converted, on the code in the book to deepen your understanding:

Then (() => {}) let p3 = p1. Then (() => undefined) let p4 = Resolve ()) setTimeout(console.log, 0, p2) // Promise <resolved> : Log (0, p3) // Promise <resolved> : Undefined setTimeout(console.log, 0, p4) // Promise <resolved> : Let p6 = p1. Then (() => promise.resolve ('bar')) SetTimeout (console.log, 0, p5) // Promise <resolved> : bar setTimeout(console.log, 0, p6) Let p6 = p1. Then (() => promise.reject ('bar')) let p6 = p1. Then (() => throw 'bar') SetTimeout (console.log, 0, p5) // Promise < Rejected > : bar Console. log, 0, p6) // Promise < Rejected > : barCopy the code

So once again we go back to the beginning and solve callback hell. The original example would look something like this if we modified it:

let x let p1 = new Promise((resolve) => { setTimeout(() => resolve(3), Then ((x) => {console.log(x + 5)}) // 12 (no return, Then ((data) => {console.log(data) // undefined return "I want to return something"}). Then (console.log) // "Suddenly I want to return something."Copy the code

That solves callback hell, and it’s kind of elegant.

Promise: Promise: Promise: Promise: Promise: Promise: Promise: Promise

Bits and pieces about rejection contracts

  • Standard writing for handling rejection periods
// Error messages are usually wrapped with built-in error types, Let p1 = promise.reject (Error('bar')) (result) => console.log(result)) // Error: bar // Or catch p1.catch((result) => console.log(result)) // Error: barCopy the code
  • It will still be used after error handlingPromise.resolve()Packaging thus becomes the term of settlement. It means that you have handled all the errors, so I will return a settlement date.
Then (null, (result) => console.log(result)) // Error: bar let p3 = p1.catch((result) => { console.log(result) return 123 }) setTimeout(console.log, 0, P2) // Promise <resolved> : undefined setTimeout(console.log, 0, p3) // Promise <resolved> : 123Copy the code
  • Reject contracts are not caught by a try/catch and are handled as above

Asynchronous functions async/await

These two keywords still start from the usage, with the purpose of eventually being used.

There is also the syntactic sugar about them being generators, which I think can be ignored, the generator feels rarely used, directly understand this advanced

async

It is used to declare an asynchronous function, but generally it is executed synchronously.

What async/await really works is await. If an asynchronous function does not contain the await keyword, it performs essentially the same as a normal function.

The only thing I find special about it, however, is that its return value is also wrapped with promise.resolve () to return the resolved date.

Async function foo() {console.log(1) return 3} let p = foo() console.log(p) // Promise <resolved> : 3Copy the code

It’s that simple. It’s not that complicated.

await

All right, here’s what really matters

This keyword suspends the execution of asynchronous function code while waiting for an expression that returns either a term or some other value.

The point of this sentence is to pause. In fact, you will find that the central idea of handling asynchronous operations is to wait until there is data to process. The following is to understand this keyword in order of execution.

async function foo() {
    await console.log(2)
    console.log(4)
}
console.log(1)
foo()
console.log(3)

// 1
// 2
// 3
// 4
Copy the code

There are three main points mentioned above:

  • The code in the await line will execute immediately.
  • The code after await is pushed to the microtask queue, and then exits the whole async function to execute other code and resumes executing the rest of the function. (It’s a concept of pause.)
  • Await must be written inside async function or an error will be reported.

Questions about the order of execution of promises and async/await

I recommend this article. Can say very strong, after reading this aspect of the interview questions basic difficult to fall you.

After knowing the above execution order problem, and then add the following knowledge point will be used.

The return value of await

Remember that the code in the then method waits for the resolve or reject method to execute the expiration date.

The purpose of executing then is to get the return value of an asynchronous operation, so await is used: Is the return value directly to the asynchronous operation, it is no longer returns a period about what of, but the value is returned directly to the, can also be understood as jumps over then this step is to get the value directly, but just like then, will wait about execution due to resolve or reject method after there will be a return value. So it’s a little bit more concise, and it’s a little bit more powerful.

Demonstrate various cases of the code on the right side of the await:

// With a value of no particular value, we can simply say that await does not exist. Of course the code behind await will still be executed asynchronously. Async function foo() {let result = await 123 console.log(result) // 123} foo() Async function foo() {let result = await promise.resolve (555) console.log(result) // 555} foo() {let result = await promise.resolve (555) console.log(result) // 555} foo()Copy the code

Here’s a possible way to write this at work:

Function request() {let p1 = new Promise((resolve, reject) => { XXXX, success: Error (err) {reject(err); error(error) {reject(err); error(error) {reject(err) }})}) return p1} // this is an await followed by a term, because the function returns a term. Async function foo() {let data = await request() console.log(data)} foo()Copy the code

A quick summary of the above:

  • No matter how complicated the code is, all you need to know is that the whole function returns a contract, what the final state of the contract is, and what the value is. It can then be used either with await or then.
  • “Await” doesn’t matter how long it will take you to get the request, it will continue to execute the code after it has a value. This is the concept of a pause.

The last

Novice on the road, there are mistakes in the place warmly welcome correction. I recommend you to go directly to JavaScript Advanced Programming Edition 4, which has a lot of details. That’s all I remember, though

reference

“JavaScript Advanced Programming 4th Edition” from a simple question to explain the JavaScript event loop (solve the interview questions, remember to see)