Best JavaScript asynchronous programming guide, js is single-threaded, and the execution stack and rendering thread of js in the browser block each other. The biggest advantage of single-threaded mode is that it is safer and simpler.
Advantages and disadvantages of single thread
js is single-threaded, and the execution stack and rendering thread of js in the browser block each other. JavaScript asynchronous programming.
The biggest advantage of single-threaded mode is that it is safer and simpler. The
disadvantage is also clear, that is, if there is a particularly time-consuming task in the middle, other tasks will have to wait a long time, resulting in suspended animation.
In order to solve this problem, js has two task execution modes: synchronous mode (Synchronous) and asynchronous mode (Asynchronous) .
JavaScript asynchronous programming
Synchronous mode
It means that the tasks of the code are executed in sequence, and the latter task must wait for the end of the previous task to start execution.
The execution sequence of the program and the writing sequence of the code are exactly the same.
In single-threaded mode, most tasks will be executed in synchronous mode. JavaScript asynchronous programming.
Disadvantages : Because it is similar to queued execution, if once a certain operation is particularly time-consuming, the page will freeze and freeze, so asynchronous mode is required.
Asynchronous mode
Asynchronous mode does not wait for the end of this task to start the next task. It executes the next task immediately after it is turned on. The subsequent logic of the time-consuming function will be defined in the form of a callback function . After the task is completed, the callback function is called.
Asynchronous mode is very important for single-threaded JavaScript. Without this mode, single-threaded JavaScript cannot handle a large number of time-consuming tasks at the same time.
The biggest difficulty in the asynchronous mode under single thread is the disorder of code execution.
The way the asynchronous code is executed is simply:
- The js thread initiates an asynchronous call at a certain moment, and then it continues to perform other tasks.
- At this time, the asynchronous thread will execute the asynchronous task separately, and will put the callback in the message queue after execution.
- After the js main thread executes the task, it will execute the tasks in the message queue in turn.
It should be emphasized here that js is single-threaded, and browsers are not single-threaded. There are some APIs that have separate threads to do. JavaScript asynchronous programming.
Callback
Callback function : a function defined by the caller and handed over to the executor for execution
// callback is the callback function // The function is passed as a parameter. The disadvantage is that it is not conducive to reading and the execution order is chaotic. function foo(callback) { setTimeout(function(){ callback() }, 3000) } foo(function() { console.log('This is a callback function') console.log('The caller defines this function, and the executor executes this function') console.log('In fact, the caller tells the executor what to do after the asynchronous task ends') })
JavaScript asynchronous programming
Promise asynchronous solution
Promise overview
The multiple nesting of callbacks will cause the code to be less readable, hard to write, and error-prone, so it is called callback hell.
To avoid this problem. The CommonJS community proposed the Promise specification, which is called the language specification in ES6.
Promise is an object used to express whether an asynchronous task succeeds or fails after execution. It has multiple states:
- Pending status, which means that it is not clear whether the result of asynchronous execution is success or failure.
- Fulfilled completed status, indicating that the operation has been completed
- Rejected operation failed
Basic usage of Promise
Return to resolve
const promise = new Promise((resolve, reject) => { resolve(100) }) promise.then((value) => { console.log('resolved', value) // resolve 100 },(error) => { console.log('rejected', error) })
JavaScript asynchronous programming
Return reject
const promise = new Promise((resolve, reject) => { reject(new Error('promise rejected')) }) promise.then((value) => { console.log('resolved', value) },(error) => { console.log('rejected', error) })
JavaScript asynchronous programming
Even if there is no asynchronous operation in the promise, the callback function of the then method will still enter the event queue.
Promise chain call
The then method of the promise object returns a brand new promise object. You can continue to call the then method. If the return is not a promise object, but a value, then this value will be passed as the value of the resolve. If there is no value, the default is undefined.
The following then method is to register a callback for the Promise returned by the previous then.
The return value of the callback function in the previous then method will be used as the callback parameter of the subsequent then method.
If the promise is returned in the callback, then the callback of the then method will wait for its end.
// promise is assumed to be a Promise instance // The callback in then returns a Promise instance promise.then(()=>{ return new Promise((resolve,reject)=>{ // some code resolve("actual parameter A") }) }).then( (Receive the actual parameter A)=>{ as the callback in the previous then}) // The callback return in then is not a promise instance promise.then(()=>{ return 123 }) .then(val=>{ console.log(val) // 123 })
JavaScript asynchronous programming
Promise exception handling
onRejected method of callback in then
Which is the second callback function in then
.catch() (recommended)
If the second callback is not passed in then then the exception will enter the callback processing of catch
If there is an exception in the promise, the reject method will be called, and you can also use .catch()
It is more common to use the .catch method because it is more in line with chain calls
The unhandledrejection event on the global object
You can also register an unhandledrejection event on the global object to handle promise exceptions that are not manually caught in the code. Of course, it is not recommended to use
// browser window.addEventListener('unhandledrejection', event => { const {reason, promise} = event console.log(reason, promise) //reason => Promise failure reason, usually an error object //promise => Promise object with exception event.preventDefault() }, false) // node process.on('unhandledRejection', (reason, promise) => { console.log(reason, promise) //reason => Promise failure reason, usually an error object //promise => Promise object with exception })
JavaScript asynchronous programming
Two static methods
Promise.resolve
- Without parameters, return a Fulfilled state behind the Promise object. Then executes the first callback in then
- The parameter is a simple data type and returns a Fulfilled state behind the Promise object. Then executes the first callback in then, and passes the parameter as an actual parameter to the callback
- If the incoming is a Promise object, the Promise.resolve method returns as it is
- If you pass in an object with the same then method as Promise, Promise.resolve will execute this object as a Promise
Promise.resolve('foo') .then(function (value) { console.log(value) }) new Promise(function (resolve, reject) { resolve('foo') }) // If the incoming is a Promise object, the Promise.resolve method returns as it is var promise = ajax('/api/users.json') var promise2 = Promise.resolve(promise) console.log(promise === promise2) // If you pass in an object with the same then method as Promise, // Promise.resolve will execute this object as a Promise Promise.resolve({ then: function (onFulfilled, onRejected) { onFulfilled('foo') } }) .then(function (value) { console.log(value) })
JavaScript asynchronous programming
Promise.reject
The Promise.reject() method returns a Promise object with a reason for rejection
// Any value passed in Promise.reject will be used as the reason for the failure of this Promise Promise.reject(new Error('rejected')) .catch(function (error) { console.log(error) }) Promise.reject('anything') .catch(function (error) { console.log(error) })
JavaScript asynchronous programming
Promise parallel execution
.all()
The Promise.all method accepts an array as a parameter. The objects in the array (p1, p2, p3) are all promise instances (if it is not a promise, the item will be converted to a promise by Promise.resolve).
Return a brand new Promise instance whose state is determined by these three promise instances. Only when all of them are fulfilled, the new Promise will enter fulfilled.
.race()
The Promise.race method also accepts an array as a parameter. When the state of one of the instances of p1, p2, and p3 changes (becomes fulfilled or rejected), the state of p changes accordingly. And pass the return value of the first promise that changes state to the callback function of p
Promise execution timing
How to simply understand the macro tasks and micro tasks. For
example, if you queue up for business in the bank,
then everyone in the queue can be regarded as a macro task.
When the queue arrives, you tell the teller that you need to apply for a card, deposit money, and transfer money. These are microtasks. The teller will not let you re-queue after finishing a business, but handle all your micro tasks at once. Then it will be the next person’s turn, which is the next macro task.
Macro task
(macro) task, it can be understood that the code executed each time the stack is executed is a macro task (including each time an event callback is obtained from the event queue and placed on the execution stack).
The macro task includes
script (overall code, synchronous code) setTimeout setInterval I/O UI interaction events postMessage MessageChannel setImmediate (Node.js environment)
JavaScript asynchronous programming
Micro task
(micro)task, it can be understood that it is a task that is executed immediately after the execution of the current task ends. In other words, after the current task, before the next task, before rendering.
Micro tasks include
Promise.then Object.observe MutaionObserver process.nextTick (Node.js environment)
JavaScript asynchronous programming
Determine the result of code execution
// micro task console.log('global start') // The callback of setTimeout is a macro task, which enters the callback queue setTimeout(() => { console.log('setTimeout') }, 0) // The callback of Promise is a micro task, which is executed directly at the end of the call Promise.resolve() .then(() => { console.log('promise') }) .then(() => { console.log('promise 2') }) .then(() => { console.log('promise 3') }) console.log('global end')
JavaScript asynchronous programming
turn out:
// The synchronization code is regarded as a macro task. After the execution is completed, all micro tasks generated in the macro task stage are executed, that is, the then in the promise, and then the next macro task is executed global start global end promise promise 2 promise 3 setTimeout
JavaScript asynchronous programming
Generator asynchronous scheme, Async/Await syntax sugar
Generator generator function
The Generator function can pause execution and resume execution. In addition, it has two features: data exchange inside and outside the function body and error handling mechanism.
The next method does not pass parameters and returns an object. The next method passes in parameters and passes the parameters to the value attribute of the return value of the function. The generator function outputs data to the outside; the next method can also accept parameters, which are input into the generator function data.
function* gen(x){ var y = yield x + 2; return y; } var g = gen(1); g.next() // { value: 3, done: false } g.next(2) // { value: 2, done: true }
JavaScript asynchronous programming
In the above code, the value attribute of the first next method returns the value of the expression x + 2 (3). The second next method takes parameter 2. This parameter can be passed to the Generator function, as the return result of the asynchronous task of the previous stage, and received by the variable y in the function body. Therefore, the value attribute of this step returns 2 (the value of variable y).
Error handling code can also be deployed inside the Generator function to capture errors thrown outside the function.
function* gen(x){ try { var y = yield x + 2; } catch (e){ console.log(e); } return y; } var g = gen(1); g.next(); g.throw('Something went wrong'); // error
JavaScript asynchronous programming
In the last line of the above code, outside the Generator function, the error thrown by the throw method of the pointer object can be caught by the try…catch code block in the function body.
Generator cooperating with Promise’s asynchronous solution can use the co library in development.
Of course, “My lord, the times have changed”We now use async / await
Async/Await syntactic sugar
Everyone has used it a lot, so I won’t repeat it.
Basic usage
async function main () { try { const users = await ajax('/api/users.json') console.log(users) const posts = await ajax('/api/posts.json') console.log(posts) const urls = await ajax('/api/urls.json') console.log(urls) } catch (e) { console.log(e) } }
JavaScript asynchronous programming
Exception handling
Let the Promise object behind await catch itself
You can also catch the Promise object returned by the outside async function uniformly
Like synchronization code, put it in a try…catch structure;