Callback functions and asynchronous programming are one of the characteristics of JavaScript, but the traditional callback functions in JavaScript are too difficult to write. If there are too many nested callback functions, it is easy to create “callback hell” phenomenon, code becomes very ugly. So Promise was introduced in ES6 to solve this problem.

The basic approach to promises

const promise1 = new Promise((resolve, reject) => { // some thing if(/* some */) resolve(/* some */) else reject(/* some */) }); Promise1. Then (v => {// resolve // do some}, e => {// reject // do some})Copy the code

Above the code is the process for creating promises.

When you create a Promise, you take a function as an argument, which is the main function that you execute asynchronously as a Promise.

(resolve, reject) => {
  // some thing
  if(/* some */)
    resolve(/* some */)
  else
    reject(/* some */)
}
Copy the code

When the execution is complete, either resolve or reject is executed.

These two functions are defined in the arguments to.then.

If a Promise does not execute resolve or reject, then. Then is never executed, and asynchronous action is implemented.

Asynchronous nature of the Promise function

An interesting feature of promises is that the resolve or reject Promise function is asynchronous:

const promise1 = new Promise((resolve, reject) => {
  reject('fail');
  console.log("promise1");
});

promise1.then(v => console.log("then1"), e => console.log(e))
Copy the code

Browser execution result:

We call reject first, and at this point the function should jump to reject in THEN. But it didn’t.

It prints promise1 and then fail. This indicates that resolve and Reject are asynchronous, marking the state at resolve or Reject, and then continuing through the Promise function before entering THEN.

Throw is similar to reject, but different

Throw is commonly referred to as reject.

const promise1 = new Promise((resolve, reject) => {
  console.log("promise1");
  reject('fail');
});

const promise2 = new Promise((resolve, reject) => {
  console.log("promise2");
  throw 'fail';
});

promise2.then(v => console.log("then1"), e => console.log(e))
Copy the code

In the code above, the only difference between promise1 and promise2 is that reject is replaced with throw, but the effect is the same. The Reject function successfully catches the error and treats it as if it were a Reject.

But one big difference with throws is that they execute synchronously in the promise function and don’t wait for the promise function to complete before entering then.

const promise1 = new Promise((resolve, reject) => {
  reject('fail');
  console.log("promise1");
});

const promise2 = new Promise((resolve, reject) => {
  throw 'fail';
  console.log("promise2");
});

promise2.then(v => console.log("then1"), e => console.log(e))
Copy the code

We’ve raised reject and throw to throw errors before we output them.

The console.log in the Promise function never gets a chance to output.

This is due to the fact that the semantics of reject and throw are different:

Throw indicates that the function execution is in error and should not continue.

Reject indicates execution failure, but does not indicate an error.

Chain execution of THEN

const promise1 = new Promise((resolve, reject) => {
  console.log("promise1");
  resolve("ok1");
});

const promise2 = new Promise((resolve, reject) => {
  resolve('ok2');
  console.log("promise2");
})

promise1.then(v => {
  console.log("then1")
  return promise2;
}).then(v => console.log("then2", v), e => console.log("then2", e));
Copy the code

Return another Promise in then, or throw an error, and the later THEN accepts the state of the other Promise, calling resolve or Reject.

As you can see, the Promise function is already executing when we return promise2 in then, passing the resolve or Reject state to the next THEN.

Then can be chain-executed even if it does not return another Promise:

Promise.resolve(2).then(() => console.log(1)).then(() => console.log(2))
Copy the code

This is because the resolve and reject functions return a promise by default. We see this promise as the final result of the browser’s output after each execution.

(Look at the last line of the browser output above)

Note that this promise does not represent the promise we originally created.

If we specify a return value, we return the default promise with an argument:

Reject can be omitted

The reject function in then can be omitted:

const promise1 = new Promise((resolve, reject) => {
  resolve('ok');
  console.log("promise1");
});

promise1.then(v => console.log("then1"))
Copy the code

But reject cannot be read by then.

Catch is a substitute for reject

promise1.then(v => console.log("then1"), e => console.log(e));

promise1.then(v => console.log("then1")).catch(e => console.log(e))
Copy the code

These two forms are equivalent.

Chain catch, Reject and catch

In chained THEN, rejcect and catch can catch errors at any previous layer.

const promise1 = new Promise((resolve, reject) => {
  throw new Error('fail');
  console.log("promise1");
});

const promise2 = new Promise((resolve, reject) => {
  resolve('ok');
  console.log("promise2");
})

promise1.then(v => {
  console.log("then1")
  return promise2;
}).then(v => console.log("then2", v), e => console.log("then2", e));
Copy the code

Browser execution result:

As you can see from the result, if a reject or throw occurs in a chained THEN, resolve in any subsequent THEN will not be executed. Then1 is not implemented, and the resolve state of THEN2 is not accepted by then2.

“Catch” is spelled:

promise1.then(v => {
  console.log("then1")
  return promise2;
}).then(v => console.log("then2", v)).catch(e => console.log("then2", e));
Copy the code

After executing reject, the promise changes to resolve. If followed by a chained THEN, reslove can be executed.

As you can see, after reject, resolve in the later THEN is also executed.

Finally, the ‘resolve’ state described in the article should actually be a pity (completed) state. To facilitate understanding, I will directly use ‘resolve’ to describe it.

For more information

Only a few properties of promises are covered here. If you want to learn more about how promises are used, check out the following resources:

Ruan Yifeng “ES6 standard introduction” Promise part

Es6.ruanyifeng.com/#docs/promi…

The Promise part of the MDN document

Developer.mozilla.org/zh-CN/docs/…

The article is completely original, please mark the source of reprint.