Author: TAT. CNT

Introduction:

As a multi-threaded browser technology, Web Worker has become an optional solution to ease page lag and improve application performance in the context of increasingly rich page content and increasingly complex functions. But her face, hidden behind the edge of the popular science articles and inscrutable compatibility; JS single thread interview questions back such as flow of front-end engineers, multi-threaded development has a natural strangeness.

Web Worker literature Review

As a multi-threaded browser technology, Web Worker has become an optional solution to ease page lag and improve application performance in the context of increasingly rich page content and increasingly complex functions.

But her face, hidden behind the edge of the popular science articles and inscrutable compatibility; JS single thread interview questions back such as flow of front-end engineers, multi-threaded development has a natural strangeness.

⇈photo

background

Literature review

Literature Review is a common concept in the field of academic research, which should be remembered by those who have written their graduation thesis. It introduces the reader to detailed information, developments, developments, prospects and comments on the subject.

Recently, the author paid attention to Web Worker and landed on a large complex front-end project. Alloy Worker communication framework is open source, and I am writing a practice summary article. During this period, I consulted relevant materials (50+ articles, 10+ technical speeches) and wrote this review article independently.

The main content

  • Development history of Worker
  • Main thread and multithreading
  • Worker Application Scenarios
  • Syntax and runtime environment
  • Worker communication speed
  • Browser compatibility
  • Debugging tool Usage
  • Community kit
  • Review of Industry practice
  • Practice suggestion and summary

The development history

Introduction to the

Students at the front end should be familiar with Web workers, and they should have read relevant articles on the community even if they have not practiced them. In terms of introduction and use, the official document is MDN’s Web Workers API. The expression of Web Worker is as follows:

Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application.

As shown in the figure below, Web Workers implement the ability to run JS in multiple threads. Page update requires two things in Serial; With Worker, two things can be done in Parallel.

⇈photo

It can be intuitively associated: parallelism may improve execution efficiency; Running task splitting reduces page lag. This discussion will continue in the application scenarios section below.

The technical specification

Web Worker belongs to HTML specification, and the specification document can be found in Web Workers Working Draft. Interested students can read it. And it’s not a very new technology, as the chart below shows: a draft was proposed in 2009.

⇈photo

First implemented in FireFox3.5 in the same year, it can be used in using web workers: See early practice in Working Smarter, Not Harder. Internet Explorer 10, released in 2012, also implemented Web workers, marking full support on major browsers. The Web Worker ability test of IE10 is shown below:

⇈photo

Developers may have compatibility concerns when pre-researching Worker solutions. The widespread existence of such concerns is mainly due to less technical practices of workers in the industry and inactive community promotion. From the perspective of development history alone, Worker has been widely available since 2012. This will be discussed later in the compatibility section.

DedicatedWorker and SharedWorker

Web Worker specification includes: DedicatedWorker and SharedWorker; Service workers are not covered by the specification and will not be covered in this article.

⇈photo

DedicatedWorker, as shown above, is a Worker for short. Threads can only be tied and communicated with a single Render Process and cannot be shared with multiple tabs. DedicatedWorker is the first implemented and most widely supported Web Worker capability.

SharedWorker can access the same Worker instance in multiple browser tabs, realizing multi-tab data sharing and webSocket connection sharing. It looks nice, but Safari dropped SharedWorker support due to webKit engine technical reasons. As shown below, it was only briefly supported in Safari 5~6.

⇈photo

The community is also debating whether to continue to support SharedWorker; You are advised to find a solution for multi-tab resource sharing on the Service Worker.

In contrast, dedicatedworkers have greater compatibility and more business landing practices, and the workers discussed later in this article refer specifically to dedicatedworkers.

Main thread and multithreading

Browsers typically open multiple pages (multiple tabs). Modern browsers use a separate Render Process for each page to improve performance and stability, as well as operating system-level memory isolation.

⇈photo

Main Thread

Within a page, content rendering and user interaction are primarily managed by the main thread in the Render Process. Each Frame rendered by the main thread, as shown below, contains five steps: JavaScript → Style → Layout → Paint → Composite. If the JS execution changes the DOM, it may also pause the JS, insert and execute the Style and Layout.

⇈photo

The JS single thread and Event Loop, as we know them, are part of the main thread. JS single-threaded execution avoids complex scenarios (such as races and deadlocks) in multithreaded development. But the main problem with single threading is that it can block user interaction and page rendering when the main thread takes too long to execute the same JS step (about 16ms is the ideal frame interval for browsers).

⇈photo

As shown in the figure above, the page cannot be updated or respond to user input/click/scroll when a long task is executed. If you are stuck for too long, the browser may throw a message indicating that you are stuck. As shown in the figure below.

  • Chrome81

  • IE11

multithreading

Web workers create threads at the operating system level.

The Worker interface spawns real OS-level threads. — MDN

JS multithreading, is independent of the main thread JS runtime environment. As shown in the figure below: Worker threads have independent memory space, Message Queue, Event Loop, Call Stack, etc. Threads communicate with each other through postMessage.

Multiple threads can run JS concurrently. If you’re familiar with asynchronous programming, you might say setTimeout/promise. all is concurrency.

“Concurrent” in a single JS thread is a Concurrent. As shown in the figure below, there is only one function call stack at runtime. Context Switch of different tasks is realized through Event Loop. These tasks use the BOM API to call up other threads to work on the master thread, but the callback code logic is still run serially by JS.

Web Worker is a JAVASCRIPT multi-threaded running technology, specifically Parallel. Parallel has multiple function call stacks, each of which can run tasks independently of each other.

Application scenarios

After discussing mainthread and multithreading, we can better understand the application scenarios of Worker multithreading:

  • Can reduce the main thread lag.
  • Performance improvements are possible.

Reduce the caton

According to RAIL, the User-aware performance model proposed by the Chrome team, synchronous JS execution time should not be too long. In terms of quantification, the recommended value is less than 16ms when playing animation, less than 100ms when responding to user operations, and less than 1000ms when the page is opened.

Logical asynchronization

The main way to reduce main thread lag is asynchronous execution. For example, when playing an animation, split the synchronization task into multiple sub-tasks smaller than 16ms, and then execute one sub-task as scheduled with requestAnimationFrame before each frame of the page until all sub-tasks are completed.

⇈photo

Asynchronous solutions that split synchronous logic work for most scenarios, but are not a silver bullet. There are several problems:

  • Not all JS logic is separable. Such as array sorting, recursive tree search, image processing algorithm, etc., the implementation of the need to maintain the current state, and call nonlinear, can not be easily split into subtasks.

  • Separable logic is difficult to control the granularity. As shown in the figure below, the split sub-task can be controlled within 16ms on the high-performance machine (iphoneX), but the user-perceived time of deadline 16ms on the low-performance machine (iphone6) has exceeded the deadline. The time will not change with the difference of the machine in the user’s hand. Google recommends reducing it to 3-4ms.

⇈photo

  • Split subtasks are not stable. To split synchronous JS logic, atomic logic needs to be found according to business scenarios, and atomic logic will follow business changes, and atomic logic needs to be reviewed every time business changes.

Worker works in one step

Worker’s multi-threading ability enables the splitting of synchronous JS tasks in one step: asynchronize the whole synchronous JS task from a macro perspective. You don’t have to hunt for atomic logic anymore, and asynchronous logic is simpler and maintainable by design.

This gives us more room to imagine. As shown in the figure below, within the main thread rendering cycle of the browser, JS running tasks (Jank jobs) that may block page rendering are transferred to the Worker thread, thus reducing the burden of the main thread, shortening the rendering interval and reducing page lag.

Performance improvement

Worker Multi-threading does not directly improve computing performance, but depends on the number of CPU cores and threading strategies.

Multithreading and CPU cores

Single Core and Multi Core cpus seem a bit far from the front end. However, when using multithreading on a page, the number of cores affects the thread creation strategy.

Processes are the basic unit of operating system resource allocation and threads are the basic unit of operating system CPU scheduling. Operating systems have complex policies for allocating CPU computing resources that threads can occupy. As shown below:

  • Single-core multithreading executes alternately through time slices.
  • Multi-core multi-threading can be truly parallel in different cores.

Worker Thread Policy

The running time of the same task on one device is the same in all threads. As shown in the figure below: We give the main thread JS task to the newly created Worker thread, the task will not run faster on the Worker thread than the original main thread, and the cost of thread creation and communication may make the render interval longer.

⇈photo

On a single-core machine, computing resources are internal volumes, and a new Worker thread does not get more computing resources for a page. On a multi-core machine, both the newly created Worker thread and the main thread can perform operations, and the total computing resources of the page increase. However, for a single task, the running time on which thread is the same.

The real performance boost is multi-core, multi-threaded concurrency.

For example, multiple synchronization tasks without dependencies can only be executed in serial on a single thread, but can be executed in parallel in multi-core and multi-threading. As shown in the image processing demo of Alloy worker in the following figure, 6 worker threads were created when running on iMac, and the total image processing time was about 2000ms faster than the serial processing of the main thread.

It’s worth noting that the number of cores on mobile devices is limited. The A13 chip in the latest iPhone Max Pro, which boasts six cores, also has only two high-performance cores (2.61 GIGABytes) and four low-frequency, energy-efficient cores (0.58 gigabytes). Therefore, it is recommended to distinguish scenarios and devices when creating multiple Worker threads.

Let’s give the main thread back to the UI

Worker’s application scenario essentially strips logic from the main thread and lets the main thread focus on UI rendering. This architectural design is not unique to Web technology.

In native Android and iOS development, the main thread is responsible for the UI; Front end area popular small program, implementation principle is the complete separation of rendering and logic.

It should be.

Worker API

Communication API

As shown in the Worker communication flow above, the Worker communication API is very simple. For a simple Chinese tutorial, please refer to the Web Worker tutorial. See the official documentation for details.

The example code for two-way communication is shown in the figure below. Two-way communication requires only 7 lines of code.

The main process is:

  1. Main thread callnew Worker(url)Create Worker instance,urlIs the Worker JS resource URL.
  2. Main thread callpostMessagesendhelloIn theonmesssageTo listen for Worker thread messages.
  3. Worker thread inonmessageReceived the message from the main threadhello; throughpostMessagereplyworld.
  4. The main thread receives Worker’s message in the message callbackworldInformation.

PostMessage creates a MessageEvent on the receiving thread, adds the data passed to event.data, and fires the event. The MessageEvent callback enters the Message Queue as the macro task to be executed. So messages sent sequentially by postMessage are executed sequentially by the receiving thread. Moreover, we do not need to worry about the loss of postMessage information in the process of instantiating Worker, which has already been dealt with by the internal mechanism of Worker.

Although the communication API of Worker event-driven (postMessage/ onMessage) is simple, communication needs to wait for Response (similar to Request and Response of HTTP Request) in most scenarios, and multiple communications of the same type need to match their respective responses. So business usage typically encapsulates the native API, such as as a Promise call. This is one of the reasons why I developed Alloy Worker.

Runtime environment

In Worker thread running in JS, creates independently of the main thread of JS running environment, called DedicatedWorkerGlobalScope. Developers need to pay attention to the similarities and differences between the Worker environment and the main thread environment, as well as the differences between workers on different browsers.

Similarities and differences between Worker environment and main thread environment

Worker is a thread without UI and cannot call UI-related DOM/BOM API. Refer to MDN functions and classes available to workers for specific APIS supported by Worker.

⇈photo

The figure above shows the similarities and differences between Worker threads and the main thread. The similarities between Worker’s running environment and the main thread mainly include:

  • Contains the full JS runtime with support for language syntax and built-in objects defined by the ECMAScript specification.
  • Support XmlHttpRequest, can independently send network requests and background interaction.
  • Contains a read-only Location, pointing to the script URL executed by the Worker thread, through which parameters can be passed to the Worker environment.
  • containsRead-only NavigatorIs used to obtain browser information, for example, passNavigator.userAgentIdentify the browser.
  • Supports setTimeout/setInterval timers, which can be used to implement asynchronous logic.
  • Support WebSocket for network I/O; IndexedDB is supported for file I/O.

From the common point of view, Worker threads are actually very powerful. In addition to using independent threads to perform heavy logic, their network I/O and file I/O capabilities bring a lot of imagination to business and technical solutions.

On the other hand, the differences between the running environment of Worker threads and the main thread are as follows:

  • Worker threads have no DOM API and cannot create and manipulate DOM; You can’t access the main thread’s DOM Element.
  • The memory between Worker thread and main thread is independent, and Worker thread cannot access global variables (window, document, etc.) and JS functions on the page.
  • Worker threads cannot call UI-related BOM apis such as Alert () or Confirm ().
  • Worker threads are controlled by the main thread, which can create and destroy workers.
  • The Worker thread can passself.closeSelf-destruct.

From the point of difference, Worker threads cannot touch the UI and are controlled by the main thread, which is suitable for working silently.

Differences of workers in different browsers

Different browsers implement different Worker specifications, comparing the main thread, and some API functions are incomplete, such as:

  • AJAX requests sent by IE10 have no referer and may be rejected by the backend server.
  • The character encoding/Buffer implementation on Edge18 is problematic.

Fortunately, there aren’t many of them. Problems can be found at run time through error monitoring, located, and fixed (polyfill).

On the other hand, some newly added HTML specification apis are only implemented in newer browsers, but not in the Worker operating environment or even the main thread. Therefore, it is necessary to judge and be compatible when using Worker.

Multithreaded isomorphic code

Worker threads do not support DOM, much like Node.js. In node.js, we often encounter errors caused by calling BOM/DOM API when doing SSR with the front and back end isomorphism. As shown below:

When developing Worker front-end projects or migrating existing business codes to workers, the proportion of homogeneous codes may be very high and it is easy to adjust to BOM/DOM API. The code logic can be distinguished by building variables, or the thread can be dynamically determined at runtime, so that the homogeneous code can run in different thread environments.

Speed of communication

Worker Multithreading although it realizes the parallel running of JS tasks, it also brings extra communication overhead. As shown in the figure below, there is A time difference between thread A calling postMessage to send data and thread B onMessage receiving data. This time difference is called communication consumption.

⇈photo

Improved performance = parallel improved performance – Performance consumed by communication. In the case of fixed computational power of threads, to improve performance through multithreading, communication consumption needs to be reduced as much as possible.

In addition, the main thread postMessage will run in the same step with the main thread, and the occupied time depends on the data transmission mode and data size. In order to avoid the main thread lag caused by multi-thread communication, it is necessary to select an appropriate transmission mode and control the data transmission scale within each rendering cycle.

Data transmission mode

Let’s start by talking about how the main thread and Worker thread transfer data. According to the computer process model, the main thread and the Worker thread belong to the same process and can access and manipulate the memory space of the process. However, in order to reduce the logical complexity of multi-thread concurrency, some transfer modes directly isolate the memory between threads, which is equivalent to adding a lock by default.

There are three communication modes: Structured Clone, Transfer Memory, and Shared Array Buffer.

Structured Clone

Structured Clone is the default communication mode for postMessage. As shown in the figure below, copy A copy of thread A’s JS Object memory to thread B. Thread B can obtain and manipulate the newly copied memory.

Structured Clone is a simple and effective way to isolate different thread memory and avoid conflicts. And the transmitted Object data structure is very flexible. However, during the replication process, thread A and thread B should synchronously execute Object Serialization and Object Deserialization. If an Object is too large, it consumes a lot of thread time.

Transfer Memory

Transfer the Memory means Transfer of Memory, it does not require Serialization/Deserialization, threads can greatly reduce transmission process takes time. As shown in the figure below, thread A transfers ownership and operation of the specified memory to thread B, but thread A can no longer access the memory after the transfer.

Transfer Memory to lose control in exchange for efficient Transfer, through Memory exclusivity to multi-thread concurrency lock. But only regular Raw Binary data such as an ArrayBuffer can be transferred. Suitable for matrix data such as RGB images. It is also practical to consider the computational cost of generating binary data from JS Objects.

Shared Array Buffers

A Shared Array Buffer is Shared memory. Thread A and thread B can access and manipulate the same memory space at the same time. The data is shared, so there’s nothing to transfer.

However, Race Conditions can occur when multiple parallel threads share memory. Unlike the first two transport methods, which lock by default, Shared Array Buffers leave the problem to the developer, who can use Atomics to maintain the Shared memory. As a newer transfer method, browser compatibility can be expected, currently only Supported by Chrome 68+.

Summary of transmission mode

  • A fully browser-compatible Structured Clone is a good choice, but the size of the data transfer is important, as discussed below.
  • The compatibility of Transfer Memory is also good (IE11+), but the limitation of data exclusivity and data type makes it an optimal solution for specific scenarios rather than a general solution.
  • The current poor compatibility of Shared Array Buffers and the development cost of thread locks suggest looking in the dark.

JSON. Stringify faster?

When using Structured Clone to transfer data, a shadow hangs over us: Should we run json.stringify on the data before postMessage?

High-performance Web Worker Messages of 2016 was tested, and it was. In 2019, Surma conducted a new test: as shown below, direct postMessage generally takes less time to transmit than json.stringify for the same data size on the horizontal axis.

⇈photo

Json.stringify. No longer needed in 2020 The first is the Structured Clone built-in serialize/ Deserialize performance is higher than json. stringify. Second, json.stringify is only suitable for serializing basic data types, while Structured Clone supports copying other built-in data types (Map, Blob, RegExp, etc., although most applications use only basic data types).

Data transmission scale

Let’s talk about Structured Clone data transfer scale. The serialize/deserialize execution time of Structured Clone is mainly affected by the complexity of data objects, which is understandable because serialize/deserialize traverses objects in at least some way. The complexity of a data object itself is difficult to measure, so serialized data size (SIZE) can be used as a reference.

How Fast Are Web Workers in 2015 was tested on medium performance phones: The Communication rate of the postMessage send array was 80KB/ms, equivalent to sending 1300KB in an ideal rendering cycle (16ms).

In 2019, Surma conducted a further study of postMessage’s data transmission capabilities, as detailed in Is postMessage Slow. The test results on a high performance machine (macbook) are shown below:

⇈photo

Among them:

  • Test data is nested in layers 1 to 6 (payload depth, ordinate in the figure), and objects with 1 to 6 (payload breadth, ordinate in the figure) child nodes of each layer. The data size ranges from 10B to 10MB.
  • On the macbook, 10MB of data takes 47ms to transfer, and 1MB of data can be transferred in 16ms.

The test results on a low performance machine (NOkiA2) are shown below:

⇈photo

Among them:

  • It takes 638ms to transfer 10MB of data on NokiA2, and 10KB of data can be transferred within 16ms.
  • There is a more than 10-fold transmission efficiency gap between high performance machines and low performance machines.

No matter how the machine performance is on the user side, users have the same experience on fluency: old friends of the front-end classmate 16ms and 100ms. Surma takes into account postMessage on low performance models, which is easy to cause the main thread to be stuck, and proposes the following data transmission scale suggestions:

  • If the JS code does not include animation rendering (100ms), the data transfer size should be kept under 100KB;
  • If the JS code includes animation rendering (16ms), the data transfer size should be kept under 10KB.

The author believes that Surma’s proposal is conservative and the transmission scale can be larger.

In summary, there are no best practices for data transfer scaling. It is to fully understand the transmission cost of Worker postMessage, and evaluate and control the data scale according to business scenarios in practical applications.

compatibility

Compatibility is an important issue in the evaluation of front-end technical solutions. This is especially true for Web workers, because of the multi-threading ability of workers, either business scenarios are completely useless; Or they are heavily dependent on basic abilities.

Compatibility is good

From the previous Worker history and compatibility view, the compatibility of workers should be good.

As you can see above, Worker has been supported by major browsers for a few years.

PC:

  • IE10(2012/09)
  • Chrome4(2010/01)
  • Safari4(2009)
  • Firefox3.5 (2009).

Mobile client:

  • iOS5(2012)
  • Android4.4 (2013).

Usability metrics

Using workers is not a one-shot deal. We don’t just focus on the presence or absence of browser Worker capabilities; Also pay attention to whether Worker capabilities are fully available. To this end, the author designed the following indicators to evaluate Worker availability:

  • Whether you have Worker ability: Indicates whether the browser is availablewindow.WorkerTo judge.
  • Can instantiate the Worker: Through monitoringnew Worker()To determine whether an error is reported.
  • Can you communicate across threads: Verify by testing two-way communication and setting a timeout.
  • First communication time: the time between the page loading of Worker script and the completion of the first communication. This indicator is related to the loading time of JS resources and the execution time of synchronization logic.

statistics

With usability metrics, you can give quantified compatibility statistics. What you’ll see is the only quantitative data available on the open community, the results of a large front-end project (100 million MAUs) for 2019-2020 (By AlloyTeam Alloy – Worker).

Among them:

  • More than 99.91% of terminals with Worker capability.
  • 99.58% of terminals with fully available Worker capability.
  • And 99.58% to 99.91% of the gap is largely due to communication timeouts.

summary

It can be seen that the current browser already supports Worker well. As long as 0.09% browsers that do not support it do a rollback strategy (such as displaying a tip), Worker can be applied to the front-end business with confidence.

Debugging tool Usage

Front-end engineers are unfamiliar with the Worker multi-threaded development mode, so is the debugging of Worker code in development. This chapter uses Chrome and Internet Explorer 10 as an example to describe how to use the debugging tool. Sample page for alloyteam. Making. IO/alloy – worke… , interested students can open the page to debug a.

Chrome debugging

Chrome has improved support for Worker code debugging, and the debugging mode in the developer panel is consistent with the main thread JS.

The Console debug

On the Console Panel, you can view all the JS running environments on the page and switch the current debugging environment by using the drop-down box. As shown in the figure below, where TOP represents the JS running environment of the main thread and alloyWorker–test represents the JS running environment of the Worker thread.

After switching to alloyWorker–test, debug code can be executed in the Worker runtime environment. As shown in the figure below, the Worker environment of the global object to self, type of DedicatedWorkerGlobalScope.

Breakpoint debugging

Worker breakpoints are debugged the same way as the main thread: the source code where the Debugger identifier is added is used as a breakpoint. When viewing the source code of the page in Sources Panel, as shown below, the left Panel shows the alloy-worker.js resource of Worker thread; When the Worker thread breakpoint is run, the Threads on the right indicates that the runtime environment is the Worker thread named alloyWorker–test.

Performance tuning

Use the recording function of the Performance Panel. As shown in the red box below, Performance also records the running status of Worker threads.

Viewing Memory Usage

The usage scenario of Worker is biased towards data and calculation. Timely review of the memory occupation of Worker threads during development to avoid memory leakage interfering with the whole Render Process. As shown in the figure below, the alloyworker-test thread occupies 1.2m of Memory in the Memory Panel.

Ie 10 debugging

In extreme cases, we need to locate code compatibility issues in older browsers like IE10. Fortunately, IE10 also supports Worker source debugging. You can refer to the Microsoft official documentation for detailed steps:

  • According to theF12Open the debugging tool, in Script Panel, the source code of Worker thread is not visible at the beginning, clickStart debugging, you can see the Worker threadalloy-worker.jsThe source code.

  • The Worker source can be debugged by breaking a breakpoint.

Data flow debugging

Communicating data flows across threads is a complex part of development and debugging. Because there may be multiple Worker instances on the page; The Worker instance has different data types (payload); And the same type of communication may be initiated many times.

When debugging data flow through onMessage callback log, it is recommended to add the current Worker instance name, communication type, communication load and other information. Take the log in alloy-worker debug mode as an example:

As shown above:

  • Each line contains: thread name, [timestamp, session Id, transaction type, transaction load].
  • The green down arrow (缟) indicates the information received by the Worker thread.
  • The pink upward arrow, As Siphiwe Siphiwe, indicates a message sent by the Worker thread.

Community kit

Modern front-end development uses the modular way to organize the code, using the Web Worker to build the module source code into a single resource (worker.js). On the other hand, Worker’s native postMessage/ onMessage communication API is not easy to use, and communication encapsulation and data convention are often required in complex scenarios.

Therefore, the open source community provides companion tools that address two key issues:

  • Worker code packaging. Package modular files into a single JS resource.
  • Worker communication encapsulation. Encapsulate multithreaded communication, simplify calls; Or the data format of the agreed communication load.

Here are some of the main tools of the community. Star count time is 2020.06.

worker-loader(1.1 k star)

The official Worker loader of Webpack is responsible for packaging Worker source code into a single chunk. Chunks can be standalone files or inline Blob resources. Output the function embedded with new Worker(), which instantiates the Worker by calling it.

However, the worker-loader does not provide the url of worker resources after construction, making it difficult for upper-layer services to customize. A related issue has been discussed; Worker-loader also does no extra processing for communication modes.

worker-plugin(1.6 k star)

Webpack build plugin provided by GoogleChromeLabs.

As a plugin, support Worker and SharedWorker construction. No need to invade the source code, by parsing the new Worker and new SharedWorker syntax in the source code, automatically complete the construction of JS resources package. Loader functionality is also provided: package resources and return resource urls, which has advantages over worker-loader.

comlink(6.2 k star)

Also from GoogleChromeLabs team, developed by Surma. Based on ES6 Proxy capability, postMessage is encapsulated with Remote Procedure Call (RPC), and cross-thread function calls are encapsulated as Promise calls.

However, it does not involve Worker resource construction packaging and requires other supporting tools. In addition, the Proxy needs polyfill in some browsers, but the degree of polyfill is uncertain.

workerize-loader(1.7 k star)

At present, the community is relatively complete and has good compatibility.

Similar to worker-loader + comlink combination. But not based on Proxy, but in the build according to the source code AST extract the calling function name, in another thread built-in function of the same name; Encapsulate cross-thread functions as RPC calls.

Another project associated with workerize-Loader is Workerize (3.8K star). Support handwritten text function, internal encapsulation as RPC; But the handwritten text function is not very practical.

userWorker(1.8 k star)

A very interesting project to encapsulate Worker as React Hook. The basic principle is to process the function passed into the Hook as a BlobUrl to instantiate the Worker. Because the function is converted to BlobUrl as a string, the function cannot have external dependencies, nor can other functions be called from the function body.

More suitable for one-time use of pure function, function complexity is limited.

Other items for reference

  • Promise – 0.4 k star worker.
  • Greenlet 4.3 k star.
  • Workly 1.7 k star.
  • Threads.js 1.1K star, supports NodeJS.

Existing tool defects

Existing community tools have solved some difficulties in the application of Worker technology, but there are still some shortcomings:

  • Web workers are not 100% available, and community tools do not provide a rollback solution.
  • For large-scale scenarios, there is no good way to structure and build code.
  • Some tools lack strong constraints on communication data conventions, which can lead to unexpected errors at run time.
  • There is less support for TypeScript source code, and there are obstacles to functional hints in the editor.

The above deficiencies prompted the author to open source the Alloy worker, a transaction-oriented highly available Web worker communication framework. For a more detailed tool discussion, refer to the industry solution comparison of Alloy -worker.

Review of Industry practice

Practice scenario

As a multi-threaded browser technology, Web Worker has become an optional solution to ease page lag and improve application performance in the context of increasingly rich page content and increasingly complex functions.

In 2010,

In 2010, The Article The Basics of Web Workers lists The following scenarios for Workers:

Application scenarios in 2010 mainly involve data processing, text processing, image/video processing, network processing and so on.

The present

In 2018, the article Parallel Programming in JavaScript using Web Workers lists the available scenarios of Workers as follows:

It can be seen that in recent years, the scene of Worker is richer than in 2010, expanding to Canvas Drawing (off-screen rendering), Virtual DOM Diffing (front-end framework), indexedDB(local storage), Webassembly(compiled language aspects), etc.

In general, workers are useful for page computing/background tasks. Next, the author will share some specific cases, and brief analysis.

Heavy computing scenario

Graphite form for Web Worker application

2017 article, very good practice. Online table sorting is a CPU-intensive scenario, and it is difficult to eliminate page lag even after complex tasks are atomized and asynchronized. After migrating the sorting to the Worker, the Scripting time for 2500 rows of data was reduced from 9984ms to 3650ms.

Making TensorflowJS work faster with WebWorkers

The 2020 article uses vivid illustrations to illustrate frame drops caused by tf.js running on the main thread. Taking action detection of real-time camera video as an example, the video animation is realized by Worker without lag (within 16ms). Motion detection takes 50ms, but does not block the video, and is about 15FPS.

Tencent document Excel function practice

The author wrote an article, recently released.

Front-end framework scenario

neo — webworkers driven UI framework

Open source Worker driver front-end framework in 2019. It divides the front-end framework into three workers: App Worker, Data Worker and Vdom Worker. The main thread only needs to maintain the DOM and proxy DOM events in the App Worker; The Data Worker is responsible for making background requests and hosting the Data store; The Vdom Worker converts the template string into a virtual node and generates increments for each change to update it.

worker-dom

Part of Google AMP project. DOM operation API and DOM event monitoring are implemented in Worker, and DOM changes are applied to the real DOM of main thread. The official Demo introduces React and render directly into the Worker!

Angular

The Angular8 CLI supports creating Web Worker directives and migrating CPU-intensive computations to workers; But Angular itself does not run in workers. Angular. IO also uses workers to improve search performance.

Data Flow Scenario

Off-main-thread React Redux with Performance

The 2019 article. Migrate the action part of Redux to Worker and open source the project redux-in-worker. Benchmark Worker Redux: Not too different from the main thread (but not stuck).

Off Main Thread Architecture with Vuex

The 2019 article. Simple analysis of UI thread overload and Worker concurrency. Decompose Vue data flow framework Vuex and find that action can contain asynchronous operation, which is suitable for migration to Worker. The implementation of action encapsulation function and prime number generation demo.

Visual scene

PROXX

PROXX is an online minesweeper game developed by GoogleChromeLabs, whose Worker ability is provided by Comlink developed by Surma. Surma specially develops Worker version and non-worker version: there is little difference between them on high-performance models Pixel3 and MacBook; However, on the low-performance model Nokia2, the clicking action of the non-worker version takes 6.6s, and the clicking callback of the Worker version takes 48ms.

Image Style manipulation

The 2013 article. Use Worker to process images into retro tones. On the current advanced 12-core machine, the processing time is reduced from 150ms to 80ms after using 4 Worker threads; On the dual-core machines of that year, the processing time was reduced from 900ms to 500ms.

OpenCV directly in the browser (webassembly + webworker)

2020 article. Based on OpenCV project, the project is compiled into WebAssembly, and opencv.js is dynamically loaded in Worker to realize the gray processing of images.

A large project

OffscreenCanvas

Chrome69+ support, can transfer the drawing right of main thread Canvas to OffscreenCanvas of Worker thread, rendering directly to the page after drawing in Worker; It also supports creating a new Canvas in the Worker to draw graphics and transferring them to the main thread for display through imagebitmap.

hls.js

HLS is HTTP real-time streaming media library based on JS. Worker is used to demuxer stream data and Transfer Memory is used to minimize transmission consumption.

pdf.js

Determine whether the browser supports the Worker ability, and put the PDF file parsing in the Worker thread if it has the Worker ability.

Related video/PPT sharing

Web Workers — I like the way you work it

In 2016, the Project of Pokedex.org updated Virtual DOM in Web Worker, significantly improving the rendering efficiency under fast scrolling.

The main thread is overworked & underpaid

Chrome Dev Summit 2019, very exciting sharing, from Google engineer Surma. The presentation pointed out that the main page is overloaded, especially in developing countries with a large number of low-performance devices. Running on Worker slower but not dropping frames is better than running on main thread faster but stuttering.

Is postMessage slow? – HTTP 203

Also from Surma’s technical interview. The focus is on postMessage performance. In the part of communication speed, Surma’s research is widely cited in this paper.

Surma has written several articles in the Worker space and opened source Comlink.

Web Worker practices on front-end projects

In 2019, he was a former colleague of the author who worked closely on Worker practice. The presentation discusses Web Worker usage scenarios; Worker’s attention points and code transformation to adapt to multi-threading; Problems and solutions encountered in practice.

Weaving Webs of Workers

2019, from an engineer at Netflix. Four major problems encountered in using Web workers are summarized and solved one by one by introducing several supporting tools in the community.

Web Workers: A graphical introduction

The 2018 presentation on multithreading and postMessage data passing section is beautiful. Put the Web Worker application in the Web piano player he developed.

What the heack is the event Loop anyway

In 2014, the main thread Event Loop was introduced with a vivid legend.

Practical advice

As mentioned above, there are many application practices of Worker technology in the community. If your business also needs to use Worker, here are some practical suggestions.

Maybe you don’t need a Worker

Using workers has costs: Worker threads take up system resources; Homogeneous code and asynchronous communication increase maintenance costs; Multithreaded programming challenges the thinking of the front end.

David’s article points out that there are not many scenarios that desperately need workers, and developers need to consider the cost-benefit ratio. Simply put, if a page action takes time and you don’t want users to notice, use Worker.

Workers should be resident threads

Although the Worker specification provides an TERMINATE API to terminate Worker threads, frequent new threads consume resources. In most scenarios, Worker threads should be used as resident threads. Reuse of resident threads is preferred in development.

Controls the number of Worker threads

This is also understandable. When Worker threads strive for CPU computing resources, too many threads cannot linearly improve performance due to the limited number of CPU cores, and each Worker thread will consume about 1M inherent memory.

Understand multithreaded development

Multithreaded development thinking and way, is a relatively big topic. Developers need to control the communication scale between threads, reduce the dependence of data and state between threads, and try to understand and control Worker threads.

Looking forward to

This paper attempts to sort out the current status and development of Web Worker technology in 2020.

From the current situation, Worker is widely available, and there are practices in business and framework in the industry, but there are still deficiencies in supporting tools.

From the perspective of development trend, Worker’s multi-threading ability is expected to become the standard configuration of complex front-end projects, which will benefit from reducing UI thread lag and squeezing computer performance. However, there are few domestic practices at present. On the one hand, the complexity of business has not been touched. On the other hand, the community lacks science popularization and practice sharing.

Front-end multi-threaded development is the time. The Worker communication framework maintained by the author, Alloy-Worker, has been open source, and the paper of landing a large front-end project is on the way. Chicken soup and spoon, add Lao Gan Ma, really delicious!

References

  • alloy-worker

Github.com/AlloyWorker…

  • Web Workers API

Developer.mozilla.org/en-US/docs/…

  • Remove shared workers?

whatwg/html#315

  • Using web Workers

Developer.mozilla.org/en-US/docs/…

  • Web Workers Working Draft

www.w3.org/TR/workers/

  • Using Web Workers: Working Smarter, Not Harder (Practice on Firefox 2009)

Hacks.mozilla.org/2009/07/wor…

  • Is postMessage slow? (Data communication experiment design)

Dassur. Ma/things/is – p…

  • Another look at Web Workers (discussing asynchronous programming)

www.ithome.com.tw/voice/13299…

  • The Basics of Web Workers (2010, talking about error handling and security restrictions)

www.html5rocks.com/en/tutorial…

  • Blink Workers (Introduction to the implementation of Blink Framework Worker)

Docs.google.com/document/d/…

  • Should you be using Web Workers

medium.com/@david.gilb…

  • How JavaScript works

Blog.sessionstack.com/how-javascr…

  • Parallel programming in JavaScript using Web Workers

Itnext. IO/achieving – p…

  • So you want to use a Web Worker

Povioremote.com/blog/so-you…

EOF

AlloyTeam welcomes excellent friends to join. Resume submission: [email protected] For details, please click Tencent AlloyTeam to recruit Web front-end engineers.