What is Promise?

1.1 concept

Abstract expression

  • Promise is a new technology (ES6 specification)

  • Promise is a new solution for asynchronous programming in JS (the old solution uses plain callback functions)

The specific expression of

  • Syntactically, a Promise is a constructor that instantiates the object;

  • Functionally: The Promise object encapsulates an asynchronous operation and retrieves its success/failure result

[Asynchronous operation programming includes: FS file operation, database operation and timer]

1.2 State changes of Promise

1.2.1 What is the state of promise?

A promise state is a property of a Promise instance object [PromiseState]

There are three types of state attribute values:

  • Pending pending (default value for initialization)

  • Resolved/fullfilled success

  • The rejected failure

Description:

There are only two changes in the promise state, and a promise object can only be changed once. Pending changes to Resolved or Pending changes to Rejected. Success or failure, there will be a result data. The result of success is usually called value, and the result data of failure is usually called Reason.

1.2.2 Promise object value:

Another property in the instance object [PromiseResult] holds the success/failure outcome of an asynchronous task

Who can change the value of PromiseResult:

  • resolve

  • reject

1.3 Basic process of Promise

1.4 Advantages of Promise

  • The way callback functions are specified is more flexible

  • Support for chained calls, which can solve the callback hell problem

1.4.1 What is Callback Hell?

Callback functions are called nested, and the result of asynchronous execution of external functions is the condition for nested callback execution.

ajax1(url, () = > {
    ajax2(url, () = > {
        ajax3(url, () = > {
            doSomething()
        })
    })
})
Copy the code

1.4.2 Callback to hell’s shortcomings?

  • Unreadable

  • Not convenient for exception handling

How do I use Promise?

2.1 API

2.1.1 Promise constructor: Promise(excutor){}

  • Executor (resolve, reject) => {}

  • Resolve function: the function we call when internally defining success value => {}

  • Reject function: The function we call when internal definition fails reason =>{}

Note: Exector is invoked immediately and synchronously within the Promise, and asynchronous operations are performed in the executor.

const p = new Promise((resolve, reject) = > {
    console.log(123)})console.log(456)
// Print 123 first and then 456
Copy the code

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

  • OnResolved function: Successful callback (value) => {}

  • OnRejected (resON) => {}

Note: Specifying the success callback used to get a success value and the failure callback used to get a failure reson returns a new Promise object.

Prototype :(OnRejected) =>{}

  • OnRejected function: failed callback function(reson) = > {}
const p = new Promise((resolve, reject) = > {
    reject('Return error')
})
p.catch(reason= >{
    console.log(reason)
})
Copy the code

2.1.4 Promise. Prototype. Finnaly method (finnaly) = > {}

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

promise
.then(result= >{...}). The catch (error= >{...}). Finally,() = > {ยทยทยท});
Copy the code

In the code above, regardless of the last state of the promise, the callback specified by the finally method is executed after the callback specified by then or catch.

Finally is essentially a special case of the THEN method.

Resolve :(value) => {}

  • The Promise function object is not an instance object

  • Function: In order to quickly get a Promise object, and can encapsulate a value, the value into a Promise object;

  • Value: Successful data or promise object

  • Description: Returns a successful promise object

  • If the object passed in is of a non-Promise type, the result returned is a successful Promise object
  • If the argument passed in is a Promise object, the result of the argument determines the result of resolve

Pass in non-promise type objects

const p1 = Promise.resolve(521)
console.log(p1)
Copy the code

Pass in a Promise object

const p1 = Promise.resolve(new Promise((resolve, rejcte) = > {
    rejcte('Error')}))console.log(p1)
Copy the code

2.1.6 promise. reject method :(reason) => {}

  • Reason: Indicates the reason for the failure

  • Action: Quickly returns a failed Promise object

  • Description: Returns a failed Promise object

const p2 = Promise.reject(521);
console.log(p2)
Copy the code

const p1 = Promise.reject(new Promise((resolve, rejcte) = > {
    resolve('hahha')}))console.log(p1)
Copy the code

2.1.7 promise. all: (Promise) =>{}

  • Promise: An array containing N promises

  • Note: Return a new Promise, which is executed only if all promises succeed, or if any Promise fails.

const p1 = new Promise((resolve, reject) = > {
    resolve('OK')})const p2 = Promise.resolve('SUCCESS');
const p3 = Promise.resolve('Oh Yeah');

const res = Promise.all([p1,p2,p3]);
console.log(res)
Copy the code

If one fails, a failed promise object is returned, and the failed promise value is the failed promise value.


const p1 = new Promise((resolve, reject) = > {
    resolve('OK')})const p2 = Promise.reject('Error');
const p3 = Promise.resolve('Oh Yeah');

const res = Promise.all([p1,p2,p3]);
console.log(res)
Copy the code

2.1.8 Promise. Race method :(promises) =>{}

  • Promises: An array of N promises

  • Whoever changes the state first decides the promise state that race returns

  • Description: Returns an array of N promises. The result state of the first completed Promise is the final result state.

const p1 = new Promise((resolve, reject) = > {
    resolve('OK')})const p2 = Promise.reject('Error');
const p3 = Promise.resolve('Oh Yeah');

const res = Promise.race([p1,p2,p3]);
console.log(res)
Copy the code

2.2 Key issues of Promise

2.2.1 How do I change the State of Promise?

  • Resolve (value) : resolved if pending;

  • Rejected: If pending is current, it becomes Rejected.

  • Throw an exception: If pending is in the current state, it becomes Rejected;

const p = new Promise((resolve,reject) = > {
    / / 1. Resolve function
    // resolve('haha') pending => fulfilled(resolved)
    / / 2. Reject function
    // reject('Error') pending => rejected
    //3. Throw an error
    throw 'Error reported' // pending => rejected
})
console.log(p)
Copy the code

2.2.2 Will multiple success or failure callbacks specified by a Promise be called?

This is called when a promise changes to the corresponding state, and is not executed if the state does not change.

const p = new Promise((resolve,reject) = > {
    resolve('HERE I come')
})
p.then(value= > {
    console.log(value+ 'First call')
})
p.then(value= > {
    console.log(value+ 'Second call')})Copy the code

2.2.3 Who is the first to change promise state or specify callback function? Resolve () and then ()

The resolve() and then() callbacks are examples:

Resolve (); then(); resolve();

 const p = new Promise((resolve,reject) = > {
    resolve('HERE I come')
})
p.then(value= > {
    console.log(value)
})

Copy the code

If the executor function is asynchronous, execute the callback then() and change the state to resolve().

const p2 = new Promise((resolve,reject) = > {
   setTimeout(() = > {
    resolve('HERE I come')},1000);
})
p2.then(value= > {
    console.log(value)
})
Copy the code

How do I change state and then specify a callback?

  • Call resolve()/reject() directly in the executor

  • Delay calling then() longer

const p2 = new Promise((resolve, reject) = > {
    setTimeout(() = > {
        resolve('HERE I come')},1000);
})
setTimeout(() = > {
    p2.then(value= > {
        console.log(value)
    })
}, 2000);
Copy the code

When will we get the data?

  • If the callback is specified first, the callback function will be called when the state changes, retrieving the data

  • If the state is changed first, the callback function is called when the callback is called, and the data is returned

2.2.4 Promise.then () returns a new promise. What determines the result status?

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

  • If an exception is thrown, the new promise changes to Rejected, and Reason is the exception thrown.

  • If an arbitrary value is returned that is not a PROMISE, the new promise becomes Resolved, and value is the returned value;

  • If another new promise is returned, the result of that promise will be the result of the new promise.

const p1 = new Promise((resolve, reject) = > {
    resolve('OK')})const res = p1.then( value= > {
    // 1. Throw an error
    // throw 'Error'

    //2. Return a non-promise object
    // return 521

    // return a promise object that determines the state of then()
    return new Promise((resolve, reject) = > {
        resolve('success')})})console.log(res)
Copy the code

2.2.5 How does PROMISE connect multiple operation tasks?

  • Promise’s then() returns a new promise, which can be opened as a chain call to then();

  • Multiple asynchronous/synchronous tasks are concatenated through chaining calls to THEN

const p1 = new Promise((resolve, reject) = > {
   setTimeout(() = > {
    resolve('OK')},1000);
}) 
p1.then(value= > {
    return new Promise((resolve, reject) = > {
        resolve('Oh Yeah')
    })
}).then(value= > {
    console.log(value)
})
Copy the code

2.2.6 Promise Exception Transmission

  • When using promise’s then chain invocation, the failed callback can be specified at the end;

  • Any previous operations other than exceptions are passed to the last failed callback;

const p1 = new Promise((resolve, reject) = > {
   setTimeout(() = > {
    resolve('OK')},1000);
}) 
p1.then(value= > {
    return new Promise((resolve, reject) = > {
        reject('Error reported')
    })
}).then(value= > {
    console.log(11)

}).then(value= > {
    console.log(22)
}).catch(reason= > {
    console.log(reason)
})
Copy the code

Any previous section that returns only a failed promise or throws an exception will handle the failure in the final catch() method.

2.2.7 Interrupt the Promise chain?

A promise chain is a chain of.then().then().then().

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

  • Solution: Return a promise object in a pending state from the callback function

None of the subsequent then () methods will execute because the state of the promise has not changed

const p1 = new Promise((resolve, reject) = > {
   setTimeout(() = > {
    resolve('OK')},1000);
}) 
p1.then(value= > {
    return new Promise((resolve, reject) = > {
        console.log(11)
    })
}).then(value= > {
    // There is only one method
    // The subsequent then () methods do not execute because the state of the promise has not changed
    return new Promise(() = > {})
}).then(value= > {
    console.log(22)
}).catch(reason= > {
    console.log(reason)
})

/ / 11
Copy the code

Async and await

3.1 async

What is async function?

  • It is the syntactic sugar for Generator functions.

There is a Generator function that reads two files in turn.

var fs = require('fs');

var readFile = function (fileName){
  return new Promise(function (resolve, reject){
    fs.readFile(fileName, function(error, data){
      if (error) reject(error);
      resolve(data);
    });
  });
};

var gen = function* (){
  var f1 = yield readFile('/etc/fstab');
  var f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
Copy the code

Write it as async, which looks like this:

var asyncReadFile = async function (){
  var f1 = await readFile('/etc/fstab');
  var f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
Copy the code

A comparison shows that an async function simply replaces the asterisk (*) of a Generator function with async, replaces yield with await, and nothing more.

  • The return value of the function isPromise object

If the return value of an async function does not appear to be a promise, it will be wrapped implicitly in a Promise. The result of the promsie object is determined by the return value executed by the async function

async function foo(){
    // return 5
    // The above is equivalent to the following
    return Promise.resolve(5)}console.log(foo())
Copy the code

3.2 await

The await operator is used to wait for a Promise object and can only be used in async function. Await expression suspends execution of the current async function until the Promise processing completes.

  • If the Promise is fulfilled normally, the resolve function parameter of its callback will be the value of await expression and the async function will continue to be executed.

  • If a Promise handles an exception rejected,await expression throws the exception reason for the Promise;

  • If the value of the expression after the parent of the await operation is not a Promise, the value itself is returned;

  • The expression to the right of await is typically a promise object, but it can be any other value;

3.3 Advantages of using Async and Await?

Async means that there is an asynchronous operation in a function, and await means that the following expression needs to wait for the result.

  • The Async and Await keywords allow us to write asynchronous execution behavior based on promises in a more concise way, without intentionally chain-calling promises.

  • Write asynchronous code synchronously

  • Easier to debug code

  • Solve callback hell

An async function with no await expression is run synchronously. However, an async function must be executed asynchronously if the function body has an await expression.

3.4 Notes on using Async and Await

  1. awaitAfter commandPromiseObject, the result of which might berejectedSo it’s better toawaitCommand intry... catchCode block.
async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err); }}// Another way to write it

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}
Copy the code
  1. multipleawaitAfter commandAsynchronous operationsIf there is no secondary relationship, it is best to let themAt the same time trigger, so it willTo shorten theThe execution time of the program.
/ / write one
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

/ / write two
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
Copy the code
  1. awaitCommands can only be used whenasyncFunction, if used in ordinary functions, will report an error.
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  / / an error
  docs.forEach(function (doc) {
    await db.post(doc);
  });
}
Copy the code

The above code will report an error because await is used in normal functions. However, if you change the argument of forEach to async, there are problems.

async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    awaitdb.post(doc); }}Copy the code

For example, 3.5

function sendAjax(method, url) {
    return new Promise((resolve, reject) = > {
        const xhr = new XMLHttpRequest();
        // xhr.responseType = 'json';
        xhr.open(method, url);
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response)
                } else {
                    reject(xhr.code)
                }
            }
        }
    })
}
// Promise's then() call
sendAjax("GET".'./data/content.txt').then(data= > {
    console.log(data)
}, code= > {
    console.log(code)
})

// async await
async function getData(){
    try {
        const data = await sendAjax("GET".'./data/content.txt');
        console.log(data)
    } catch (error) {
        console.log(error)
    }
}
Copy the code

JS asynchronous microqueue and macro queue

The principle diagram of the 5.1

At the beginning, the whole script is executed as a macro task. In the process of execution, the synchronous code is directly executed. The red task enters the macro task queue, and the micro task enters the micro task queue

5.2 Examples

setTimeout(() = > {
    console.log('timeout callback1()')
    Promise.resolve(3).then(
    value= > {
        console.log('Promise3' +'* * *'+ value)
    }
   )
}, 0);

setTimeout(() = > {
    console.log('timeout callback2()')},0);

Promise.resolve(1).then(
    value= > {
        console.log('Promise1' +'* * *'+ value)
    }
)
Promise.resolve(2).then(
    value= > {
        console.log('Promise2' +'* * * *'+ value)
    }
)
Copy the code

The queue used to store callback functions to be executed in JS contains two different specific queues.

5.2 summarize

Macro queue: Used to hold macro tasks (callbacks) to be executed, such as timer callbacks /DOM event callbacks /Ajax callbacks

Microqueue: used to hold microtasks (callbacks) to be executed, such as promise’s callback /MutationObserver callback macro tasks: Script, timer, I/O, UIrander microtasks: Other technologies developed based on MutationObserver, promise.then () or Catch (), Promise: fetchApi, V8’s garbage collection process, Node’s unique Promise.nexttick.

JS execution distinguishes between two queues:

  • The JS engine must perform all the initial synchronization code

  • Each time the first macro task is ready to be extracted, all the microtasks are extracted and executed one by one

Synchronization => Micro task => macro task

5.3 Promise

Interview question 1:

 setTimeout(() = > {
    console.log(1)},0);
Promise.resolve().then(() = > {
    console.log(2)})Promise.resolve().then(() = > {
    console.log(4)})console.log(3)
// 3 2 4 1
Copy the code

Interview question 2:

setTimeout(() = > {
    console.log(1)},0);
new Promise((resolve) = > {
    console.log(2) / / synchronize
    resolve()
}).then(() = > {
    console.log(3)
}).then(() = > {
    console.log(4)})console.log(5)

//2 5 3 4 1
Copy the code

The interview questions in three

const first = () = > (new Promise((resolve, reject) = > {
    console.log(3)
    let p = new Promise((resolve, reject) = > {
        console.log(7)
        setTimeout(() = > {
            console.log(6)
            resolve(6)},0);
        resolve(1)
    })
    resolve(2)
    p.then(arg= > {
        console.log(arg)
    })
}))
first().then(arg= > {
    console.log(arg)
})
console.log(4)
// 3 7 4 1 2 6
Copy the code

Resolution:Perform synchronization in first(), then print 4, then perform microtask in first, and finally macro task.

The interview is four

 setTimeout(() = > {
    console.log(0)},0);
new Promise((resolve, reject) = > {
    console.log(1)
    resolve()
}).then(() = > {  / / 1
    console.log(2)
    new Promise((resolve, reject) = > {
        console.log(3)
        resolve()
    }).then(() = > { / / 3
        console.log(4)
    }).then(() = > { / / 4
        console.log(5)
    })
}).then(() = > {  / / 2
    console.log(6)})new Promise((resolve, reject) = > {
    console.log(7) 
    resolve()
}).then(() = > {
    console.log(8)  / / 1
})
Copy the code
  • Async MDN

  • The meaning and usage of async functions

  • ECMAScript introduction to 6