Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between Javascript async functions and Web workers?

Threading-wise, what's the difference between web workers and functions declared as

async function xxx() { } 

?

I am aware web workers are executed on separate threads, but what about async functions? Are such functions threaded in the same way as a function executed through setInterval is, or are they subject to yet another different kind of threading?

like image 320
resle Avatar asked Mar 04 '18 07:03

resle


People also ask

What is the difference between service worker and web worker?

Unlike web workers, service workers allow you to intercept network requests (via the fetch event) and to listen for Push API events in the background (via the push event). A page can spawn multiple web workers, but a single service worker controls all the active tabs under the scope it was registered with.

What is a web worker in JavaScript?

A web worker is a JavaScript that runs in the background, independently of other scripts, without affecting the performance of the page. You can continue to do whatever you want: clicking, selecting things, etc., while the web worker runs in the background.

Is promise a web worker?

Deferred/promise are constructs to assign a reference to a result not yet available, and to organize code that runs once the result becomes available or a failure is returned. Web Workers perform actual work asynchronously (using operating system threads not processes - so they are relatively light weight).

What is difference between async and await in JavaScript?

The async keyword is used to define an asynchronous function, which returns a AsyncFunction object. The await keyword is used to pause async function execution until a Promise is fulfilled, that is resolved or rejected, and to resume execution of the async function after fulfillment.


2 Answers

async functions are just syntactic sugar around Promises and they are wrappers for callbacks.

// v await is just syntactic sugar //                 v Promises are just wrappers //                                         v functions taking callbacks are actually the source for the asynchronous behavior    await new Promise(resolve => setTimeout(resolve));   

Now a callback could be called back immediately by the code, e.g. if you .filter an array, or the engine could store the callback internally somewhere. Then, when a specific event occurs, it executes the callback. One could say that these are asynchronous callbacks, and those are usually the ones we wrap into Promises and await them.

To make sure that two callbacks do not run at the same time (which would make concurrent modifications possible, which causes a lot of trouble) whenever an event occurs the event does not get processed immediately, instead a Job (callback with arguments) gets placed into a Job Queue. Whenever the JavaScript Agent (= thread²) finishes execution of the current job, it looks into that queue for the next job to process¹.

Therefore one could say that an async function is just a way to express a continuous series of jobs.

 async function getPage() {    // the first job starts fetching the webpage    const response = await fetch("https://stackoverflow.com"); // callback gets registered under the hood somewhere, somewhen an event gets triggered    // the second job starts parsing the content    const result = await response.json(); // again, callback and event under the hood    // the third job logs the result    console.log(result); }  // the same series of jobs can also be found here: fetch("https://stackoverflow.com") // first job    .then(response => response.json()) // second job / callback    .then(result => console.log(result)); // third job / callback 

Although two jobs cannot run in parallel on one agent (= thread), the job of one async function might run between the jobs of another. Therefore, two async functions can run concurrently.

Now who does produce these asynchronous events? That depends on what you are awaiting in the async function (or rather: what callback you registered). If it is a timer (setTimeout), an internal timer is set and the JS-thread continues with other jobs until the timer is done and then it executes the callback passed. Some of them, especially in the Node.js environment (fetch, fs.readFile) will start another thread internally. You only hand over some arguments and receive the results when the thread is done (through an event).

To get real parallelism, that is running two jobs at the same time, multiple agents are needed. WebWorkers are exactly that - agents. The code in the WebWorker therefore runs independently (has it's own job queues and executor).

Agents can communicate with each other via events, and you can react to those events with callbacks. For sure you can await actions from another agent too, if you wrap the callbacks into Promises:

const workerDone = new Promise(res => window.onmessage = res);  (async function(){     const result = await workerDone;         //... })(); 

TL;DR:

JS  <---> callbacks / promises <--> internal Thread / Webworker 

¹ There are other terms coined for this behavior, such as event loop / queue and others. The term Job is specified by ECMA262.

² How the engine implements agents is up to the engine, though as one agent may only execute one Job at a time, it very much makes sense to have one thread per agent.

like image 99
Jonas Wilms Avatar answered Sep 29 '22 03:09

Jonas Wilms


In contrast to WebWorkers, async functions are never guaranteed to be executed on a separate thread.

They just don't block the whole thread until their response arrives. You can think of them as being registered as waiting for a result, let other code execute and when their response comes through they get executed; hence the name asynchronous programming.

This is achieved through a message queue, which is a list of messages to be processed. Each message has an associated function which gets called in order to handle the message.

Doing this:

setTimeout(() => {   console.log('foo') }, 1000) 

will simply add the callback function (that logs to the console) to the message queue. When it's 1000ms timer elapses, the message is popped from the message queue and executed.

While the timer is ticking, other code is free to execute. This is what gives the illusion of multithreading.

The setTimeout example above uses callbacks. Promises and async work the same way at a lower level — they piggyback on that message-queue concept, but are just syntactically different.

like image 22
nicholaswmin Avatar answered Sep 29 '22 03:09

nicholaswmin