JavaScript the Fun Part


effective-javascript-2

inside-the-browser-firefox


Today we are going to look at inside a web browser which is Firefox.

All the time we talk about JavaScript, JavaScript and today we see where is this JavaScript.

If you have opened Firefox, closed it completely.

Then open you Terminal.

Then open your Firefox and do not do anything with it. It should have one tab opened.

Processes

On your Terminal type to get all processes related to Firefox

pidof firefox | tr ' ' '\n' | sort -h

// which gives you something like this
4084
5282
5597
5822

The first one 4084 is the parent process id or main process id for Firefox itself.

The second one is the child process id which is the active tab we have.

The other two are also children and are reserved processes.

Parent and Children

We can see them in tree mode of the ps command.

try:

 ps -ocmd,ppid,pid,nlwp,state --forest $(pidof firefox)

// output
CMD                          PPID   PID NLWP S
/usr/lib/firefox/firefox        1  4084   52 S    // parent
 \_ /usr/lib/firefox/firefo  4084  5282   21 S    // active child
 \_ /usr/lib/firefox/firefo  4084  5597   20 S
 \_ /usr/lib/firefox/firefo  4084  5822   19 S

Also those options are:

More info about "state" option:

D    uninterruptible sleep (usually IO)
R    running or runnable (on run queue)
// ours
S    interruptible sleep (waiting for an event to complete)
T    stopped by job control signal
t    stopped by debugger during the tracing
W    paging (not valid since the 2.6.xx kernel)
X    dead (should never be seen)
Z    defunct ("zombie") process, terminated but not reaped by its parent

Threads

For seeing where is JavaScript we have show the threads inside a child process.

Try this command, looking at threads inside 5282 process

ps -T -p 5282

// which gives us this output
  PID  SPID TTY          TIME CMD
 5282  5282 ?        00:00:02 Web Content
 5282  5298 ?        00:00:00 Chrome_~dThread
 5282  5300 ?        00:00:00 JS Watchdog
 5282  5301 ?        00:00:00 JS Helper
 5282  5302 ?        00:00:00 JS Helper
 5282  5303 ?        00:00:00 Socket Thread
 5282  5304 ?        00:00:00 Timer
 5282  5316 ?        00:00:00 DOM File
 5282  5317 ?        00:00:00 Worker Launcher
 5282  5318 ?        00:00:00 PaintThread
 5282  5334 ?        00:00:00 ImgDecoder #1
 5282  5335 ?        00:00:00 ImageIO
 5282  5357 ?        00:00:00 ImageBr~geChild
 5282  5358 ?        00:00:00 RemVidChild
 5282  5359 ?        00:00:00 AudioIPC0
 5282  5360 ?        00:00:00 AudioIPC1
 5282  5367 ?        00:00:00 ProcessHangMon
 5282  5368 ?        00:00:00 ProfilerChild
 5282  5383 ?        00:00:00 HTML5 Parser
 5282  5774 ?        00:00:00 ImgDecoder #2

For us the important stuff here are:

 ...
 5282  5300 ?        00:00:00 JS Watchdog
 5282  5301 ?        00:00:00 JS Helper
 5282  5302 ?        00:00:00 JS Helper
 ...
 5282  5304 ?        00:00:00 Timer
 ...

To better understand these threads I asked a question on Stack-Overflow and there is no answer to it.

What are JS Watchdog, JS Helper, Timer threads inside a web browser's process

So if I could not find the correct answers the explanation will be my best guess!

JS Watchdog

This section maybe wrong, please clarify me!

What I found through searching:

None of these directly explain the role of JS Watchdog thread.

My best guess is that this thread takes care of running long time operation to prevent browser crash.

For example:

In such cases the threads tries to stop that operation!

// sample for too long call stack
(function ff(){ ff() })();

// output on devtools
InternalError: too much recursion

JS Helper

This section maybe wrong, please clarify me!

My best guess about these two JS Helper thread is that they are responsible for main JS code and Asynchronous code.

In face one of them is kind of main thread JS and the other one is the helper thread for running asynchronous events.

We know that in modern JS we have:

The my best guess is that these two threads are for Main Task and Micro Task.

Because I know that Timer functionality in JS is Macro Task.

We will see in code.

// sample
|const log = console.log.bind( console );

log( "start of main task" );

setTimeout(function(){
    log( "this is a Macro Task" );
}, 1000 );
// declare a function 
function f(){
    log( "this is function f()" );
}

// invoke it
f();

log( "end of main task" );

// output
--- start of main task ---
this is function f()
--- end of main task ---
this is a Macro Task

As you can see the Macro Task is done of the Main Tasks are done.

In fact we the JS file is executed the setTimeout() function has asynchronous nature and therefor it is put on a helper thread to be executed after 1000 milliseconds.

So when the main JS thread's tasks are all done, the tasks on Event Queue is executed and here the setTimeout() is on the Event Queue.

How about Micro Tasks?

It is the same as Macro Task, but has higher priority. Like what? Like Promise.

const log = console.log.bind( console );

log( "--- start of main task ---" );

async function  microTask(){
    await null;
    log( "this is a Micro Task" );
}

// registered for later execution
setTimeout(function(){
    log( "this is a Macro Task" );
},0);

// run after setTimeout
// registered for later execution
microTask();

// declare a function 
function f(){
    log( "this is function f()" );
}

// executed right now
f();

log( "--- end of main task ---" );

// output
--- start of main task ---
this is function f()
--- end of main task ---
this is a Micro Task
this is a Macro Task

Timer

This section maybe wrong, please clarify me!

And my best guess for Timer threads is that it takes care of asynchronous operations related to:

if we change our function added for setTimeout to a promise, we will get the same output again.

const log = console.log.bind( console );

log( "--- start of main task ---" );

async function  microTask(){
    await null;
    log( "This is a Micro Task" );
}

setTimeout(async function(){
    await null;
    log( "this is a Macro Task with Promise" );
},0);

// run after setTimeout
microTask();

// declare a function 
function f(){
    log( "this is function f()" );
}

// invoke it
f();

log( "--- end of main task ---" );


// output:
--- start of main task ---
this is function f()
--- end of main task ---
This is a Micro Task
this is a Macro Task with Promise

Because still setTimeout() function has less priority.

How about adding extra operation to a micro task? Can we make it to be executed after a Macro task. No.

// notice the for loop inside the promise
const log = console.log.bind( console );

log( "--- start of main task ---" );

async function  microTask(){
    await null;
    let index = 0;
    log( "index:", index );
    for( ; index < 1000000000; ++index);
    log( "index:", index );
    log( "This is a Micro Task" );
}

setTimeout(async function(){
    await null;
    log( "this is a Macro Task with Promise" );
},0);

// run after setTimeout
microTask();

// declare a function
function f(){
    log( "this is function f()" );
}

// invoke it
f();

log( "--- end of main task ---" );


// output
--- start of main task ---
this is function f()
--- end of main task ---
index: 0
index: 1000000000
This is a Micro Task
this is a Macro Task with Promise

As you can see although we added a long running for loop but setTimeout() function has to wait till finishing the for loop operation.

The two points here are:


Update: Fri Sep 20 2019 15:21:52 GMT+0430 (Iran Daylight Time)