Before the beginning, fresh gram has an end

A long journey begins at a single step

I. Understanding and use of Promise

1. What is Promise?

1.1, understanding,

1.1.1 abstract Expression:

  1. Promise is a new technology (the ES6 specification was officially incorporated in 2017);

  2. Promise is a new solution for asynchronous programming in JS; The old scheme used only callback functions for asynchronous operations. If there was too much dependency, there would be the famous callback hell problem.

Common asynchronous operations are as follows:

A. FS file operation

require('fs').readFile('./index.html', (err,data)=>{})

// Scenario requirements: Read the values of the 1, 2, and 3. TXT files in sequence
const fs = require('fs');
​
fs.readFile('./1.txt'.'utf8'.(err, result1) = > {
  console.log(result1)
  fs.readFile('./2.txt'.'utf8'.(err, result2) = > {
    console.log(result2)
    fs.readFile('./3.txt'.'utf8'.(err, result3) = > {
      console.log(result3)
    })
  })
});
Copy the code

B. Database operation

C, Ajax

$.get('/server', (data)=>{})

D. Timer

setTimeout(()=>{}, 2000)

1.1.2 Specific Expressions:

  1. Grammatically speaking:

Promise is a constructor that wraps a Promise around an asynchronous operation, as shown in example 1 below.

  1. In terms of function:

A Promise can instantiate an object that encapsulates an asynchronous operation and returns a success or failure result.

1.2. State changes of promise

1. Changed from Pending to Resolved

2, Pending changes to Rejected

Note:

A promise can only have three states:

This is a big pity, which is resolved/ regrettable.

The promise state can only change from “wait” to “complete” or “reject”, not reverse.

And the state can only change once, that is, after the change, whether it becomes a success or failure, will not change;

The then method takes two arguments. The first is a callback on success, called when a promise transitions from a “wait” state to a “complete” state, and the second is a callback on failure, called when a promise transitions from a “wait” state to a “reject” state.

1.3 Basic process of Promise

1.4 basic use of Promise

Example 1: Basic operations

    // 1) Create a Promise object (pending state) specifying the executor function
      const p = new Promise((resolve, reject) = > {
        // 2) Start the asynchronous task in the executor function
        setTimeout(() = > {
          const time = Date.now()
          // Assume that an odd number of times represents success and an even number represents failure
          if (time % 2= = =1) {
            resolve('Success value' + time)
          } else {
            reject('Failed value' + time)
          }
        }, 2000)})// 3) Promise specifies a successful or failed callback to get a successful vlaue or a failed Reason
​
      // p.then(
      // (value) => {
      // // Successful callback function onResolved, get successful Vlaue
      // console.log(' successful value: ', value)
      / /},
      // (reason) => {
      // // Second parameter
      // // failed callback function onRejected, get failed reason
      //     console.log('失败的 reason: ', reason)
      / /}
      // )
​
      / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- or more suggest this orthography, convenient and intuitive -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
      p.then((value) = > {
        // Successful callback onResolved to get a successful vlaue
        console.log('Successful value:', value)
      }).catch((reason) = > {
        // The second argument
        // The failed callback function onRejected returns the failed reason
        console.log('Failure reason:', reason)
      })
Copy the code

Example 2: Encapsulating a timer – based asynchronous function

    function doDelay(time) {
        // 1. Create promise objects
        return new Promise((resolve, reject) = > {
          // 2. Start asynchronous tasks
          console.log('Start asynchronous Task')
          setTimeout(() = > {
            console.log('Delay task start execution... ')
            const time = Date.now()
            // Assume that an odd number of times represents success and an even number represents failure
            if (time % 2= = =1) {
              resolve('Success data' + time)
            } else {
              reject('Failed data' + time)
            }
          }, time)
        })
      }
​
      const promise = doDelay(2000)
​
      promise
        .then((value) = > {
          console.log('Successful value:', value)
        })
        .catch((reason) = > {
          console.log('Failure reason:', reason)
        })
Copy the code

Example 3: Encapsulating ajax asynchronous request functions

Note:

Ajax requests are themselves asynchronous operations;

      /* Reusable ajax request function: XHR + promise */
      function promiseAjax(url) {
        return new Promise((resolve, reject) = > {
          const xhr = new XMLHttpRequest()
          xhr.onreadystatechange = () = > {
            if(xhr.readyState ! = =4) return
            const { status, response } = xhr
            Resolve (value)
            if (status >= 200 && status < 300) {
              resolve(JSON.parse(response))
            } else {
              Reject (reason)
              reject(new Error('Request failed: status:' + status))
            }
          }
          xhr.open('GET', url)
          xhr.send()
        })
      }
​
      promiseAjax('https://api.apiopen.top2/getJoke? page=1&count=2&type=video')
        .then((data) = > {
          console.log('Show success data', data)
        })
        .catch((error) = > {
          alert(error.message)
        })
Copy the code

2. Why use Promise?

2.1. The way callback functions are specified is more flexible

1. Old scheme: This scheme must be specified before starting asynchronous tasks

2. Promise: Start the asynchronous task => return the Promise object => Bind the callback function to the Promise object (you can even specify multiple callback functions after the asynchronous task ends)

2.2 support chain call, can solve the problem of callback hell

2.2.1 what is callback hell?

Callback functions are nested calls, and internal function execution conditions (such as parameters) depend on the result of asynchronous execution of external callback functions

2.2.2. Disadvantages of callback hell?

Not easy to read, not easy to handle exceptions, not easy to maintain, etc

2.2.3 Solution?

Promise chain call

2.2.4 Ultimate solution?

async/await

2.2.5, instance

Example 1: Promise solves callback hell

const fs = require('fs');
​
// -------------- callback hell ---------------------// fs.readFile('./1.txt', 'utf8', (err, result1) => {
// console.log(result1)
// fs.readFile('./2.txt', 'utf8', (err, result2) => {
// console.log(result2)
// fs.readFile('./3.txt', 'utf8', (err, result3) => {
// console.log(result3)
/ /})
/ /})
// });function p1 () {
  return new Promise ((resolve, reject) = > {  // return a Promise object
    fs.readFile('./1.txt'.'utf8'.(err, result) = > {
      resolve(result)
    })
  });
}
​
function p2 () {
  return new Promise ((resolve, reject) = > {
    fs.readFile('./2.txt'.'utf8'.(err, result) = > {
      resolve(result)
    })
  });
}
​
function p3 () {
  return new Promise ((resolve, reject) = > {
    fs.readFile('./3.txt'.'utf8'.(err, result) = > {
      resolve(result)
    })
  });
}
​
p1().then((r1) = > {
  console.log(r1);
  return p2();
})
.then((r2) = > {
  console.log(r2);
  return p3();
})
.then((r3) = > {
  console.log(r3)
})
Copy the code

Example 2: asyncFunc async functions

1. Add the async keyword in front of the definition of ordinary functions to make them asynchronous;

2. The default return value of asynchronous functions is a Promise object, not just undefined;

3. Use the throw keyword inside the asynchronous function to throw errors instead of reject in the promise;

In addition, the await keyword:

1. It can only appear in async;

2. Await (a promise operation) it can suspend the execution of the asynchronous function and wait for the promise object to return the result before executing the function downward;

async function fn() {
  throw "There have been some errors.";
}
​
fn()
  .then(function (data) {
    console.log(data);
  })
  .catch(function (err) {
    console.log(err);
  });
​
​
// --------------------async----------------------
async function p1() {
    return "p1";
}
​
async function p2() {
  return "p2";
}
​
async function p3() {
  return "p3";
}
​
console.log('I'm not returning a string.',p1());
​
async function run() {
  let r1 = await p1();
  let r2 = await p2();
  let r3 = await p3();
  console.log(r1);
  console.log(r2);
  console.log(r3);
}
​
run();
Copy the code

Note:

1. Because of asynchronous functionsasyncThe default return value ispromiseObject, so the return values of functions p1, p2, and p3 here are not pure strings, but ratherpromiseObject:

MDN official:

2,awaitYou can followanyJS expression of

Note:

While “await” can wait for many types of things, its primary purpose is to wait for Promise objects;

An await followed by a promise will cause the asynchronous function to stop executing and wait for the promise to resolve;

If await is followed by a normal expression, execute immediately as normal code.

Such as:

Third, asyncFuncReadFile

const fs = require('fs'); Const promisify = require('util').promisify; const promisify = require('util').promisify; Const readFile = promisify(fs.readfile); const readFile = promisify(fs.readfile); async function run () { let r1 = await readFile('./1.txt', 'utf8') let r2 = await readFile('./2.txt', 'utf8') let r3 = await readFile('./3.txt', 'utf8') console.log(r1) console.log(r2) console.log(r3) } run();Copy the code

3. How do I use Promise?

3.1. Use of API

Promise (excutor) {}

(1) Execute (resolve, reject) => {}

(2) resolve function: internal define success we call the function value => {}

(3) Reject: reject function we call when internal definition fails reason => {}

Note:

Executors invoke the Promise immediately and synchronously, and asynchronous operations are performed in the executor

So in this article, PORTAL: JS event execution mechanism

New Promise(function (resolve, reject) {… } operation, which by default is synchronized execution code

Prototype. Then (onResolved, onRejected) => {}

OnResolved function (value) => {}

(2) onRejected () => {}

Note:

Return a new Promise object by specifying a success callback for a success value and a failure callback for a failure Reason

3, prototype. Catch method :(onRejected) => {}

(1) onRejected () => {}

Note:

Then () (undefined, onRejected)

4、Promise.resolve方法: (value) => {}

(1) Value: successful data or promise object

Note:

If an object of type other than a Promise is passed in, the result returned defaults to a successful Promise object.

If a Promise object is passed as an argument, the result of the argument determines the result of resolve.

let p1 = Promise.resolve(123)
console.log('p1', p1)
​
let p2 = Promise.resolve(
  new Promise((resolve, reject) = > {
    // resolve('OK')
    reject('Error')}))console.log('p2', p2)
p2.catch((reason) = > {
  console.log(reason)
})
Copy the code

Get:

5, Promise. Reject method: (reason) => {}

(1) The reason for the failure

Description:

Return a failed promise object. Note the difference with the fourth promise.resolve method

let p1 = Promise.reject(123)
let p2 = Promise.reject('abc')
let p3 = Promise.reject(
  new Promise((resolve, reject) = > {
    resolve('OK')}))console.log(p1)
console.log(p2)
console.log(p3)
Copy the code

Get:

6, Promise. All methods :(promises) => {}

Promises: Promises: an array containing N promises

Note:

Return a new promise that will only succeed if all promises succeed;

A. Both are successful

let p1 = new Promise((resolve, reject) = > {
  resolve('OK')})let p2 = Promise.resolve('Success')
let p2 = Promise.resolve('Oh Yeah')
​
const result = Promise.all([p1, p2, p3])
console.log(result)
Copy the code

Get:

B. There are failures

Note:

If they all succeed, return the array, and if they fail, the result is, again, the first value that failed

let p1 = new Promise((resolve, reject) = > {
  console.log(1111111)
  resolve('OK')})let p2 = new Promise((resolve, reject) = > {
  console.log(222222)
  reject('Failed 2222')})let p3 = new Promise((resolve, reject) = > {
  console.log(3333333)
  reject('Failed 3333')})const result = Promise.all([p1, p2, p3])
console.log(result)
Copy the code

Get:

7, promises: (promises) => {}

Promises: Promises: an array containing N promises

Note:

Return a new promise, and the result state of the first completed promise is the final result state

let p1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK')},1000)})let p2 = Promise.resolve('Success')
let p3 = Promise.resolve('Oh Yeah')
​
/ / call
const result = Promise.race([p1, p2, p3])
console.log(result)
Copy the code

Get:

3.2 Key issues of Promise

1. How to change the state of promise?

(1) Resolve (value): Resolved if it is pending

(2) Reject (reason): If it is pending, it changes to Rejected

(3) Raise exception: If the value is pending, it changes to Rejected

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
  throw 'Something's wrong' // pending => rejected
})
​
console.log(p)
Copy the code

Note:

Then and catch are executed after the state changes.

2. Will multiple success/failure callbacks specified by a Promise be called?

Note:

This is called when a promise changes to the corresponding state, as follows:

let p = new Promise((resolve, reject) = > {
  resolve('OK')})/// specify callback - 1
p.then((value) = > {
  console.log(111, value)
})
​
// Specify callback - 2
p.then((value) = > {
  console.log(222, value)
})
Copy the code

Get:

3. Change the Promise state and specify the callback function (then).

(1) Both are possible. The normal case is to specify the callback and then change the state, but it is also possible to change the state and then specify the callback

(2) How to change the state before specifying the callback?

Resolve ()/reject()

Then ()

(3) When will the data be available?

If the callback is specified first, the callback function will be called when the state changes, and the data will be returned

② If the state is changed first, the callback function will be called when the callback is specified

To put it simply:

In fact, it is synchronous code, micro task, macro task execution order difference;

Portal: JS event execution mechanism

3.1. When a Promise’s internal state change actions (resolve, Reject, throw) are not included in the asynchrony

let p = new Promise((resolve, reject) = > {
  console.log(1) / / synchronize
  resolve('OK') Micro / / task
  console.log(22) / / synchronize
})
​
p.then(
  (value) = > {
    console.log(value)
  },
  (reason) = >{})Copy the code

Get:

3.2. When a Promise’s internal state change actions (resolve, Reject, throw) are included in the asynchro

let p = new Promise((resolve, reject) = > {
  console.log(111) / / synchronize
  setTimeout(() = > { // Asynchronous macro tasks
    console.log(222) // Asynchronous macro task -- synchronous task
    resolve('OK') // Asynchronous macro task -- microtask
    console.log(333) // Asynchronous macro task -- synchronous task
  }, 1000)
  console.log(444) / / synchronize
})
​
p.then(
  (value) = > {
    console.log(value)
  },
  (reason) = >{})Copy the code

Get:

4, What determines the result state of a new promise returned by promise.then()?

(1) Simple expressions:

Determined by the result of the execution of the callback function specified by then()

(2) Detailed expression:

① If an exception is thrown, the state of the new Promise changes to Rejected

② If an arbitrary value is returned that is not a PROMISE, the state of the new PROMISE automatically defaults to Resolved

③ If another new promise is returned, the result of that promise becomes the result of the new promise

let p = new Promise((resolve, reject) = > {
  resolve('ok')})// Execute the then method
let result = p.then(
  (value) = > {
    // console.log(value);
    //1. Throw an error ------ reject failed status
    // throw 'error'
​
    //2. Returns a non-Promise object ------ that automatically becomes successful
    // return 521
​
    //3. Return the result as a Promise object ---- whichever is returned
    return new Promise((resolve, reject) = > {
      // resolve('success');
      reject('error')})},(reason) = > {
    console.log('Notice, this failure has nothing to do with me.')
    console.warn(reason)
  }
)
console.log(result)
Copy the code

5. How does promise string together multiple action tasks?

(1) Promise’s then() returns a new promise, which can be written as a chained call to then()

(2) Chain multiple synchronous/asynchronous tasks through chaining calls to THEN

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK')},1000)
})
​
p.then((value) = > {
  console.log(value) Print Ok after one second
  return new Promise((resolve, reject) = > {
    resolve('success')
  })
})
  .then((value) = > { // The preceding then returns a new promise that can be opened as a chained call to then()
    console.log(value) // success
  })
  .then((value) = > { // Then has no return value
    console.log(value) // undefined If no value is returned, undefined is returned by default
  })
Copy the code

6, Promise abnormal penetration?

(1) When using promise’s then chain call, you can specify the failed callback at the end,

(2) Any previous operation is abnormal, will be passed to the last failed callback processing

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK')
    // reject('Err')
  }, 1000)
})
​
p.then((value) = > {
  console.log(value)
  throw 'Failure! '
})
  .then((value) = > {
    console.log(222)
  })
  .then((value) = > {
    console.log(333)
  })
  .catch((reason) = > {
    console.log('Execute catch')
    console.log(reason)
  })
Copy the code

Get:

7. Break the Promise chain?

(1) When using promise’s then chain call, it breaks in the middle and does not call subsequent callback functions

(2) There is only one way: return a Pendding Promise object in the callback function

let p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('OK')},1000)
})
​
p.then((value) = > {
  console.log(111) // Only 111 will be printed
  // There is only one way: return pending, break the promise chain (as mentioned earlier, only execute if the state changes)
  return new Promise(() = > {}) 
})
  .then((value) = > {
    console.log(222) // It has been interrupted and will not print
  })
  .then((value) = > {
    console.log(333) // It has been interrupted and will not print
  })
  .catch((reason) = > {
    console.warn(reason) // It has been interrupted without error and will not print
  })
Copy the code

Async/Await

1. Knowledge points:

A, async keyword is used before function declaration, for example: async function test(){}

B, async always returns a Promise object, whether or not the function returns a Promise object, for example:

async function main() {
  //1. If the return value is a non-PROMISE data type
  return 123
}
​
let result = main()
console.log(result) // Is actually a Promise object
Copy the code

Get:

async function main() {
  //2. Return a Promise object
  return new Promise((resolve, reject) = > {
    resolve('OK'); })}Copy the code

Get:

async function main() {
  //3. Throw exception
  throw 'Oh NO'
}
​
let result = main()
console.log(result)
Copy the code

Get:

C, await can only be used in async functions, it will return an error if used elsewhere

D, async/await and Primose objects are essentially the same

E, async/await is used to perform asynchronous operations in synchronous mode

F, if an await promise fails, an exception will be thrown, which requires a try… Catch processing

2. What problems have been solved?

The promise.then syntax has solved the problem of nested layers of callbacks that always existed before, so why use async/await? Let’s start with the Promise code:

function login () {
  return new Promise(resolve= > {
    resolve('aaaa')})}function getUserInfo (token) {
  return new Promise(resolve= > {
    if (token) {
      resolve({
        isVip: true})}})}function getVipGoods (userInfo) {
  return new Promise(resolve= > {
    if (userInfo.isVip) {
      resolve({
        id: 'xxx'.price: 'xxx'})}})}function showVipGoods (vipGoods) {
  console.log(vipGoods.id + The '-' + vipGoods.price)
}
login()
  .then(token= > getUserInfo(token))
  .then(userInfo= > getVipGoods(userInfo))
  .then(vipGoods= > showVipGoods(vipGoods))
Copy the code

As shown in the example, each Promise is equivalent to an asynchronous network request. Usually a business process requires multiple network requests, and network requests depend on the result of one request. In this example, Promise simulates this process.

async function call() {
  const token = await login()
  const userInfo = await getUserInfo(token)
  const vipGoods = await getVipGoods(userInfo)
  showVipGoods(vipGoods)
}
call()
Copy the code

The async/await call is much cleaner and simpler than the Promise then chain call, as is the synchronous code

3. What is worth noting

When using async/await, we often ignore the problem of time accumulation caused by synchronous execution. Sometimes our code can be written as concurrent execution, but since async/await is made as secondary execution, let’s take an example:

function test () {
  return new Promise(resolve= > {
    setTimeout(() = > {
      console.log('test')
      resolve()
    }, 1000)})}function test1 () {
  return new Promise(resolve= > {
    setTimeout(() = > {
      console.log('test1')
      resolve()
    }, 1000)})}function test2 () {
  return new Promise(resolve= > {
    setTimeout(() = > {
      console.log('test2')
      resolve()
    }, 1000)})}async function call () {
  await test()
  await test1()
  await test2()
}
call ()   // About 3000ms...
Copy the code

In fact, if I don’t care about the order in which this code is executed, the secondary execution will waste a lot of execution time.

function call () {
  Promise.all([test(), test1(), test2()])
}
call() // Parallel execution...
Copy the code

4. How do I implement the principle of async/await?

Async /await is a syntactic sugar, and the same effect can be achieved using ES6’s iterative function Generator. For details, see this article.

7 pictures, 20 minutes async/await principle! Why is it taking so long?

🚀 🚀 🚀

Suggestion: After reading this article, take a look at these two articles will be more fragrant!

JS event execution mechanism

SetTimeout +Promise+Async output order It’s simple!