From JavaScript event loop to Promise
The JS thread is a single-threaded running mechanism, that is, to do its own thing in order. The browser thread is used for interaction and control. JS can operate DOM elements. When talking about Asynchronization in JS, we need to note that JS has two types of Asynchronization: one is browser-based Asynchronous IO, such as Ajax, and the other is setTimeout and setInterval Based on the timing method.
For asynchronous I/O, such as ajax, code is executed sequentially, but a separate browser thread is used to process requests, callback is triggered after processing is complete. In this case, there are actually two thread subjects involved in the asynchronous process, one is the javascript main thread, and the other is the browser thread.
Anyone familiar with Javascript knows that there is an event queue in Javascript, and all processing methods are in this queue. The main Javascript thread is polling this queue for processing, the advantage is that the CPU is always busy. This mechanism is the same as the message pump in Windows, and is driven by messages (events,
For setTimeout and setInterval, when the js thread executes the code snippet, the main js thread will expire at the specified time, put the set callback function in the event queue, and then the main js thread continues to execute the following code. After the js thread executes the code on the main thread, the function in the event queue is executed cyclically. The execution time set by setTimeout or setInterval has some deviations in actual performance. A common explanation is that when the scheduled task expires, the callback function should be executed, however, in this case, the main js thread may still have tasks being executed, or the callback function is back-to-back in the event queue, causing the execution time of the callback function to be different from the time set by the timer.
So the question is, what is event queue?
Eventloop is an array used as a queue, and eventloop is always executed cyclically. Every round of the loop becomes a tick. In every tick, if there is a waiting event in the queue, the next event will be extracted from the queue for execution. These events are our previous callback functions. ES6 now precisely specifies the details of the event loop, which means that it is technically included in the JavaScript engine's sphere of influence, not just determined by the host environment, one major reason is the introduction of promise in ES6.
Var eventloop = []
Var event;
While (true ){
If (eventloop. length> 0 ){
// Get the next event in the queue
Event = eventloop. shift ();
// Execute the next event
Try {
Event ();
} Catch (e ){
ReportError (e );
}
}
}
On the browser side, the minimum time interval in setTimeout is specified by W3C in the HTML standard, and the time interval less than 4 ms is counted as 4 ms.
At any time, you only need to wrap a code into a function and specify that it is executed in response to an event. You create a module for future execution in the code, the asynchronous mechanism is also introduced in this program.
The js engine does not run independently. It runs in the host environment, that is, the Web browser we see. Of course, with the development of js, including the latest Node, it provides js with an environment for running on the server. In addition, the current js is also embedded into the various configurations of the robot to the lightbulb.
However, all these environments share a common "point", which provides a mechanism to process the execution of multiple blocks in the program, the JavaScript engine is called when each block is executed. This mechanism is called an event loop.
The js engine does not have the concept of time. It is just an environment for executing arbitrary JavaScript code snippets as needed.
The most common callback in js is chained callback and nested callback.
We often nest ajax calls in ajax and then nest ajax calls. This is the callback hell. The biggest problem with callback is control inversion, which will lead to a complete break of the trust chain, to solve the control inversion problem in callback, Some APIs provide the separation callback (one for success notification and one for failure notification), such as the success function and failure function in ajax. In this case, the API error handling function failure () can often be omitted. If it is not provided, it is assumed that the error can be swallowed up.
Another callback mode is called "error-first". The first callback parameter is retained as the error object. If the callback is successful, the parameter is cleared/set to false.
Callback functions are the basic unit of JavaScript Asynchronization. However, as JavaScript matures, callback is not enough for the development of the asynchronous field.
Promise
Promise is a solution in asynchronous programming. It was first proposed and implemented by the Community. ES6 wrote it into the language standard, unified usage, and Native Promise object.
Promise is an easy-to-reuse mechanism for encapsulating and combining future values. A process control mechanism that acts as two or more steps in an asynchronous task, this-then-that in time series. if we call a function foo (), we do not need to care about more details in foo. This function may complete the task immediately or after a while. For us, we only need to know when foo () will complete the task, so that we can continue to execute the next task. In the traditional method, let's go back and choose to listen to the function's degree of completion. When it completes, we will be notified through the callback function. At this time, we will be notified to execute the callback in foo, but when promise is used, what we need to do is to listen for events from foo, and then decide as needed when we get the notification.
One of the important advantages is that we can provide the listening objects in this event to multiple independent parts in the Code. When foo () is completed, they can be notified independently:
Var evt = foo ();
// Let bar () Listen to the completion of foo ()
Bar (evt );
// Let baz () Listen to the completion of foo ()
Baz (evt );
In the above example, bar and baz do not need to know or pay attention to the Implementation Details in foo. In addition, foo does not need to focus on the implementation details in baz and bar.
In the same way, in promise, the previous code snippet will let foo () Create and return a Promise instance, and the Promise will be passed to bar () and baz (). So in essence, promise is the object returned by a function. You can bind the callback function to this object instead of passing the callback function as a parameter to the function.
Const promise = doSomething ();
Promsie. then (successCallback, failureCallback ){
}
Of course, promise does not pass the callback function to two processing functions like the old functions, and it has the following advantages:
- The callback function will never be executed until the tick operation of the JavaScript event queue is completed.
- Callback functions added in the form of. then are called even functions added after the asynchronous operation is complete.
- You can add multiple callback functions by calling. then multiple times, which run independently according to the insertion sequence.
However, the most direct good output of Promise is the chain call.
DoSomething (). then (function (result ){
Return doSomethingElse (result );
})
. Then (function (newResult ){
Return doThirdThing (newResult );
})
. Then (function (finalResult ){
Console. log ('got the final result: '+ finalResult );
})
. Catch (failureCallback );
In addition, you can continue to use the chained operation after a failed operation, even if an action in the chained operation fails, it can help the new action to continue to complete.
When calling the resolve () and reject () functions in Promise with parameters, their parameters will be passed to the callback function.
Promise. resolve () and Promise. reject () are shortcut methods for manually creating a promise that has already been resolve or reject. Generally, we can use Promise. resolve () to chain an array composed of asynchronous functions. For example:
Promise. resolve (). then (func1). then (func2 );
Promise. all () and Promise. Race () is a combined tool that runs asynchronous operations in parallel.
The Promise. then () method is used to specify the callback functions for the resolved state and rejected state respectively. The function passed to then is placed in a micro-task queue instead of being executed immediately. This means that it is executed only after all operations in the JavaScript event queue are completed and the event queue is cleared.
Let promise = new Promise (function (resolve, reject ){
Console. log ('Promise ');
Resolve ();
});
Promise. then (function (){
Console. log ('fig .');
});
Console. log ('Hi! ');
// Promise
// Hi!
// Resolved
The Promise. then () method returns a Promise, which requires a maximum of two parameters: the success and failure callback functions of Promise.
P. then (onFulfilled, onRejected );
P. then (function (value ){
// Fulfillment
}, Function (reason ){
// Rejection
});
OnFulfilled: When Promise changes to the accept status (fulfillment), this parameter is called as a callback function. This function has a parameter, that is, the accepted value.
OnRejected: When Promise becomes denied, this parameter is called as a callback function. This function has a parameter, that is, the reason for rejection.
Once the Promise status changes, it will be permanently maintained and will not be changed.
Handle errors in Promise
In general, we will throw an error in every Promise, and the rejected processing function in the then function in Promise will be called. This is a common method for error handling:
Let p = new Promise (function (resolve, reject ){
Reject ('error ');
});
P. then (function (value ){
Success (value );
}, Function (error ){
Error (error)
}
)
However, a better way is to use the catch function to handle internal errors in Promise. The catch Method returns a Promise object, and the then method can be called later. In addition, try to write the catch Method in the last one of the chain calls to avoid the following then method errors being captured.
Let p = new Promise (function (resolve, reject ){
Reject ('error ');
});
P. then (function (value ){
Success (value );
}). Catch (function (error ){
Console. log ('error ');
}}
Promise. finally () function, which is introduced by ES2018. Specifies the operations that will be performed regardless of the final state of the Promise object. The callback function of the finally method does not accept any parameters, which means there is no way to know whether the previous Promise status is fulfilled or rejected. This indicates that the operations in the finally method are irrelevant to the status and independent from the execution result of Promise.
Please correct the above article if any error occurs. Thank you !!!