1. Learn a little about Promise

The Promise object represents events that will happen in the future and is used to deliver messages for asynchronous operations.

2. Why do we need Promise

JS is a single-threaded language and in particular we can only do asynchronous operations with callback functions, so we introduced Promise

3. The most common asynchrony

Ajax requests, stetimeOut

4. What is asynchronous? What is synchronization?

Synchronization: Perform the next task only after the task is completed and the result is obtained. Asynchronous: The system directly executes the next task before completing the task.

Promise to create

To create a Promise object, we need to use new to call the promise constructor to instantiate the chestnut

const promise = new Promise((resolve, reject) = >{
  // Asynchronous processing
  // After processing, call resolve or reject
  if (req.status === 200) { 
        resolve('success');
     } else {
        reject('failure'); }}; })Copy the code

We need to have three states when we use promises

  • Pending
  • This is a big pity.
  • (Rejected)

These three states make the logic much simpler when calling Promise’s asynchronous methods

Ps: When we throw a statement in the first layer of the Promise function, the Promise will directly go into the failed state!

new Promise((resolve,reject) = >{
  throw new Error('test')})Copy the code

Incidentally: What exactly does the new operator do?

As a rule of thumb, we should use the new operator

  1. Create an empty JS object
  2. Modify the empty object’s prototype and point it to the constructor’s prototype
  3. Use empty object as constructor context (change this to point to)

Judge the return value of the constructor using the newly created object as the context for this. If the function returns no object, return this with a simple chestnut

function create(Con, ... args){
  // Create an empty object
  let  obj = Object.create(null);
  // Point the empty object to the constructor's prototype chain
  Object.setPrototypeOf(obj, Con.prototype);
  // obj binds to the constructor to access properties in the constructor, obj.con (args)
  let result = Con.apply(obj, args);
  Return if result is an object
  // The new method is invalid, otherwise obj is returned
  return result instanceof Object ? result : obj;
}
Copy the code

test

function company(name, address) {
    this.name = name;
    this.address = address;
  }
Copy the code

use

var company1 = create(company, 'yideng'.'beijing');
console.log('company1: ', company1);
Copy the code

Promise.prototype. Then method: chain operation

Chestnut 1

var p1 = new Promise(function(resolve, reject){
  // ... some code
resolve(1)}); p1.then(() = >{ console.log(1)}).then(() = >{console.log(2)}) / / 1. 2


PromiseResolve method,PromiseThe reject method// resolve
var p = Promise.resolve('Hello');

p.then((s) = >{
  console.log(s)
})

// reject 
var p1 = Promise.reject('Wrong');
p1.then(null.function (s){
  console.log(s)
});
Copy the code

Chestnut no.2

var a = new Promise((resolve,reject) = >{ resolve(1)})
var a1 = new Promise((resolve,reject) = >{ resolve(2)})
var a3 = new Promise((resolve,reject) = >{ resolve(3)})
a.then((val) = >{
   console.log(val)
   return a1
}).then((va) = >{
  console.log(va)
  return a3
}).then((v) = >{
  console.log(v)
})
// output 1,2,3
Copy the code

Promise. Resolve, Promise. Reject

// resolve
var p = Promise.resolve('Hello');

p.then((s) = >{
  console.log(s)
})
Hello / / output

// reject 
var p1 = Promise.reject('Wrong');
p1.then(null.function (s){
  console.log(s)
});
// Output error
Copy the code

Promise. All usage

This method passes in an iterable array and returns a Promise object, which is activated when all the Promise objects in the array have been executed

Ps: The returned object enters the successful state if all the execution in the array succeeds, and the returned object enters the failed state if one execution fails

Chestnut: All success
var a = new Promise((resolve,reject) = >{ resolve(1)})
var a1 = new Promise((resolve,reject) = >{ resolve(2)})
var a3 = new Promise((resolve,reject) = >{ resolve(3)})
Promise.all([a,a1,a3]).then(value= >{
    console.log(value)
})
// Output [1, 2, 3]
Copy the code
Chestnut: Partial success
var a = new Promise((resolve,reject) = >{ resolve(1)})
var a1 = new Promise((resolve,reject) = >{ resolve(2)})
var a3 = new Promise((resolve,reject) = >{ reject(3)})
Promise.all([a,a1,a3]).then(value= >{
    console.log(value)
}).catch(err= >{
    console.log(err)
})
// Output: 3
Copy the code

Promise. The use of the race

This method passes in an iterable array and returns a Promise object that changes depending on the state of the first promise object in the array

var a = new Promise((resolve,reject) = >{ resolve(1)})
var a1 = new Promise((resolve,reject) = >{ resolve(2)})
var a3 = new Promise((resolve,reject) = >{ reject(3)})
Promise.race([a,a1,a3]).then(value= >{
    console.log(value)
}).catch(err= >{
    console.log(err)
})
// Output: 1
Copy the code

Added es2021 promise.any

Promise.any() receives a Promise iterable and returns the Promise that succeeded as soon as one of the promises succeeds. If none of the promises in the iterable succeed (i.e. all Promises fail/reject), return an instance of the failed promise and AggregateError type, which is a subclass of Error and is used to group single errors together. Essentially, this method is the opposite of promise.all ().

Example:
const pErr = new Promise((resolve, reject) = > {
  reject("Always fail");
});

const pSlow = new Promise((resolve, reject) = > {
  setTimeout(resolve, 500."Finally done");
});

const pFast = new Promise((resolve, reject) = > {
  setTimeout(resolve, 100."Soon done.");
});

Promise.any([pErr, pSlow, pFast]).then((value) = > {
  console.log(value);
  // pFast fulfils first
})
// Expected output: "soon done"
Copy the code

Let’s take a look at the following code

setTimeout(function(){
 console.log('Timer's on.')});new Promise(function(resolve){
 console.log('Execute for loop now'); 
 for(var i = 0; i < 10000; i++){
   i == 99 && resolve(); 
  } 
 }).then(function(){ 
  console.log('Execute the then function')});console.log('End of console execution');
Copy the code

A look at my confident output is as follows

consoleExecute the command immediatelyforThe loop executes the then function and the timer startsCopy the code

But here’s the thing:

Immediately to performforCycle!consoleEnd of execution Execute then function start timerCopy the code

Why is that output?

So first of all, the code execution encounters the first block of code, setTimeout, and setTimeout is pushed into the Event Table and then we’re going to execute the following code, the New Promise module, before we execute the Promise callback, which is the.then function

console.log('Execute for loop now'); 
for(var i = 0; i < 10000; i++){
   i == 99 && resolve();
} 
Copy the code

The code. Second, we execute the for loop, and when I == 99, we execute resolve() to push the callback.then to the Event Queue, which is console.log(‘ end of console execution ‘);

This line of code. Once we’re done, we find that there are no more tasks on the main thread to execute, we go to the Event Queue to read the corresponding function, and then we go to the main thread to execute the same process over and over again, also known as the Event Loop. How do you know that the main thread stack is empty? The js engine has a monitoring process that continuously checks to see if the main thread stack is empty, and if it is, checks the Event Queue to see if there are any functions waiting to be called.

So setTimeOut and the first thing you might think about setTimeOut is that asynchrony can be delayed, but that’s not how you think about it once you look at the code

such as:setTimeout(() = > {
   console.log(1)},3000)

sleep(8000)
Copy the code
// Execution result
// ... 2000 years later( 8s later)
/ / 1
Copy the code

Just to explain, after we execute setTimeout, we will push setTimeout into the Event Table, and then we will execute the sleep function, but at this time, sleep is still executing, so we have to wait, and after 3s, Console. log(1) is pushed to the Event Queue, but sleep is still executing. After sleep completes, console.log(1) enters the main thread from the Event Queue

Ps: We often encounter setTimeout(fn,0). What does it mean to execute after 0 seconds? Can it be done immediately? SetTimeout (fn,0) specifies that a task will be executed at the earliest available free time on the main thread. This means that the main thread will execute as soon as all synchronization tasks in the stack are completed and the stack is empty. Ps: The HTML5 standard specifies the minimum value (minimum interval) for the second parameter of setTimeout(), which must not be less than 4 milliseconds. If it is less than this value, it is automatically increased. Previously, older browsers had set the minimum interval to 10 milliseconds. In addition, DOM changes, especially those that involve page re-rendering, are usually not performed immediately, but every 16 milliseconds. RequestAnimationFrame () works better than setTimeout().

In addition to the broad definition of synchronous and asynchronous tasks, we have more detailed definitions: macro tasks and micro tasks:

  • Macro-task: includes the entire code script, setTimeout, and setInterval
  • Micro-task: Promise, process.nexttick
  • In the ES6 specification, microtasks are called Jobs, macroTasks are called tasks, macro tasks are initiated by the host, and microtasks are initiated by JavaScript itself

Different types of tasks will enter the corresponding Event Queue. For example, setTimeout and setInterval will enter the same Event Queue.

To a chestnutsetTimeout(function() {
    console.log('setTimeout');
})

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

console.log('console');
Copy the code
  • First the code executes from top to bottom
  1. When a setTimeout is encountered, its callback function is registered and distributed to the macro task Event Queue.
  2. And then I met Promise,
  3. The new Promise belongs to the main thread task and prints directly, and then discovers the then function, which belongs to the microtask and is distributed to the microtask Event Queue.
  4. If console.log() is encountered, the mainline task will print directly.
  5. So when the task is done in the main thread, we’re going to execute the code that’s distributed to the microtask Event Queue, so first in, first out, and we found that then is executed in the microtask Event Queue.
  6. Ok, once the microtask in the Event Queue is done, the macro task in the Event Queue is done, again first in, first out.
  7. We find the callback function corresponding to setTimeout in the macro task Event Queue and execute it immediately.
  8. The end.
  • So the output should be
- // promise
- // console 
- // then 
- // setTimeout
Copy the code

The relationship between event loops, macro tasks and micro tasks is shown in the figure below: