Write a JavaScript framework: Better scheduled execution than setTimeout

Source: Internet
Author: User
This is the second chapter of the JavaScript framework series. In this chapter, I plan to explain how asynchronous code is executed in a browser. You will understand the differences between the timer and the event loop, such as setTimeout and Promises. This series is about an open-source client framework called NX. In this series, I mainly explain the main difficulties that the framework has to overcome. This is the second chapter of the JavaScript framework series. In this chapter, I plan to explain how asynchronous code is executed in a browser. You will understand the differences between the timer and the event loop, such as setTimeout and Promises.

This series is about an open-source client framework called NX. In this series, I mainly explain the main difficulties that the framework has to overcome. If you are interested in NX, visit our homepage.

This series contains the following chapters:

Project Structure

Scheduled execution (current chapter)

Sandbox code Evaluation

Data Binding

Data Binding with ES6 proxy

Custom Elements

Client route

Asynchronous Code Execution

You may be familiar with asynchronous code execution methods such as Promise, process. nextTick (), setTimeout (), and requestAnimationFrame. They all use event loops internally, but they differ in exact timing.

In this chapter, I will explain the differences between them and demonstrate how to implement a timing system in an advanced framework like NX. We don't need to redo it. We will use the native event loop to achieve our goal.

Event Loop

Event loops are not even mentioned in ES6 standards. JavaScript only has jobs and Job queues ). More complex event loops are defined separately in NodeJS and HTML5 specifications, because this article is for the frontend, And I will describe the latter in detail.

Event loops can be seen as loops of a condition. It keeps searching for new tasks to run. An Iteration in this loop is called a tick ). The Code executed during a tick answer is called a task ).

while (eventLoop.waitForTask()) {     eventLoop.processNextTask() }

A task is a synchronization code that can schedule other tasks in a loop. SetTimeout (taskFn) is a simple way to call a new task ). In any case, a task may have many sources, such as user events, network operations, or DOM operations.

Task queue

More complex, event loops can have multiple task queues. There are two constraints: the events of the same task source must be in the same queue, and the tasks must be processed in the order of insertion. In addition, the browser can do anything it wants to do. For example, it can decide which task queue to process next.

while (eventLoop.waitForTask()) {     const taskQueue = eventLoop.selectTaskQueue()   if (taskQueue.hasNextTask()) {     taskQueue.processNextTask()   } }

With this model, we cannot accurately control timing. If you use the setTimeout () browser, you may decide to run several other queues before running our queue.

Microtask queue

Fortunately, the event loop also provides a single queue called a microtask queue. At the end of the current task, the microtask queue clears the tasks in each tick answer.

while (eventLoop.waitForTask()) {     const taskQueue = eventLoop.selectTaskQueue()   if (taskQueue.hasNextTask()) {     taskQueue.processNextTask()   }   const microtaskQueue = eventLoop.microTaskQueue   while (microtaskQueue.hasNextMicrotask()) {     microtaskQueue.processNextMicrotask()   } }

The simplest way to call a microtask is Promise. resolve (). then (microtaskFn ). Micro-tasks are processed in the insert order, and because only one micro-task queue exists, the browser will not mess up the time.

In addition, a micro-task can schedule a new micro-task, which will be inserted into the same queue and processed in the same answer.

Draw Rendering

The last step is to draw Rendering scheduling. Unlike event processing and decomposition, Rendering is not completed in a separate background task. It is an algorithm that can run at the end of each loop.

Here, the browser has a lot of freedom: It may be drawn after each task, but it may not be drawn after hundreds of tasks are executed.

Fortunately, we have requestAnimationFrame (), which executes the passed function before the next draw. Our final event model is like this:

while (eventLoop.waitForTask()) {     const taskQueue = eventLoop.selectTaskQueue()   if (taskQueue.hasNextTask()) {     taskQueue.processNextTask()   }   const microtaskQueue = eventLoop.microTaskQueue   while (microtaskQueue.hasNextMicrotask()) {     microtaskQueue.processNextMicrotask()   }   if (shouldRender()) {     applyScrollResizeAndCSS()     runAnimationFrames()     render()   } }

Now we use all our knowledge to create a timing system!

Use event Loops

Like most modern frameworks, NX is also based on DOM operations and data binding. Batch operation and asynchronous execution to achieve better performance. For the above reasons, we use Promises, MutationObservers, and requestAnimationFrame ().

The expected timer is as follows:

The Code comes from developers.

Data Binding and DOM operations are performed by NX.

Developer-defined event hooks

Draw in the browser

Step 1

The NX register object runs synchronously Based on the ES6 proxy and DOM changes based on MutationObserver (Change observer) (details in the next section ). It acts as a microtask and is delayed until step 2 is executed. This latency has been converted to objects in Promise. resolve (). then (reaction) and will be automatically run through the change observer.

Step 2

The Code (task) from the developer is completed. Microtask Registration starts with NX. Because they are micro tasks, they are executed in order. Note that we are still in the same tick loop.

Step 3

The developer notifies NX to run the hook through requestAnimationFrame (hook. This may happen after the tick-Answer loop. It is important that the hook runs before the next draw and after all data operations, and DOM and CSS changes have been completed.

Step 4

The browser draws the next view. This may also happen after the tick-Answer loop, but it will never happen before step 3 of a tick-answer.

Keep in mind

We have implemented a simple and effective Timing System Based on the native event loop. Theoretically speaking, it runs well, but it is still very fragile. A slight error may cause a very serious BUG.

In a complex system, the most important thing is to establish certain rules and maintain them later. There are the following rules in NX:

Never use setTimeout (fn, 0) for internal operations

Use the same method to register a micro-task

Micro-tasks are for internal operation only

Do not interfere with the developer hook running time

Rules 1 and 2

Data reflection and DOM operations are performed in the order of operations. In this way, as long as they are not mixed, their execution can be well delayed. Mixed execution may cause inexplicable problems.

SetTimeout (fn, 0) behavior is completely unpredictable. Using different methods to register a microtask can also lead to confusion. For example, in the following example, microtask2 does not run correctly before microtask1.

Promise.resolve().then().then(microtask1)   Promise.resolve().then(microtask2)

It is very important to separate the developer's code execution and internal operation time window. Mixing these two behaviors can lead to unpredictable events and requires developers to understand the internal framework. I think many front-end developers have had similar experiences.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.