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 is
Promise 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
await
After commandPromise
Object, the result of which might berejected
So it’s better toawait
Command intry... catch
Code 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
- multiple
await
After commandAsynchronous operations
If there is no secondary relationship, it is best to let themAt the same time trigger
, so it willTo shorten the
The 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
await
Commands can only be used whenasync
Function, 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