The article directories

Promise notes

Reference course: Silicon Valley Web Front End Promise tutorial from Getting started to Mastering (early 2021)

What is Promise

1. Two expressions of Promise

  • Abstract expression:
  1. Promise is a new technology (ES6 specification)
  2. ==Promise is a new solution for asynchronous programming in JS ==, more reasonable and powerful than traditional solutions. Note: The old scheme used the callback function only
  • Specific expressions:
  1. Syntactically: Promise is a constructor
  2. Functionally: The Promise object encapsulates an asynchronous operation and retrieves its success/failure result

2. Asynchronous programming scenario:

  1. Fs (a built-in module in Node.js that can manipulate local files) file operations:

    // Use the callback function to handle asynchronous problems
    require('fs').readFile('./xxxx.txt'.(err, data) = > {});
    Copy the code
  2. The AJAX request:

    // jQuery's GET request wrapper uses callback functions to handle asynchronous problems
    $.get('/xxxx'.(data) = > {});
    Copy the code
  1. Timer:

    // Use the callback function to handle asynchronous problems
    setTimeout(() = > {}, 2000);
    Copy the code
  2. Database operations

In each of these scenarios, you can use promises instead of callback functions to handle asynchronous programming. For a description of the concept of asynchrony, check out my other blog post:

Reference: AJAX learning Notes _ Ian Lai’s blog -CSDN Blog

3,Three states of the Promise object

You can think of a Promise object as a state store that holds the execution result of an event that, of course, did not happen at the moment. When a Promise object is created, the state of the Promise object is pending — pending/undecided; This is a pity. (Also called Resolved — resolved) The Promise object state will be fulfilled. If this fails, the reject() function is called, and the Promise object state changes to Rejected — it has failed.

Description in RUan Yifeng’s ES Primer:

Promise objects have two characteristics.

(1) The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: Pending, fulfilled and Rejected. == Only the result of the asynchronous operation can determine which state == is currently in. No other operation can change this state. That’s where the name “Promise” comes from. Its English name means “Promise,” indicating that nothing else can change it.

(2) Once the state changes, it will never change again, and this result can be obtained at any time. There are only two possibilities for the state of the Promise object to change from pending to depressing and from pending to Rejected ==. As long as these two things are happening the state is fixed, it’s not going to change, it’s going to stay the same and that’s called resolved. If the change has already occurred, you can add a callback to the Promise object and get the same result immediately. This is quite different from an Event, which has the characteristic that if you miss it and listen again, you will not get the result.

In fact, all three states are the value of a property called PromiseState in the Promise object instance, which has different values at different times.

The transition process of the three states of the Promise object is shown below:

Pictures from silicon Valley related courses

Why use Promise

1. More flexibility in the way callback functions are specified

  1. Old: Must be specified before starting asynchronous tasks
  2. Promise: Start asynchronous task => return promie object => Bind callback function to Promise object (can even specify/multiple after asynchronous task ends)

2,Support == chain call ==, can solve the callback hell problem

Based on the Promise state transition diagram above, we can see that the then() function returns a new Promise object after the callback is called. This means that we can then call the then() function again to handle the new Promise asynchronous operation. So we could write code like this:

let p = new Promise((resolve, reject) = >{...// Asynchronous operation
});

p.then((value) = >{.../* Callback after successful operation */}, (reason) = >{.../* Callback after operation failure */})
	.then((value) = >{... },(reason) = >{... }) .then((value) = >{... },(reason) = >{... })Copy the code

If you program asynchronously with traditional callback functions, you may have nested calls within the callback function. The result of the asynchronous execution of the external callback function is the condition for the nested callback execution, that is, nesting another asynchronous task within a callback function, resulting in the so-called == callback hell ==.

The callback hell

This is not only bad for reading (indenting too much), but also bad for exception handling (you might write some exception handling code repeatedly).

Iii. Basic use of Promise

Call the Promise constructor to create an instance of an object of type Promise, passing in a callback function as an argument. This callback takes arguments of type == to resolve and reject, which are provided by the JavaScript engine and don’t need to be deployed. You can customize their names, but they are typically called resolve and reject.

The resolve() function is called when the asynchronous operation succeeds to change the state of the Promise object from Pending to fulfilled/ Resolved, and the result value of the asynchronous operation is taken as an argument (its name can be customized, But it’s usually called value.

On failure, the reject() function is called, changing the state of the Promise object from Pending to Rejected. The reason for the error reported by the asynchronous operation is passed as an argument (its name can be customized, but is generally called Reason).

// Call the Promise constructor to create an object of type Promise, passing a callback function as an argument
let promise = new Promise((resolve, reject) = > {
  // ... some code
  if (/* Asynchronous operation succeeded */){
    resolve(value);
  } else {
    reject(reason);
});
Copy the code

The then() method of the Promise object is then called, passing in two parameters that are function types. The first function is a callback when an asynchronous operation succeeds; The second parameter is used as a callback when an asynchronous operation fails.

promise.then((value) = > {
  /* Asynchronous operation succeeds (i.e. : callback when the Promise object is fulfilled/resolved */
}, (reason) = > {
  /* The asynchronous operation fails (i.e. the callback to the Promise object whose state is Rejected */)
});
Copy the code

Use Promise to encapsulate asynchronous operations

The main idea is to put the asynchronous operation in a function argument inside a Promise constructor, call reject() on failure and resolve on success, passing in the result of success and the cause of failure. Finally, the entire Promise object is returned as a return value.

1. Encapsulate the FS file operation module in Node.js

/** * encapsulates a function myReadFile that reads the contents of the file * argument: path file path * returns: Promise object */

function myReadFile(path) {
  return new Promise((resolve, reject) = > {
    require('fs').readFile(path, (error, data) = > {
      if(error) { reject(error); } resolve(data); })}); } myReadFile('./resource/content.txt')
.then(value= > {
  console.log(value.toString());
}, reason= > {
  console.warn(reason);
})
Copy the code

2. Encapsulate AJAX requests

SendAJAX sends an AJAX request * parameter URL resource address * parameter method request method * Return result Promise object */

function sendAJAX(method, url) {
  return new Promise((resolve, reject) = > {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response); } reject(xhr.status); }}}); } sendAJAX('GET'.'https://api.apiopen.top/getJoke')
  .then(value= > {
    console.log(value);
  }, reason= > {
    console.log(reason);
  })
Copy the code

ReferenceError: XMLHttpRequest is not defined: Node.js does not have an XMLHttpRequest object, so this code cannot be executed using the Node command.

Use util.promisify() in Node.js to encapsulate error-first asynchronous operations

Util is a built-in module in Node.js. Uti.promisify () wraps an error-first style callback into another function that returns a Promise value.

Description in official documentation:

Use functions that follow the common error-first callback style (that is, place (err, value) =>… Callback as the last argument) and returns a version that returns the promise.

Reference: util.promisify() utility

For example, readFile(path, (error, data) => {}) of fs module in Node.js is a typical error-first asynchronous operation. You can then wrap the readFile() function as a function that returns a Promise object by doing the following.

/** * util.promisify method */
// Import the util module
const util = require('util');
// Import the fs module
const fs = require('fs');
// Return a new function
let mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/content.txt').then(value= >{
  console.log(value.toString());
});
Copy the code

PromiseState vs. PromiseResult

PromiseState stores Promise status (pending, regrettable /resolved, rejected).

For an explanation of the Promise state, please refer to the first part [What is Promise] : 1-3. The three states of the Promise object (hold down the Ctrl key and click to jump).

PromiseResult stores the result of an asynchronous operation

Whether the asynchronous operation fails or succeeds, a result is generated, which is stored in the PromiseResult property of the Promise object. Resolve (value) and Reject (Reason) are the only two functions that change the value of this property. The value of this property can then be read in a callback to the then() function.

21 August 2021 22:33:46- Added: Suddenly, instead of displaying PromiseState and PromiseResult in Chrome, Edge browser 80.0.361.62 (official build) (64-bit) It’s PromiseStatus and PromiseValue. In addition, the state of “Edge” is “Resolved” and the state of “Success” in Chrome is “depressing”. But none of this matters much.

A few apis in Promise

1.Executor executes the executor function

The executor function is the callback passed to the Promise constructor when the Promise object is created :(resolve, reject) => {}.

Where resolve() is the function we call when internally defined success: value => {}; The reject function is what we call when the internal definition fails: reason => {}.

Note: The == Executor executor immediately calls == synchronously within the Promise, and asynchronous operations are performed in the executor. This is important.

Take this code for example:

let promise = new Promise((resolve, reject) = > {
  console.log('Internal executor synchronization called');
});
console.log('The code outside the Promise object executes.');

// Output the resultThe executor called internally synchronouslyPromiseObject external code executesCopy the code

2, then() method

Then () is a method on Promise prototype (promise.prototype. Then) :(onResolved, onRejected) => {}.

The onResolved function is the callback function when it succeeds :(value) => {}; The onRejected function is a callback function when (reason) => {}. The then() method returns a new Promise object.

For a discussion of several cases where the result is returned, go to the result of the then() method.

3. Catch () method

Catch () is a method on promise.prototype. Catch :(onRejected) => {}.

(reason) => {} then(undefined, onRejected) => {} The underlying layer is also encapsulated with THEN (). Like a neutered version of then(), a callback can only be triggered if the state of the Promise object is changed to fail.

let p = new Promise((resolve, reject) = > {
  // Change the state of the Promise object
  reject('error');
});

// Execute the catch method
p.catch(reason= > {
  console.log(reason);
});

// Output the result
error
Copy the code

4,The resolve () method

Resolve () is a method on the Promise function object (promise.resolve) :(value) => {}.

Where value is data in a successful state or a successful promise object. It also returns an object of type Promise (but its state can be either successful or failed).

// If the argument passed is a non-PROMISE object, the result returned is a successful Promise object
let p1 = Promise.resolve(521);
// The state of P1 will be fulfilled, and the result (PromiseResult) will be 521

// If the argument is passed as a Promise object, the result of the argument determines the result of resolve
let p2 = Promise.resolve(new Promise((resolve, reject) = > {
  // resolve('OK');
  reject('Error');
}));
// If the state of the incoming Promise object is successful, then p2 is also successful and its result is the result value of the internal Promise object
// If the state of the incoming Promise object is failed, then p2 is also failed and its result is the result value of the internal Promise object
Copy the code

5,Reject () method

Reject () is a method on the Promise function object (promise.reject) :(reason) => {}.

The reason for the failure is _____. It returns an object of type Promise in a failed state.

Resolve, unlike promise.resolve, returns a failed Promise no matter what type of data you pass in, and the result of that failed Promise is the same as what you pass in.

// No matter what type of data you pass in, it returns a failed state Promise object,
// And the result of that object (PromiseResult) is the data we pass in
let p = Promise.reject(521);
let p2 = Promise.reject('iloveyou');

// Even if you pass in a Promise and set its state to success, reject returns a Promise that fails.
// And the outcome of that object (PromiseResult) is the Promise object we pass in
let p3 = Promise.reject(new Promise((resolve, reject) = > {
  resolve('OK');
}));
Copy the code

6,All () method

All () is a method on the Promise function object (promise.all) :(promises) => {}.

Promises are an array of promise objects. It returns a new promise. Promises will only succeed if all promises in the entered promises array are successful. Any promise that fails will fail.

And if the returned promise object is a success, the resulting value is an array of promises. If a promise object is returned that failed, the result value is the result value of the first promise object in promises array that is in a failed state.

// p1, p2, p3 are all successful states
let p1 = new Promise((resolve, reject) = > {
  resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');

// p4 and p5 are in failed state
let p4 = Promise.reject('Error');
let p5 = Promise.reject('Oh NO');

// Result1 is a promise type object, and its PromiseState state is very sad /resolved,
// The result (PromiseResult) is ['OK','Success','Oh Yeah']
const result1 = Promise.all([p1, p2, p3]);

// Result2 is an object of type PromiseState whose state is PromiseState (PromiseState),
// The result (PromiseResult) is Error
const result2 = Promise.all([p1, p4, p5]);
Copy the code

Chromium 86.0.4240.198 in Chrome

The result is displayed in Edge browser version 80.0.361.62 (official internal version) (64-bit)

Note the difference between Edge and Chrome browsers in terms of state and outcome of promise objects. PromiseState and PromiseResult in Chrome Corresponds to PromiseStatus and PromiseValue in Edge browser. In addition, the state of “Edge” is “Resolved” and the state of “Success” in Chrome is “depressing”.

In the figure above, there is an Uncaught (in Promise) Error because we did not add a callback to the failure case in the code above.

7,Race () method

Race () is a method on the Promise function object (promise.race) :(promises) => {}.

Promises are an array of promise objects. It returns a new promise. The state and result of the first promised object in the Promises array to complete the state change are the state and result of the returned promise. Like several Promise objects in an array in a race to complete the state transition first, the function returns the same result. The word race can also mean a race.

// p1, p2, p3 are all successful states
let p1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK');
  }, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');

// p4 and p5 are in failed state
let p4 = Promise.reject('Error');
let p5 = Promise.reject('Oh NO');

// Result1 is a promise type object, and its state (PromiseState) is the same as P2, which is very sad /resolved.
// The result (PromiseResult) is the same as p2, which is a Success
const result1 = Promise.race([p1, p2, p3]);

// Result2 is a promise-type object whose state (PromiseState) is the same as that of P4, which is promise-type object (PromiseState),
// The result (PromiseResult) is the same as p4, which is Error
const result2 = Promise.race([p1, p4, p5]);
Copy the code

Seven, a few key issues

1.Three ways to change a Promise state

Ruan Yifeng “ES6 Introductory Tutorial” has such a sentence: == Only the result of asynchronous operation can determine which state == is currently in, and no other operation can change this state. There are three kinds of operations that produce results.

Resolve () function

By actively calling resolve() in an asynchronous operation, we can change the current Promise object from its pending state to a pity/Resolved state.

1.2, reject() function

By actively calling reject() in an asynchronous operation, we can change the pending state of the Promise object to rejected.

1.3. Actively throw an exception with a throw statement

You can force the current Promise object from its pending state to its Rejected state by actively throwing an exception in an asynchronous operation using a throw statement.

let p = new Promise((resolve, reject) = > {
  / / 1. Resolve function
  // resolve('ok'); // pending => fulfilled (resolved)
  / / 2. Reject function
  // reject("error"); // pending => rejected
  //3. Throw an Error, either a string of Error messages or an Error object
  throw 'Something's wrong';
});
console.log(p);

// Output from the console in Edge
Promise {<rejected>: "Something's wrong."}
__proto__: Promise
[[PromiseStatus]]: "rejected"
[[PromiseValue]]: "Something's wrong."
Copy the code

2,Specify multiple callbacks for a Promise object

When multiple success or failure callbacks are specified for a Promise object, these callbacks are invoked when the Promise object changes to the corresponding state.

let p = new Promise((resolve, reject) = > {
  resolve('OK');
});
// Multiple calls to the then() method specify multiple successful callbacks to p
// Specify callback - 1
p.then(value= > {
  console.log('Callback function 1', value);
});

// Specify callback - 2
p.then(value= > {
  console.log('Callback function 2', value);
});

// Console outputThe callback function1OK callback function2 OK
Copy the code

3. The Promise object changes state and specifies the order in which the corresponding callback functions are assigned

Is the Promise object changed state first, or is the corresponding callback specified first? Suppose we call resolve() to change the Promise state and then() to specify the corresponding callback function. Resolve () is called first, or then() is called first. The answer is both.

3.1. Change the state first, and then specify the callback condition

① Call resolve()/reject() directly in the executor synchronization code.

let p = new Promise((resolve, reject) = > {
  // The following code is synchronous, rather than wrapped in an asynchronous operation,
  // The state of the Promise object will be fulfilled gradually, and then() function will be specified below
  resolve('OK');
});

p.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
});
Copy the code

Wrap resolve() in an asynchronous operation (such as a timer), but also add an asynchronous operation (such as a longer timer) to then().

let p = new Promise((resolve, reject) = > {
  // This code is asynchronous. After 1 second, the state of the Promise object will change to depressing,
  // The lower then() function is executed after 2 seconds, so the state is modified before the corresponding callback is specified
  setTimeout(() = > {
    resolve('OK');
  }, 1000);
});

setTimeout(() = > {
  p.then(value= > {
    console.log(value);
  }, reason= > {
    console.log(reason);
  });
}, 2000);
Copy the code

3.2. Specify a callback and then change the state

Resolve () is wrapped in asynchronous operations (such as timers), but then() is synchronous code.

let p = new Promise((resolve, reject) = > {
  // This code is asynchronous. After 1 second, the state of the Promise object will change to depressing,
  // The then() function below is synchronous code, so the corresponding callback is specified before the state is modified
  setTimeout(() = > {
    resolve('OK');
  }, 1000);
});

p.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
});
Copy the code

3.3,When a successful or failed callback is executed == and the data is retrieved

Note that this is all about the timing of the == specified success/failure callback, which tells the Promise object what to do when the state changes, and the timing of the execution is when the Promise object will actually start doing what it specified when the state changes. When does a successful or failed callback get executed by == and get passed data?

(1) If the callback is specified first, the callback function will be called immediately after the state changes and the data will be retrieved.

(2) If the state is changed first, the callback function will be called immediately and the data will be retrieved when the callback is specified.

4,The result of the then() method

Earlier, we discussed two function type arguments to the thne() method, and its return is also worth noting.

First, the then() method returns a Promise object whose state, PromiseState, and result, PromiseResult == are determined by the execution of the callback function specified by then().

An analogy can be made to the results returned by the promise.all () and promise.race () apis mentioned earlier.

4.1. The callback to THEN returns an arbitrary value of a non-PROMISE type

If the callback specified in THEN () returns an arbitrary value of a non-Promise type, then the state of the new Promise returned by then(result in the code below) will be fulfilled/resolved. The result value of the PromiseResult is the value returned by the callback function called in then().

let p = new Promise((resolve, reject) = > {
  // the state and result of p do not affect the state and result of result
  resolve('ok');
});

// Execute the then method
let result = p.then(value= > {
  // The result of the callback function in then() is a non-Promise object
  // The state of the PromiseState becomes depressing,
  // The result of the PromiseResult value is 521 as returned below
  return 521;
}, reason= > {
  console.warn(reason);
});
console.log(result);

// Output the result
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 521
Copy the code

The then callback returns a value of type Promise

If the callback specified in then() returns another new Promise, the state and result of that Promise will be the state and result of the new Promise returned by THEN (result in the code below).

let p = new Promise((resolve, reject) = > {
  // the state and result of p do not affect the state and result of result
  resolve('ok');
});

// Execute the then method
let result = p.then(value= > {
  // The callback function in then() returns an object of type Promise
  return new Promise((resolve, reject) = > {
    // The state of the PromiseState becomes depressing,
  	// The result value of PromiseResult is success
    // resolve('success');
    
    // The result state changes to reject.
  	// The result value of PromiseResult is error
    reject('error');
  });
}, reason= > {
  console.warn(reason);
});

// This is the callback that specifies the success and failure of result,
// If you do not specify a failed callback, Chrome will fail to output result because of an error
result.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
})

console.log(result);

// Output the result
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "error"
Copy the code

The then callback uses the throw statement to manually throw an exception

If you manually throw an exception in the callback specified by THEN () with a throw statement, then() returns a new Promise (result in the code below) with the state PromiseState changed to Rejected, The result value of PromiseResult is the thrown exception string or exception object.

let p = new Promise((resolve, reject) = > {
  // the state and result of p do not affect the state and result of result
  resolve('ok');4});
	// Execute the then method
let result = p.then(value= > {
  // The callback function in then() manually throws an exception with the throw statement
  // The result state changes to reject.
  // result = PromiseResult
  throw 'Something's wrong! '
}, reason= > {
  console.warn(reason);
});
// This is the callback that specifies the success and failure of result,
// If you do not specify a failed callback, Chrome will fail to output result because of an error
result.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
})
console.log(result);
// Output the result
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "Something's wrong!
Copy the code

5. Chain call of Promise

Earlier, we mentioned one important reason for using Promises: Promise supports chained calls (hold down the Ctrl key and click to jump). Since the THEN () method returns a new Promise object, we can then call the then() method again on the returned Promise object. And based on our discussion of the result returned by the then() method, the result of the returned Promise object is determined by the result of the callback function specified by then().

What about the state and result of the return Promise when we make the chain call?

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK');
  }, 1000);
});

p.then(value= > {
  return new Promise((resolve, reject) = > {
    resolve("success");
  });
}).then(value= > {
  // The console output is SUCCESS, because the first then() function returns a successful Promise object with the result value success
  console.log(value);
});

p.then(value= > {
  return new Promise((resolve, reject) = > {
    resolve("success");
  });
}).then(value= > {
  // The console output is SUCCESS, because the first then() function returns a successful Promise object with the result value success
  console.log(value);
}).then(value= > {
  // The console output is undefined because the second then() callback does not return a specific value,
  // returns undefined and a successful Promise object
  // So the second then() function returns a Promise object with undefined
  console.log(value);
});
Copy the code

As you can see, when the chained call is made, the Promise object is still returned in exactly the same three cases as summarized earlier in the then() method.

6. Abnormal penetration

When making a chain call, you can specify a failed callback at the end. This way, if a failed state Promise appears in the previous then() and no failed callback is specified, the last specified failed callback will be invoked. The last failed callback specified is like a backstop, which is left to handle if the brothers in front are not helpful.

For this last specified failed callback, we would normally specify the failed callback using the catch() method.

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK');
    // reject('Err');
  }, 1000);
});

p.then(value= > {
  // console.log(111);
  throw 'Failure! ';
}).then(value= > {
  console.log(222);
}).then(value= > {
  console.log(333);
}).catch(reason= > {
  console.warn(reason);
});

// Output the resultFailure!Copy the code

Furthermore, the result of a failure is passed == layer by layer, which means that the failed callback specified in the final catch() will not be called if there is already a callback to handle the failure before the final catch(). See the blog below for more insight:

Reference: Test analysis Promise exception penetration principle – 17135131xJT – Blog Park

7. Break the Promise chain

In the following chained call, what if we only want to output 111? That means you have to break subsequent chain calls.

The interrupt chain call == has one and only method: return a Promise object == with a pending state in the callback to then().

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK');
  }, 1000);
});

p.then(value= > {
  console.log(111);
  // Return a Promise object with a pending state to interrupt the call chain
  return new Promise(() = > {});
}).then(value= > {
  console.log(222);
}).then(value= > {
  console.log(333);
}).catch(reason= > {
  console.warn(reason);
});

// Output without interrupts
111
222
333
// Output after interrupt
111
Copy the code

Write promises by hand

1. Observe the structure of the Promise object

Take a closer look at the structure of the Promise object:

Promise object structure

2. Break down your thinking

If we were to write code to implement Promise, there would be several modules:

① Write a constructor called Promise.

② Declare two built-in variables: PromiseState (used to store the current state of a Promise object) and PromiseResult (used to store the outcome value of a Promise object).

③ Pass an executor executor function to the Promise constructor. And == make a synchronous call to executors in a Promise == (we mentioned earlier that the == Executor executor function immediately calls == synchronously within a Promise). The Executor executor function is also passed arguments of two function types: resolve and reject (the function name is optional, as long as it is called with the same name).

(4) Declare resolve and reject in the constructor, pass in data as the result of the Promise object, and complete the state change and result of the current Promise instance (PromiseState property) in the constructor. Assignment of the PromiseResult property.

In addition to the resolve and reject functions mentioned in ④, manually throwing exceptions can also change the state of a Promise object. In addition to the resolve and reject functions mentioned in ④, the state of a Promise object can be changed. So we should wrap the executor function try… The catch block catches the error message, and the reject function is called to change the state to Rejected, passing the error message as an argument.

(6) Because Promise objects are allowed to change their state only once, we must condition the modification of the PromiseState property in resolve and Reject.

⑦ When the state of the Promise object is modified, the corresponding callback function should be triggered, which is an important part of the asynchronous Promise implementation. That is, success and failure callbacks in implementing then functions.

Then () ==

⑨ Implements the catch function and handles exception penetration.

⑨ implements several methods (resolve, Reject, All, and Race) on the Promise function object.

⑩== Let the callback function in THEN () enter the asynchronous queue ==.

3. Implementation code

Declare the Promise constructor and set two built-in objects

function Promise() {
  // The default state of the created Promise object is pending
  this.PromiseState = 'pending';
  this.PromiseResult = null;
}
Copy the code

3.2. Pass the Executor executor function to the Promise constructor and call it synchronously

function Promise(executor) {
  // this.PromiseState = 'pending';
  // this.PromiseResult = null;

  executor();
}
Copy the code

Declare resolve and reject and pass it to executor

Pass resolve and reject to executor. And declare both functions in the constructor beforehand.

function Promise(executor) {
  // this.PromiseState = 'pending';
  // this.PromiseResult = null;

  // Note the deliberate use of the self variable to hold the reference to this of the current Promise instance object
  // because when the constructor instantiates the Promise object, this points to the window
  // This causes the resolve and reject functions to be called without modifying the two properties on the Promise instance
  let self = this;

  // The resolve function is used to modify the state of the Promise object to depressing and assign the result value
  function resolve(data) {
    self.PromiseState = 'fulfilled';
    self.PromiseResult = data;
  }

  The reject function modifies the state of the Promise object to Rejected and assigns the result value
  function reject(data) {
    self.PromiseState = 'rejected';
    self.PromiseResult = data;
  }

  executor(resolve, reject);
}
Copy the code

3.4. Handle instantiation errors

In 3.3, we implemented the resolve and Reject functions to change the state of a Promise object, but instantiation should also change the state if an error is thrown in the Executor, which should be changed to Rejected. So we need to catch and handle errors at the executor call.

function Promise(executor) {
  /* this.PromiseState = 'pending'; this.PromiseResult = null; let self = this; function resolve(data) { self.PromiseState = 'fulfilled'; self.PromiseResult = data; } function reject(data) { self.PromiseState = 'rejected'; self.PromiseResult = data; } * /

  try {
    executor(resolve, reject);
  } catch(error) { reject(error); }}Copy the code

3.5. Ensure that the state of a Promise object can be changed only once

Before that, in the talk [1-3, the three states of the Promise object (hold down the Ctrl key click to jump)], Ruan Yifeng “ES6 introductory tutorial” on the characteristics of the Promise object made two description, one of which is:

Promise objects have two characteristics.

(2) == Once the state changes, it will not change again ==, and this result can be obtained at any time. There are only two possibilities for the state of the Promise object to change from pending to depressing and from pending to Rejected. As long as these two things are happening the state is fixed, it’s not going to change, it’s going to stay the same and that’s called resolved. If the change has already occurred, you can add a callback to the Promise object and get the same result immediately.

Therefore, we must ensure that the state of a Promise object can only be changed once. That is, before modifying the PromiseState property of a Promise object, we must determine whether the current state of the Promise object allows modification (i.e. whether the current state of the Promise object is pending).

function resolve(data) {
  // Just add the following judgment to resolve and reject, respectively
  // The state of a Promise object can only be changed once
  if(self.PromiseState ! = ='pending') {
    return;
  }
  self.PromiseState = 'fulfilled';
  self.PromiseResult = data;
}

function reject(data) {
  if(self.PromiseState ! = ='pending') {
    return;
  }
  self.PromiseState = 'rejected';
  self.PromiseResult = data;
}
Copy the code

3.6. Implement successful callback and failed callback in then function

The implementation of the THEN function is an important part of the Promise implementation of asynchronous programming, only the state transition to specify the corresponding callback function can handle the results of the asynchronous operation.

Let’s look at how we use the then method with native promises:

let p = new Promise((resolve, reject) = > {
  resolve('success');
});

p.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
})
Copy the code

We need to pass two function parameters to the THEN function, and both function parameters will receive one parameter that is the result of an asynchronous operation (the value of the PromiseResult property). And crucially, we should determine which of the two function parameters to call based on the state of the Promise object.

OnResolved below is a callback when the Promise object state is failed and onRejected is a callback when the Promise object state is successful. Note that this is used in the then function below, so why don’t we use the self variable to hold the reference to this as we did in resolve and reject above? Notice that when we call then above, we call it from p.teng (…). So this in the then function naturally points to the current Promise instance object. This has to be understood.

Promise.prototype.then = function (onResolved, onRejected) {
  if(this.PromiseState === 'fulfilled') {
    onResolved(this.PromiseResult);
  }
  if(this.PromiseState === 'rejected') {
    onRejected(this.PromiseResult); }}Copy the code

3.7. Perform asynchronous operations in Executor

In the implementation above, our custom promises did what we expected, but once we performed an asynchronous operation in the Executor executor, we didn’t get the expected results.

For example, in the code below, we wrap resolve() with a two-second timer in the Executor executor, and expect to see success in the console after two seconds. But using our custom promises doesn’t produce the expected results. Why? Recall what we discussed in 7-3-3.3 when successful or failed callbacks are executed == and data is available (key understanding). So the following code is a case of specifying the callback and then changing the state.

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('success');
  }, 2000);
});

p.then(value= > {
  console.log(value);
}, reason= > {
  console.log(reason);
})
Copy the code

When our synchronization code executes to p.teng (…) , the code in the timer has not been executed, so at this time, the state of P is not changed to depressing, but still remains as the initial pending. However, since there is no judgment on pending state in our customized THEN function, it is natural that p in the current state cannot be processed.

If we were to use our current custom Promise, the code flow would look something like this:

A code flow diagram using the current custom Promise

Therefore, we should consider when to call a failed or successful callback in the then function. According to the following two principles:

(1) If the callback is specified first, the callback function will be called immediately after the state changes and the data will be retrieved.

(2) If the state is changed first, the callback function will be called immediately and the data will be retrieved when the callback is specified.

We should call the then callback == when the == state changes, which is resolve and reject in our custom Promise constructor. However, the callbacks in THEN are defined on promise. prototype, while resolve and reject are defined directly on Promise function objects. They have different scopes. So the then callbacks cannot be called in resolve and reject. At this point, we need == to add the pending state judgment to then and store the two callback function variables in then on the Promise instance object ==. Specific new implementations are as follows:

function Promise(executor) {
  /* this.PromiseState = 'pending'; this.PromiseResult = null; let self = this; * /
  
  this.callback = null;
  
  function resolve(data) {
    /* if (self.PromiseState ! == 'pending') { return; } self.PromiseState = 'fulfilled'; self.PromiseResult = data; * /
    
    // Note that we can't use this either, because this refers to window,
    // This is a pity when the current state of the Promise object is changed.
    // The successful callback that was specified should be called: onResolved for asynchronous tasks
    if(self.callback) { self.callback.onResolved(data); }}function reject(data) {
    /* if (self.PromiseState ! == 'pending') { return; } self.PromiseState = 'rejected'; self.PromiseResult = data; * /
    
    // Note that we can't use this either, because this refers to window,
    // When the state of the current Promise object is changed to Rejected,
    // You should call the successful callback you specified, onRejected, for asynchronous tasks
    if(self.callback) { self.callback.onRejected(data); }}/* try { executor(resolve, reject); } catch (error) { reject(error); } * /
}

Promise.prototype.then = function (onResolved, onRejected) {
  /* if (this.PromiseState === 'fulfilled') { onResolved(this.PromiseResult); } if (this.PromiseState === 'rejected') { onRejected(this.PromiseResult); } * /
  if (this.PromiseState === 'pending') {
    this.callback = { onResolved, onRejected }; }}Copy the code

So, for the example mentioned above, the program execution flow is as follows:

Graph LR A[execute Promise<br> constructor] A --> B[execute setTimeout<br> asynchronous task] --> C[wait 2 seconds] --> This will be A big pity. This will be A big pity. This will be A big pity --> F --> G --> H --> I[PromiseState<br> is pending] --> J[save two callback functions <br> in the incoming THEN on P.callback] --> F

3.8. When multiple callbacks are specified for a Promise object

In 7-2, Specify multiple callbacks for a Promise object (Ctrl + click to jump), we know:

When we specify multiple success or failure callbacks for a Promise object, these callbacks will be invoked when the Promise object changes to the corresponding state.

In 3.7 above, we can only guarantee that the callback in the last then function will be executed, so we should improve the 3.7 code (note that I omitted some irrelevant code, and the original writing is commented at the top of the improved code, note the contrast) :

function Promise(executor) {...// this.callback = null;
  this.callbacks = [];
  
  function resolve(data) {...// if (self.callback) {
    // self.callback.onResolved(data);
    // }
    self.callbacks.forEach(item= >{ item.onResolved(data); })}function reject(data) {...// if (self.callback) {
    // self.callback.onRejected(data);
    // }
    self.callbacks.forEach(item= >{ item.onRejected(data); })}... }Promise.prototype.then = function (onResolved, onRejected) {...if (this.PromiseState === 'pending') {
    // this.callback = { onResolved, onRejected };
    this.callbacks.push({ onResolved, onRejected }); }}Copy the code

3.9. Process the return result of then

In then(), we discuss three cases where the then function returns a result: ① Return a result of type Promise. ② Return a result of a non-promise type. ③ Throw an error with the throw statement.

First wrap a return new Promise(() => {… }); In either case, the then function returns an instance object of type Promise. Something like this:

// Then returns an instance of type Promise.
Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) = >{... }); }Copy the code

Then put the code originally written in then on top [……] Later, this part of the code is modified on the basis of the original.

3.9.1 Synchronous code is executed in executor
// Synchronous code is executed in executor
let p = new Promise((resolve, reject) = > {
  resolve('success');
});
Copy the code

The next step is to determine whether the result returned by the two callbacks in the then function is of a Promise type.

The result variable receives the results of the two callback functions (onResolved and onRejected) in the THEN function. Look at tag1 in the code below.

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) = > {
    if (this.PromiseState === 'fulfilled') {
      let result = onResolved(this.PromiseResult);	/ / "tag1"./ / "tag2"
    }

    if (this.PromiseState === 'rejected') {
      let result = onRejected(this.PromiseResult);	/ / "tag1"./ / "tag2"
    }

    if (this.PromiseState === 'pending') {
      this.callbacks.push({ onResolved, onRejected }); }}); }Copy the code

Then add the following judgment at tag2 above:

// If the callback (onResolved or onRejected) returns a Promise type, this is the case
if (result instanceof Promise) {
  // if (result.PromiseState === 'pending') return; // Terminates the call chain
  // result.PromiseState === 'fulfilled' ? resolve(result.PromiseResult) : reject(result.PromiseResult);
  
  // The following then function can also be replaced with the two lines commented out above, which is more semantic and which is more clever
	// Since result is a Promise object in this if judgment, then can be called
  result.then(value= > {
    // If result is a successful Promise, call resolve of the outermost Promise constructor,
    // Make the state of the Promise object returned by the then function become depressing,
    // The result value of result is passed in as the result value of the Promise object returned at the end of the then function
    resolve(value);
  }, reason= > {
    // If result is a failed Promise, call the outermost Promise constructor reject,
    // Change the state of the Promise object returned by then to Rejected,
    // The result value of result is passed in as the result value of the Promise object returned at the end of the then function
    reject(reason);
  });
} else {
  // If the callback (onResolved or onRejected) returns a non-promise result, this is the case
  // Call the resolve function of the outermost Promise constructor.
  // Make the state of the Promise object returned by the then function become depressing,
  // The result value of result is passed in as the result value of the Promise object returned at the end of the then function
  resolve(result);
}
Copy the code

Note that result.then(…) is used. To set the state of the Promise object that is eventually returned. There is no specific mention of terminating the call chain.

Finally, we need to use a try… The catch statement wraps the code at tag2 above:

try {
  /* if (result instanceof Promise) { ...... } else { ...... } * /
} catch (error) {
  // This is the case when an onResolved or onRejected callback throws an error
  // Call the outermost Promise constructor, reject,
  // Change the state of the Promise object returned by then to Rejected,
  // And passes the caught error as the result value of the Promise object returned at the end of the then function
  reject(error);
}
Copy the code
3.9.2 Asynchronous code is executed in executor
// The executor executes asynchronous code, such as setting a timer
let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('success');
  }, 2000);
});
Copy the code

In 8-3-3.7, Executing asynchronous operations in Executor (Ctrl + click to skip), we discussed how the flow of asynchronous callback functions is affected when an asynchronous operation is executed in executor. We solved the problem by adding a pending state determination to the THEN function and storing the two callback variables from the THEN function on the Promise instance object, but we did nothing about the result returned by the THEN function. For details, please see the following illustration:

The code flow diagram uses the current custom Promise, without processing the result returned by the THEN function

If (this.promisestate === ‘pending’) {… } The code in this judgment is improved.

The code at [tag3] in the following code is the same as that at [tag2] in 3.9.2 above. It is also used to determine whether the returns of the two callback functions passed in then are Promise objects.

if (this.PromiseState === 'pending') {
  // this.callbacks.push({ onResolved, onRejected });
  // Since we need to consider the state and value of the result returned by then,
  // So instead of saving the two callbacks directly on the current Promise object instance,
  // The state and value of the return result of the current callback function are determined
  this.callbacks.push({
    onResolved: function () {
      try {
        // Note that we can't use this because this refers to window,
        // You should deliberately use a self variable to hold the this reference to the current Promise instance object
        letresult = onResolved(self.PromiseResult); ./ / 【 tag3 】
      } catch(error) { reject(error); }},onRejected: function () {
      try {
        // Note that we can't use this because this refers to window,
        // You should deliberately use a self variable to hold the this reference to the current Promise instance object
        letresult = onRejected(self.PromiseResult); ./ / 【 tag3 】
      } catch(error) { reject(error); }}}); }Copy the code

This way, when the resolve or Reject functions in the asynchronous task we set up are called, the corresponding callbacks specified above are also called, setting the state and result values for the Promise objects returned by then.

3.9.3 Encapsulate repetitive code in THEN

At this point, we can see that the following code structure is repeated several times in 3.9.1 and 3.9.2 above:

try {
  // The only line that is different is the one that receives the result of the callback function. XXXX stands for onResolved or onRejected
  let result = xxxx(this.PromiseResult);
  
  if (result instanceof Promise) {
    result.then(value= > {
      resolve(value);
    }, reason= > {
      reject(reason);
    });
  } else{ resolve(result); }}catch (error) {
  reject(error);
}
Copy the code

This is a big pity (if (this.PromiseState === ‘depressing ‘) {… }, if (this. PromiseState = = = ‘rejected’) {… }, if (this.promisestate === ‘pending’) {… }), the only difference is the line that receives the result of the callback function, so we can wrap the above code into a function and abstract the parts that need to be flexible into a function argument. This makes the code much cleaner.

Promise.prototype.then = function (onResolved, onRejected) {
  let self = this;

  return new Promise((resolve, reject) = > {
    // Encapsulates repetitive code. The function sets the return value of the then function
    function setReturnValOfThen(callbackType) {
      try {
        // Note that we can't use this because this refers to window,
        // You should deliberately use a self variable to hold the this reference to the current Promise instance object
        let result = callbackType(self.PromiseResult);
        // console.log(' result returned by callback ', result);
        if (result instanceof Promise) {
          // if (result.PromiseState === 'pending') return;
          // result.PromiseState === 'fulfilled' ? resolve(result.PromiseResult) : reject(result.PromiseResult);
          // console.log(' the callback returns a Promise object ');
          result.then(value= > {
            resolve(value);
          }, reason= > {
            reject(reason);
          });
        } else {
          // console.log(' the callback does not return a Promise object ');resolve(result); }}catch(error) { reject(error); }}if (this.PromiseState === 'fulfilled') {
      setReturnValOfThen(onResolved);
    }

    if (this.PromiseState === 'rejected') {
      setReturnValOfThen(onRejected);
    }

    if (this.PromiseState === 'pending') {
      // this.callback = { onResolved, onRejected };
      // this.callbacks.push({ onResolved, onRejected });
      this.callbacks.push({
        onResolved: function () {
          setReturnValOfThen(onResolved);
        },
        onRejected: function () { setReturnValOfThen(onRejected); }}); }}); }Copy the code

3.10. Realize catch function and exception penetration

Catch functions can be reviewed in [6-3]. Abnormal penetration is reviewed in vii -6.

3.10.1. Realize catch function

First, the catch function, like the then function, is a method on the Promise prototype.

If you pass undefined to the first argument of the then function, you can use the catch function. You can then treat the callback passed to the catch as the second argument to the then function.

Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
}
Copy the code
3.10.2 Achieve abnormal penetration

Currently our code does not allow exception penetration.

let p = new Promise((resolve, reject) = > {
    resolve('OK');
});

let result1 = p.then(value= > {
  // console.log(111);
  throw 'Failure! ';
})
let result2 = result1.then(value= > {
  console.log(222);
})
let result3 = result2.then(value= > {
  console.log(333);
})
let result4 = result3.catch(reason= > {
  console.warn(reason);
});

// Due to the nature of exception penetration, the expected result should be: output failed on the console
TypeError: callbackType is not a function
Copy the code

Using native Promises, each of the above results looks like this:

The result of native promises

Using our custom Promise, the result is shown below:

Customize the result of a Promise

Result1.then (…) There is a problem because we do not pass a failed callback to the THEN. Since result1 is a failed state Promise object, when we call result1.then(…) Call result1.then(…) We pass undefined by default, so when we call result1.then(…) Is equivalent to undefined(…) TypeError: callbackType is not a function. TypeError: callbackType is not a function.

To solve this problem, we need to deal with the default arguments to the THEN function, that is, when the onResovled or onRejected arguments we pass to the THEN are not function types.

Promise.prototype.then = function (onResolved, onRejected) {
  // let self = this;

  // Add the following statements to ensure that the two arguments we pass to the then function are not function types
  // But you can still guarantee that the return Promise object will have the correct state and result value if you need to invoke the related callback later
  onResolved = typeof onResolved === 'function' ? onResolved : value= > value;
  onRejected = typeof onRejected === 'function' ? onRejected : reason= > { throw reason };

  /* return new Promise((resolve, reject) => { Function setReturnValOfThen(callbackType) {...... } if (this.PromiseState === 'fulfilled') { setReturnValOfThen(onResolved); } if (this.PromiseState === 'rejected') { setReturnValOfThen(onRejected); } if (this.PromiseState === 'pending') { ...... }}); * /
}
Copy the code

3.11. Implement resolve function

Previously, we discussed the resolve method on the Promise function object in the 6-4, Resolve () method.

First, we know that resolve() is a method on a Promise function object (promise.resolve) and that its return value must be a Promise object.

Secondly, we know the following rules:

① If the argument passed is a non-PROMISE object, the function returns a successful Promise object.

② If the parameter passed in is a Promise object (suppose p), and if p is in a successful state, then the function returns a Promise object in a successful state, and its result is the result value of P; If p is in a failed state, then the function returns a Promise object that is also in a failed state and whose result is the result value of P.

Promise.resolve = function (value) {
  return new Promise((resovle, reject) = > {
    // If resolve is passed as a Promise object,
    // Determine the state and result of the Promise object returned by resolve based on the state and result of the passed object
    if (value instanceof Promise) {
      value.then(val= > {
        resovle(val);
      }, reason= > {
        reject(reason);
      });
    } else {
      // If resolve is passed as a Promise object,
      // Then directly set the state of the Promise object returned by the resolve function to depressing, and the result value is the passed valueresovle(value); }}); }Copy the code

3.12. Implement reject function

Previously, we discussed the Reject method on the Promise function object in 6-5, Reject ().

First, we know that reject() is a method on the Promise function object (promise.reject), and that the return value must be a Promise object.

Secondly, we know the following rules:

(1) Reject returns a failed Promise object, regardless of whether the argument is a Promise object.

Reject (reject) returns a reject (reject). The value of the Promise object is the same as the parameter we passed in.

Promise.reject = function (reason) {
  return new Promise((resolve, reject) = > {
    reject(reason);
  });
}
Copy the code

3.13. Implement the all function

Earlier, we discussed the all method on the Promise function object in the 6-6, All () method.

First, we know that all() is a method on the Promise function object (promise.all) and that its return value must be a Promise object.

Secondly, we know the following rules:

The passed argument is an array containing several Promise objects. If all the Promise objects in the passed array succeed, they will fail.

② If the returned Promise object is successful, the result value is an array of the result values of all the Promise objects in the array.

③ If the returned Promise object fails, the result value is the result value of the first failed Promise object in the array.

Promise.all = function (promiseArr) {
  // count the number of successful promises in the promiseArr
  let count = 0;
  // promiseResult stores the result value of the returned Promise object
  let promiseResult = [];
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i].then(value= > {
        // If this callback is entered, the Promise object currently iterated was successful
        count++;
        promiseResult[i] = value;
        // If count accumulates to the size of the promiseArr array,
        All Promise objects in the promiseArr are successful
        if(count === promiseArr.length) { resolve(promiseResult); }},reason= > {
        // If the state of the currently iterated Promise object is failed, change the state of the return value to Rejected immediatelyreject(reason); }); }}); }Copy the code

3.14. Implement the race function

We discussed race methods on Promise function objects earlier in the six-7 race() method (Ctrl + click to jump).

First, we know that race() is a method on a Promise function object (promise.race), and that the return value must be a Promise object.

Secondly, we know the following rules:

The parameters passed in are an array of Promise objects. Only the state and result of the first Promise object in the array to complete the state change are the state and result of the Promise returned by the race function.

Promise.race = function (promiseArr) {
  return new Promise((resolve, reject) = > {
    for (let i = 0; i < promiseArr.length; i++) {
      // If the following THEN is called, the current iterated Promise object is the first to complete the state transition
      // So you can immediately change the state of the return value to the corresponding value and set the result value simultaneously
      promiseArr[i].then(value= > {
        resolve(value);
      }, reason= >{ reject(reason); }); }}); }Copy the code

Make the callback function in THEN execute asynchronously

Observe the following code:

let p1 = new Promise((resolve, reject) = > {
  resolve('OK')
  // reject('ERROR');
  console.log(111);
});

p1.then(value= > {
  console.log(222);
}, reason= > {
  console.log(444);
});

console.log(333);
// Output of the native Promise
111
333
222

// The output of our current custom Promise
111
222
333
Copy the code

The reason for the difference is that native promises make callbacks in THEN execute asynchronously, whereas our custom promises make them execute synchronously. To make callbacks execute asynchronously, use a timer to wrap callbacks executed in THEN (that is, queue the related callbacks in an event loop until the synchronization task is complete).

There are four changes to be made when the callback function in THEN is actually called:

// Then function
Promise.prototype.then = function (onResolved, onRejected) {
  /* let self = this; . return new Promise((resolve, reject) => { function setReturnValOfThen(callbackType) { ...... } * /

    if (this.PromiseState === 'fulfilled') {
      setTimeout(() = > {
        setReturnValOfThen(onResolved);
      });
    }

    if (this.PromiseState === 'rejected') {
      setTimeout(() = > {
        setReturnValOfThen(onRejected);
      });
    }

    /* if (this.PromiseState === 'pending') { ...... } * /
  });
}
Copy the code
// Resolve and reject functions in executor
function resolve(data) {
  /* if (self.PromiseState ! == 'pending') { return; } self.PromiseState = 'fulfilled'; self.PromiseResult = data; * /
  setTimeout(() = > {
    self.callbacks.forEach(item= >{ item.onResolved(data); })}); }function reject(data) {
  /* if (self.PromiseState ! == 'pending') { return; } self.PromiseState = 'rejected'; self.PromiseResult = data; * /
  setTimeout(() = > {
    self.callbacks.forEach(item= >{ item.onRejected(data); })}); }Copy the code

Async and await

1. Async functions

Official MDN document reference: – JavaScript | MDN async function

Functions decorated with the async keyword have the following characteristics:

  1. The return value of this function is a Promise object

  2. The result of the returned Promise object is determined by the return value executed by the async function under the same rules as the callback in the then function:

    (1) If the async function returns an arbitrary value of non-promise type, then the state of the Promise object generated when the function is called will be fulfilled/resolved. The result value PromiseResult is the value returned by async.

    ② If an async function returns a new Promise (let’s say P), then the state and result of P will be the state and result of the Promise object generated when the function is called.

    (3) If you throw an exception manually in an async function, the state of PromiseState generated when the function is called will change to Rejected. The result value of PromiseResult is the thrown exception string or exception object.

Await expression

The official MDN document reference: await – JavaScript | MDN

Expressions decorated with the await keyword have the following characteristics:

  1. [Uncaught SyntaxError: await is only valid in async function]; [Uncaught SyntaxError: await is only valid in async function] And async function == does not have to have await expression.

  2. The expression to the right of the await keyword has three cases:

    ① If the expression is a successful Promise, await returns the result value of that Promise.

    ② If the expression is a failed Promise object, await the await object: [Uncaught (in Promise) XXXX], you can use try… The catch statement wraps the await expression, and the error caught in the catch statement is the result value of the failed Promise object.

    ③ If the expression is an arbitrary value of a non-PROMISE object, await returns that arbitrary value.

3, async and await combination

With async and await, we can do some asynchronous operations (reading files, sending AJAX requests, etc.) without using callback functions. These asynchronous tasks are done as if we are writing synchronous code (the asynchronous operations are actually done inside the ‘await’), which is simpler and easier to read.

The reference

Updated: August 21, 2021 at 18:33:46

Silicon Valley Web Front End Promise tutorial from Getting started to Mastering (early 2021

【Promise related online documents 】

Reference: use the Promise – JavaScript | MDN

Reference: Promise – JavaScript | MDN

Reference: Promise object – ES6 tutorial – Netpath

Reference: AJAX learning Notes _ Ian Lai’s blog -CSDN Blog

CSDN blog_ callback hell

Reference: util.promisify() utility

Updated: August 22, 2021 at 14:27:59

Reference: Test analysis Promise exception penetration principle – 17135131xJT – Blog Park

Updated: 01:09:38 On August 24, 2021

【async and await】

Reference: async function – JavaScript | MDN

Reference: await – JavaScript | MDN