What is a Promise?

Promise is an asynchronous solution provided by ES6 that allows asynchronous operations that write complex traditional callback functions and listen to events to communicate the results in synchronous code. In its original form, a promise is a promise that an asynchronous (or synchronous) process will give you a result after a certain amount of time, and that result will have different states depending on the situation.

The downside of traditional pullbacks

Example:

function fn1(value, callback) {
  setTimeout(() = > {
    let a = 1
    for(let i = 1; i <= value; i++) {
      a *= i
    }
    callback(a)
  })
}

fn1(10000000.function(result) = >{
  console.log(result)
})
Copy the code

The above code performs the factorial operation and then executes the callback. Suppose that in order to get the factorial of 10000000, because of the large amount of computation, do not let it block JS, so that it is executed in asynchronous, so the callback is needed to get the result.

However, this result needs to be subtracted in the fn2 function, if the computation amount (word) is large ~(dog head):

function fn2(value, callback) {
  setTimeout(() = > {
    const b = value - 1 - 2 - 3 - 4 - 1000
    callback(b)
  }, 100)
}

fn1(10000000.function(result1) = >{
  fn2(result1, function(result2) = >{
    console.log(result)
  })
})
Copy the code

Then you need to do some multiplication in the FN3 function, if the operation (word) is very large ~(head), do some addition in the FN4 function… fn5 fn6 fn7… fn100……..

function fn3(value, callback) {
  // value = x*x*123...
  callback(value)
}

function fn4(value, callback) {
  // value = x+x+123...
  callback(value)
}

fn1(10000000.function(result1) = >{
  fn2(result1, function(result2) = >{
    fn3(result2, function(result3) = >{
      fn4(result3, function(result4) = >{... fn100(result99,function(result100) = >{
          console.log(result)
        })
      })
    })
  })
})
Copy the code

A hundred callbacks to get the final result… Became a callback hell, the truth though there is no so many levels, nor in front of so many asynchronous 😂 to do a lot of calculation, but the content of each processing function also it can’t be that simple, the above example is to express, when we deal with multi-layer callback, such as the multistage interface, must be very fat not beautiful, Maybe the result of one of these callbacks is nowhere to be found (result1, result2, result3…). .

The emergence of the Promise

A Promise represents a Promise and, like a callback function, promises a result, but that result can be delivered in a different way (success or failure) depending on the state of the Promise.

Disadvantages of callbacks:

  • Layer upon layer of nesting, the code writing logic is different from the traditional order, which is not conducive to reading and maintenance
  • When the order of asynchronous operations changes, a lot of re-changes may be required

Promise solves two problems:

  • Callback hell, which can perform asynchrony via function chain calls and then process the results, making the code logic write like synchronization

  • Support concurrency, such as obtaining the results of multiple concurrent requests

The state of the Promise

Promise is a constructor that takes an instance object as a new Promise and takes an execution function (fn) as an argument. This execution function also takes resolve, reject

const promise = new Promise(function (resolve, reject) {
  / /... do something asynchronous
  // resolve sth or reject sth
})
Copy the code

Promise itself has three states:

  • Pending – > wait
  • This is a big pity -> Executive state
  • Rejected -> Rejected state

A Promise is a constructor that needs to be used by new instantiation with the initial pending state inside the Promise

Fn is passed a callback function, which is passed to Promise as resolve and reject. These two parameters are also functions that need to throw the result after asynchronous execution within FN. Resolve is the state of acceptance and success. Reject Indicates a state of rejection or failure

When fn’s internal code executes resolve or reject, its internal state changes

The state corresponding to Resolve Reject is

resolve -> fulfilled
reject  -> rejected
Copy the code

Once a promise is resolved or reject, it cannot be migrated to any other state

Basic process:

  1. Initialize the Promise state (pending)
  2. Perform then (..) Register callback processing arrays (then methods can be called multiple times by the same Promise)
  3. The fn function passed in the Promise is immediately executed, and the resolve and reject functions inside the Promise are passed to FN as parameters, which will be processed according to the event mechanism
  4. The Promise promises that the parameters fulfilled and Rejected passed in by the THEN method must be executed in the new execution stack after the event loop in which the THEN method is called

The above can be ignored first, let’s see how to use

The method of the Promise object

1. Then method registration'Resolve'/' rejectThe callback function of

promise.then(fulfilled, rejected)
// This is a pity that promise performs the callback when resolve succeeds
// Reject is the callback that the promise executes when reject fails
Copy the code

Take a chestnut

const promise = new Promise((resolve, reject) = > {
  let num = 1;
  setTimeout(() = > {
    num += 1;
    resolve(num) // The result will be fulfilled. At the same time, the state will change gradually
  }, 1000)
})

promise.then(function a(result) {
    console.log('a') // a
    console.log(result) / / 2
}, function b(result) {
    console.log('b')
    console.log(result)
})
Copy the code

Method A is implemented, and the general process is that fn executes synchronous code in the execution function, and asynchronously executes it after setTimeout is encountered. After 1s waiting, the value of num will be transmitted after the execution of resolve, because the state of resolve is depressing. So method A is executed, but method B is not executed. Similarly, if you change resolve to reject in setTimeout, the transition state will be changed to Rejected, so method B is executed

This will be a pity. 2

The pity callback in THEN will be performed and the value will be passed in as the parameter value. When fn executes the resolve method internally (the internal state of the Promise is resolved), a parameter value can be passed in.

const promise = new Promise((resolve, reject) = > {
  let value = 1;
  setTimeout(() = > {
    value = value + 1;
    resolve(value)
  }, 0);
}).then(function(res) {
  console.log(res) // --> 2
})

// Can also be separated
const promise = new Promise((resolve, reject) = > {
  let value = 1;
  setTimeout(() = > {
    value = value + 1;
    resolve(value)
  }, 0);
});

promise.then(function(res) {
  console.log(res) // --> 2
})
Copy the code

New Promise creates a new Promise instance object, passing (resolve, reject) => {… } This fn argument acts as an execution function.

Fn internally performs an asynchronous operation (setTimeout) which can also be a network request when synchronizing code

let value = 1;
Copy the code

After execution

3. Reject is called

The same is true for reject. The difference is that we pass an additional execution callback to THEN:

const promise = new Promise((resolve, reject) = > {
  let value = 1 + 1
  reject(value)
})
.then(function(res) {
  console.log(res) // This will not be fulfilled
}, function(err) {
  console.log(err) / / 2
})
Copy the code

In the above code, fn executes reject, and the internal state of the Promise is rejected. Therefore, only the second execution callback in THEN (Rejected) is executed, while reject accepts a value argument to the rejected callback in the next THEN for subsequent errors

4. Catch an error

The chained call writing captures the exception that occurred in the Resolved callback in the previous THEN

promise.catch(rejected)
/ / equivalent to
promise.then(null, rejected)
// This is a big pity. // Note: This is a big pity

promise.then(fulfilled, rejected) 
// Can be written as:
promise.then(fulfilled)
       .catch(rejected)   
Copy the code

When an error occurs in fullfill:

const promise = new Promise((res, rej) = > {
  res(1)
})
.then(res= > {
  let a = 1
  return res + a.b.c
})
.then(res= > {
  return res + 1
}, err= > {
  // Errors of the upper level are caught
  console.log(err) // Cannot read property 'c' of undefined
})

Copy the code

const promise = new Promise((res, rej) = > {
  res(1)
}).then(res= > {
  let a = 1
  return res + a.b.c
}).then(res= > {
  return res + 1
}).then(res= > {
  console.log(res)
}).catch(err= > {
  // An error at any of the above levels is eventually referred to catch
  console.log(err) // TypeError: Cannot read property 'c' of undefined
})
 
Copy the code

The catch function is called, no matter how many THEN’s there are, unless a failed callback is passed in the THEN:

const promise = new Promise((res, rej) = > {
  res(1)
})
  .then(res= > {
    let a = 1
    return res + a.b.c
  })
  .then(res= > {
    return res + 1
  }, err= > { // This will be captured first
    console.log(err) // TypeError: Cannot read property 'c' of undefined
  })
  .then(res= > {
    console.log(res)
  }).catch(err= > {
  // A catch will not be executed if the rejected callback is caught above
  console.log(err) 
  })
Copy the code

5. I promise

The promise.then method returns a new promise object each time it is called, so it can be chainedCopy the code
function taskA() {
    console.log("Task A")}function taskB() {
    console.log("Task B")}function rejected(error) {
    console.log("Catch Error: A or B", error)
}
var promise = Promise.resolve()
promise
  .then(taskA)
  .then(taskB)
  .catch(rejected) Catch the exception in the previous then method
Copy the code

This parameter will be accepted by the resolved callback when the rejected callback is executed by the next level instead of the Rejected callback:

const promise = new Promise((res, rej) = > {
  res(1)
})
  .then(res= > {
    let a = 1
    return res + a.b.c
  })
  .then(res= > {
    return res + 1
  }, err= > {
    console.log(err) // When an error is caught here, the returned value will still be received by the resolved callback in the next level then
    return 'dz'
  })
  .then(res= > {
    console.log(res) // dz
  }, err= > {
    console.log(err)
  })
Copy the code

A static method for Promise

1. Promise. Resolve returns a Promise object in fullfill state

Promise.resolve('dz').then(res= > { console.log(res) })// --> dz
/ / equivalent to
new Promise((resolve) = > {resolve('dz')}).then(res= > { console.log(res) }) // --> dz
Copy the code

Reject Returns a Promise object in the Rejected state

3. Promise.all accepts an array, each element of which is a Promise object, and returns an array of reject states after each Promise object is executed

It is called only if each Promise object is in a 'resolve' state, and is typically used to handle multiple parallel asynchronous operationsCopy the code
const p1 = Promise.resolve('dz1')
const p2 = Promise.resolve('dz2')
const p3 = Promise.resolve('dz3')
Promise.all([p1, p2 , p3]).then(res= > {
  console.log(res) / / -- > [' dz1 ', 'dz2', 'dz3], the result is in line with the promise to return the order of the array
})
Copy the code

4. Promise.race also accepts an array of Promise objects

The Promise. Race will perform the later processing as long as one of the elements enters the fulfilled or rejected state.Copy the code
function timer(delay) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(delay)
    }, delay)
  })
}
Promise.race([
  timer(10),
  timer(20),
  timer(30),
]).then(res= > { console.log(res) }) / / - > 10
Copy the code

5. Finally will be executed regardless of the Promise state

Will finally be executed no matter what the Promise returns and not change the state of the Promise

Promise.resolve(1).finally(() = >{})
Promise.reject(1) .finally(() = >{})
Copy the code