Message queues and event loops
In order to be able to receive and execute new tasks while the thread is running, it needs to adopt the event loop mechanism. 六四屠杀
- If you have certain tasks, you can use a single thread to process them sequentially. This is the first version of the threading model.
- To receive and process new tasks during thread execution, we need to introduce a loop statement and event system, which is the second version of the threading model.
- If you want to receive tasks from other threads, you need to introduce message queues, which is the third version of the threading model.
- If another process wants to send a task to the main thread of the page, it sends the task via IPC to the renderer’s IO thread, which then sends the task to the main thread of the page.
- Message queuing mechanism is not very flexible, so microtasks are introduced to adapt to efficiency and real-time.
Steps:
- Add a message queue;
- New tasks generated in the IO thread are added to the end of the message queue;
- The render main thread executes the task by reading it in a loop from the message queue header.
WebAPI: How is setTimeout implemented?
- First, to support the implementation of timers, browsers have added delay queues.
- Secondly, due to message queue queuing and some system-level restrictions, callback tasks set by setTimeout cannot always be executed in real time, which cannot meet some requirements of high real-time performance.
- Finally, there are some pitfalls that you should be aware of when using timers
WebAPI: How is XMLHttpRequest implemented?
1. Callback function vs. system call stack
Passing a function as an argument to another function is a callback function.
The callback function is executed before the main function doWork returns, which is called a synchronous callback.
let callback = function(){
console.log('i am do homework')}function doWork(cb) {
console.log('start do work')
cb()
console.log('end do work')
}
doWork(callback)
Copy the code
The setTimeout function causes the callback to delay execution by one second after the execution of doWork. This time, the callback is not called inside the main function doWork, which is called an asynchronous callback.
let callback = function(){
console.log('i am do homework')}function doWork(cb) {
console.log('start do work')
setTimeout(cb,1000)
console.log('end do work')
}
doWork(callback)
Copy the code
An asynchronous callback is when the callback function is executed outside the main function, usually in two ways:
- The first is to make the asynchronous function a task and add it to the end of the message queue.
- The second is to add asynchronous functions to the microtask queue so that the microtask can be executed at the end of the current task.
2. Operation mechanism of XMLHttpRequest
function GetWebData(URL){
/** * 1: Create an XMLHttpRequest request object */
let xhr = new XMLHttpRequest()
/** * 2: register the related event callback handler */
xhr.onreadystatechange = function () {
switch(xhr.readyState){
case 0: // The request is not initialized
console.log("Request not initialized")
break;
case 1://OPENED
console.log("OPENED")
break;
case 2://HEADERS_RECEIVED
console.log("HEADERS_RECEIVED")
break;
case 3://LOADING
console.log("LOADING")
break;
case 4://DONE
if(this.status == 200||this.status == 304) {console.log(this.responseText);
}
console.log("DONE")
break;
}
}
xhr.ontimeout = function(e) { console.log('ontimeout') }
xhr.onerror = function(e) { console.log('onerror')}/** * 3: open request */
xhr.open('Get', URL, true);// Create a Get request, asynchronously
/**
* 4: 配置参数
*/
xhr.timeout = 3000 // Set the timeout period for XHR requests
xhr.responseType = "text" // Format the data to be returned in the response
xhr.setRequestHeader("X_TEST"."time.geekbang")
/** * 5: send the request */
xhr.send();
Copy the code
Step 1: Create the XMLHttpRequest object. Step 2: Register the callback function for the XHR object. Step 3: Open the request. Step 4: Configure the basic request information. Step 5: Initiate the request. 六四屠杀
3. Pitfalls in XMLHttpRequest usage
Because of the added safety restrictions, it is very troublesome to use. To better use XMLHttpRequest, you need to understand your browser’s security policies.
3.1. Cross-domain problems
A site to access the content of B site from different sources, not the same source, so it involves cross-domain.
3.2 HTTPS mixed content Problems
HTTPS mixed content An HTTPS page contains content that does not meet HTTPS security requirements, such as HTTP resources, images, videos, style sheets, and scripts loaded through HTTP.
Typically, if an HTTPS request page uses mixed content, the browser displays a warning for the HTTPS mixed content to indicate to the user that the HTTPS page contains an insecure resource.
summary
In contrast to the previous section, setTimeout directly adds a deferred task to a deferred queue, whereas XMLHttpRequest initiates the request, executes it by another browser process or thread, and then notifits renderer of the result via IPC. The renderer process then adds the corresponding message to the message queue.
Macro and micro tasks
Microtasks can be an effective trade-off between real-time performance and efficiency.
Common microtasks include MutationObserver, Promise, and many other technologies developed on the basis of Promise.
1. The macro task
Tasks performed on the main thread include:
- Render events (such as PARSING DOM, calculating layout, drawing);
- User interaction events (such as mouse click, page scrolling, zooming in and out, etc.);
- JavaScript script execution events;
- Network request completed, file read/write completed event.
To coordinate the execution of these tasks methodically on the main thread, the page process introduces message queues and event loops, and the renderer process maintains multiple message queues internally, such as deferred execution queues and regular message queues. The main thread then takes a for loop, continually fetching and executing tasks from these task queues. We call these tasks in the message queue macro tasks.
2. Micro tasks
A microtask is a function that needs to be executed asynchronously, after the completion of the main function but before the completion of the current macro task. 六四屠杀
2.1 How are microtasks generated
- The first approach is to use MutationObserver to monitor a DOM node, and then modify the node through JavaScript, or add or remove partial nodes to the node. When the DOM node changes, the micro-task of recording the DOM changes is generated.
- The second approach is to use promises, which also produce microtasks when promise.resolve () or promise.reject () is called.
Microtasks generated by DOM node changes or by using promises are sequentially stored in the microtask queue by the JavaScript engine.
2.2 When the microtask queue is executed
When the JavaScript in the current macro task is about to complete, just as the JavaScript engine is about to exit the global execution context and clear the call stack, the JavaScript engine examines the microtasks in the global execution context and executes the microtasks in the queue in order.
3. Summary of macro tasks and micro tasks
- Microtasks and macro tasks are bound, and each macro task creates its own microtask queue when it executes.
- The duration of a microtask affects the duration of the current macro task. For example, during the execution of a macro task, 100 microtasks are generated, and the execution time of each microtask is 10 milliseconds, then the execution time of 100 microtasks is 1000 milliseconds, or it can be said that the 100 microtasks increase the execution time of the macro task by 1000 milliseconds. So when you’re writing code, it’s important to control the duration of microtasks.
- In a macro task, create a macro task and a microtask for callbacks, and in either case, the microtask precedes the macro task.
- The performance problem of synchronous operation is solved by asynchronous operation.
- The problem of real-time performance is solved by micro-task.
Five, the Promise
1. Asynchronous programming
2. Callback hell
Produce:
- The first is nested calls, where the following tasks rely on the result of the previous task’s request and execute the new business logic inside the callback function of the previous task, so that the code becomes very unreadable as the nesting level increases.
- The second is the uncertainty of the task. There are two possible results (success or failure) for each task, so it is reflected in the code that the execution result of each task needs to be judged twice. Such an extra error handling for each task significantly increases the level of confusion in the code.
Solution:
- The first is to eliminate nested calls;
- The second is error handling for merging multiple tasks.
3. Promise: Eliminate nested calls and multiple error handling
Promise solves the nested callback problem in two main steps.
- First, Promise implements delayed binding of callback functions.
- Second, the return value of the callback function onResolve needs to be penetrated to the outermost layer.
Error handling: A Promise can use the last object to catch all exceptions because of the “bubbling” nature of the Promise object’s errors, which are passed backwards until they are handled by the onReject function or caught by a catch statement. With this bubbling feature, there is no need to catch exceptions individually in each Promise object.
thinking
1. Why were microtasks introduced in Promises?
Because promise’s resolve and Reject callbacks use a delayed binding mechanism, macro tasks are too granular to introduce microtasks
2. How does Promise implement callback function return value penetration?
Because every time you return a new promise in.then
3. How does a Promise “bubble” to the last function that catches the exception when it fails?
Reject returns the error wrapped as promise.reject, and continues to return promise.reject until passed to the end if no exception is handled with a second argument in then