Six options for asynchronous JavaScript programming

  • The callback function
  • Event listeners
  • Event publish/subscribe pattern
  • Promise
  • Generator Generators/ yield
  • async/await

Callback -> Promise -> Generator -> async/await

Promise object

What is the Promise

A promise is a solution to asynchronous programming that holds asynchronous operations internally and allows you to get messages for those asynchronous operations

The characteristics of

  • The state of an object is unaffected by external influences. There are three states. We’re in progresspendingAnd has been successfullyfulfilled, has failedrejected. Only the result of an asynchronous operation can determine the current state, and no other operation can change the state.
  • Once the state changes, it never changes again, and you can get this result at any time. There are only two possible state changes: frompendingintofulfilledAnd from thependingintorejected. When the state is frozen, it’s calledresolvedHave to finalize the design.

Advantages: unified interface, make control asynchronous operation convenient; Solve callback hell by presenting asynchronous operations as synchronous operations

Disadvantages: midway can not be cancelled, once the new execution immediately; An internal error cannot be reflected externally (without a callback function). Pending is a state where you can’t know exactly where you’re going

New Promise(request 1).then(request 2).then(request 3).then(request 4).then(request 5).catch(handle exception)Copy the code

Basic usage

Step 1, createPromiseThe instance

const promise = new Promise(function(resolve, reject) {
  // ... some code

  ifResolve (value); }else{ reject(error); }}); Resolve () changes the pending state to resolved, reject() changes the Pending state to Rejected, reject() changes the pending state to Rejected, and reject() changes the pending state to Rejected.Copy the code

Second, specify the callback function

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

thenA method can take two callback functions as arguments. The first callback is called when the Promise object's state changes to Resolved. The second callback is called when the Promise object's state changes to Rejected.Copy the code

The Promise is executed immediately after it is created

The code created internally by the Promise executes immediately, the callback function is put into the task queue, and the tasks in the call stack (i.e., synchronization tasks) are not executed until all the tasks in the task queue are completed.

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi! '); // Promise // Hi! // resolvedCopy the code

Promises are typically created as returns from functions, so they can be wrapped and used multiple times in different situations

Ajax operations implemented with Promise objects

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if(this.readyState ! = = 4) {return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else{ reject(new Error(this.statusText)); }}; const client = new XMLHttpRequest(); client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept"."application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('Wrong', error);
});
Copy the code

whenresolve()orreject()The argument is the other onePromiseInstance when the originalPromiseStatus invalid by newPromiseThe state determines the originalPromiseThe callback function executes

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 analysis is as follows: P1 will enter the Rejected state in three seconds, and P2 will enter the Resolved state in one second. As P1 is set to P1, the P2 state will become invalid in one second. P1 is still in the pending state. The p2 state also changes to Rejected, which triggers the callback. Catch () and prints out the parameters in P1 reject()Copy the code

Calling resolve or Reject does not terminate the execution of the Promise’s argument function

new Promise((resolve, reject) => { resolve(1); console.log(2); }).then(r => { console.log(r); }); / / / 1/2Copy the code

And you just put a return in front of it

new Promise((resolve, reject) => {
  returnresolve(1); // The following statement does not execute console.log(2); })Copy the code

Promise.prototype

Promise.prototype.then()

parameter

The first argument is the Callback from the Resolved state and the second (optional) is the callback from the Rejected state.

The return value

The then method returns a new Promise instance (note, not the original Promise instance).

So you can write it chained, where a then method is followed by another THEN method.

The chain operation

After the first callback completes, the second callback is passed the result as an argument.

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});
Copy the code

The former callback returns a Promise object (that is, an asynchronous operation), while the latter waits for the state of the Promise object to change before being called.

getJSON("/post/1.json").then(
  post => getJSON(post.commentURL)
).then(
  comments => console.log("resolved: ", comments),
  err => console.log("rejected: ", err)
);
Copy the code

Promise.prototype.catch()

Promise.prototype. Catch equivalent to. Then (null, rejection) or. Then (undefined, rejection).

Suggest using.catch()without.then()To catch errors

Because.catch() not only handles the state of the Promise object rejected, but also catches errors in the.then() method

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {// Handle getJSON and an error that occurred while the previous callback function was running console.log('Error! ', error);
});
Copy the code

If the Promise state has changed to Resolved, throwing an error is invalid

Errors in the Promise object are “bubbling” and are passed backwards until they are caught

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {// Handle the first three Promise errors});Copy the code

Promises eat up mistakes

The Promise definition displays syntax errors on the console, but the code does not stop running and continues to execute, meaning that errors inside a Promise do not affect code outside the Promise

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {// The following line is an error because x does not declare resolve(x + 2); }); }; someAsyncThing().then(function() {
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123
Copy the code

The return value is also onePromiseObject, which can be chain-operated

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {// The following line is an error because x does not declare resolve(x + 2); }); }; someAsyncThing() .catch(function(error) {
  console.log('oh no', error);
})
.then(function() {
  console.log('carry on'); }); // oh no [ReferenceError: x is not defined] // Carry on if no error is reported, the catch method is skippedCopy the code

Promise.prototype.finally()

The finally method is used to specify actions that will be performed regardless of the final state of the Promise object.

Callbacks specified by the finally method are also executed after the callbacks specified by then or catch.

Promise. Then (result = > {...}). The catch (error = > {...}), finally (() = > {...});Copy the code

The callback function takes no arguments

Unable to determine the state, in order to write less of the same code.

implementation

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};
Copy the code

The return value is always the original value

// use undefined promise.resolve (2). Then (() => {}, () => {}) // use undefined promise.reject ().reject() => {}). Then () => {}, () = > {}) / / reject a value of 3 Promise. Reject (3) finally (() = > {})Copy the code

Promise method

Promise.all()

Effect: Wrap multiple Promise instances into a new Promise instance

Const p = promise. all([p1, p2, p3]);

Parameters: Enter an array whose elements are not Promise instances and will be converted to promise.resolve

Return value: Returns a new Promise instance with the state of P determined by P1, P2, and P3

  • Only when the states of P1, P2 and P3 become depressing, the state of P will become depressing. At this time, the return values of P1, P2 and P3 will form an array and be passed to the callback function of P.
  • If p1, P2, and P3 are rejected, P becomes rejected, and the return value of the first rejected instance is passed to p’s callback function.
  • If a Promise instance that is a parameter defines its own catch method, then it does not fire the promise.all () catch method once it is rejected.

Conclusion: logic and whole pity only pity, a rejected

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('Error reported'); }) .then(result => result) .catch(e => e); Promise.all([p1, p2]) .then(result => console.log(result)) .catch(e => console.log(e)); / / /"hello", Error: Error]Copy the code

Promise.race()

const p = Promise.race([p1, p2, p3]);

In the above code, the state of P changes as long as one of the first instances of P1, P2, and P3 changes state.

The return value of the first changed Promise instance is passed to p’s callback.

Conclusion: race, whoever returns first returns this value

// Change the state of a Promise to REJECT or resolve if no result is obtained within a specified time. const p = Promise.race([ fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)})]); p .then(console.log) .catch(console.error);Copy the code

Promise.allSettled()

The wrapper instance will not complete until all of these parameter instances return the result, whether this is fulfilled or Rejected.

The new Promise instance is returned, and once it is over, the state is always fulfilled

Conclusion: All are set up to resolve promise.all () without knowing that all operations are finished

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]
Copy the code

The listener receives an array results as an argument.

Each member of this array is an object corresponding to two Promise instances passed in promise.allSettled ().

Each object has a status attribute, whose value can only be the string fulfilled or the string Rejected.

Someday, the object has the value attribute, and the object has the reason attribute, which corresponds to the return values of the two states.

Promise.any()

The promise.any () method takes a set of Promise instances as parameters and wraps them into a new Promise instance.

As long as one parameter instance becomes a depressing state, the packaging instance will become a depressing state. If all parameter instances become the Rejected state, the wrapper instance becomes the Rejected state.

This is a big pity, which is a pity only once in a lifetime

var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
  console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {
  console.log(results); // [-1, Infinity]
});
Copy the code

Promise.resolve()

Effect: Turn an existing object into a Promise object

Grammar:

Promise.resolve('foo'New Promise(resolve => resolve();'foo'))
Copy the code

Parameters:

(1) The argument is an instance of Promise

Promise.resolve will return the instance intact without any modifications.

(2) The argument is a Thenable object

The promise. resolve method converts this object to a Promise, and then immediately executes the thenable object’s then method.

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

(3) Arguments are not objects with then methods, or are not objects at all

The promise. resolve method returns a new Promise object in the resolved state as the argument to the callback function.

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello
Copy the code

(4) Without any parameters

Return an Resolved Promise object directly. Pay attention to the order in which the callbacks are executed.

setTimeout(function () {
  console.log('three');
}, 0);

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

console.log('one');

// one
// two
// three
Copy the code

Promise.reject()

Returns a new Promise instance with the status Rejected.

The arguments of the promise.reject () method are left as reject arguments and become arguments for subsequent methods.

const p = Promise.reject('Wrong'); // const p = new Promise((resolve, reject) => reject('Wrong'))

p.then(null, function(s) { console.log(s) }); / / make a mistakeCopy the code

Promise.try()

Let synchronous functions execute synchronously, asynchronous functions execute asynchronously, and let them have a uniform API

The following function f() represents operations that are not determined to be synchronous or asynchronous

// const f = () => console.log()'now');
(
  () => new Promise(
    resolve => resolve(f())
  )
)();
console.log('next');
// now
// next
Copy the code
// Async () => f())().then(...) .catch(...)Copy the code
Promise.try(() => f()).then(...) .catch(...)Copy the code