A bloody case caused by a Javascript interview question #selected front-end development JAVASCRIPT

The article was first published in  the Third Frontier Research Institute of szhshp  , please indicate when reprinting

Let’s first look at a few interview questions. The developers of the company have tried to do them, but basically no one can answer them all correctly.

There are many test sites covered, and there are also some difficulties. The questions are very interesting. It is recommended to manually execute them while playing.

Question 1

    for (var i = 0; i <5 ; i++) {
        setTimeout(function(){
            console.log(i)
        ),1000}
    }
    console.log(i)
  • Q: What is the output of this question?
  • A: This question is relatively simple. If you have a little in-depth knowledge of Javascript, you will find that there is a closure in the loop of this question , so the output numbers are exactly the same, and the final output is also exactly the same.
  • Test Site: Closures, (Pseudo) Asynchronous

Question 2

    for ( let i = 0 ; i < 5 ; i++) { //note that var becomes let 
        setTimeout( function () {
             console .log(i)
        },1000)
    }
    console.log(i)
  • Q: What is the output of this question?
  • A: This topic is actually a pit. First of all, the difference between the title and Q1 is that the definition of the variable i is changed to the keyword let. When using let, the variable will be limited to the loop, so the second output will actually report an error. In addition, setTimeout implements (pseudo) asynchrony, and because let controls the variable scope and destroys the closure structure, it will output in normal order.

    About let keyword[^3]

    Use the let statement to declare a variable, the scope of which is restricted to the block in which it is declared. You can assign values to the variables when you declare them or later in your script.
    A variable declared using let cannot be used before its declaration or an error will result..

  • Test Site: Closures, (Pseudo) Asynchronous, Scope

Question 3

The same code for Q1

    for (var i = 0; i <5 ; i++) {  //DO NOT MODIFY
        setTimeout(function(){ //DO NOT MODIFY
            console.log(i)
        },1000)
    }
    console.log(i)  //DO NOT MODIFY
  • Q: Modify the above code (some lines are not allowed to be modified, and can be inserted between codes) to achieve "output a number every second and the order is 0-5"
  • A

    1. First of all, we consider the destruction of the closure structure. There are many ways to destroy the closure. The simplest is to convert the cross-domain variable into a variable within the scope.
    2. Secondly, the processing of the setTimeout event queue is considered

      for (var i = 0; i <5 ; i++) {
       (function(i){
           setTimeout(function(){
               console.log(i)
           },1000*i)    
       })(i)            //Pass i as a parameter to the anonymous function, which destroys cross-domain access within the closure
      }
      setTimeout(function (){
      console.log(i);
      }, 5000 );                //Forcibly put 5 into the output after 5sec
      
  • Test sites: closures, (pseudo) asynchrony, scope, event queue

    Question 4

window.setTimeout(function (){
    console.log(2)
},1);

//Ouput for a long time
for (var i = 0; i < 1000; i++) {
    console.log('');
};

console.log(1)

window.setTimeout(function (){
    console.log(3)
},0);
  • Q: What is the output of this question?
  • A: Some students may remember that setTimeout is a callback function, so no matter how long the delay is, the result is the final output.
  • Test site: (pseudo) asynchronous, event queue

Question 5

This question is actually plagiarized from other places[^2], it just overlaps with the previous test center, so I put it together:

    setTimeout(function(){console.log(4)},0);
    new Promise(function(resolve){
        console.log(1)

        //time consuming ops
        for( var i=0 ; i<10000 ; i++ ){
            i==9999 && resolve();
        }

        console.log(2)
    }).then(function(){
        console.log(5)
    });
    console.log(3);
  • Q: What is the output of this question?
  • A: The output is 12354

    Regarding this output, there are several logics as follows:

    1. 4 is the output of setTimeOut.callback, added to the end of MacroTask,
    2. output 1
    3. Execute Promise.resolve() to put the callback of output 5 into MicroTask (note that this is not MacroTask)
    4. output 2
    5. output 3
    6. The first task of MacroTask is executed
    7. Find out if there are tasks in MicroTask, find that there are, execute, and output 5
    8. Find out if there is a task in the MacroTask, find that there is, execute, output 4
    9. Find out if there are tasks in MicroTask, and find no, you can rest
    10. Find out if there are any tasks in the MacroTask, and find no, you can sleep
    11. Finished

About the event loop/about macrotask and microtask[^1]

Introduction

An event loop (EventLoop) will have an executing task (Task), and this task is from the macrotask queue. In the whatwg specification, queue is the task queue. When the execution of this macrotask ends, all available microtasks will be executed in the same event loop. When the execution of these microtasks ends, microtasks can be added until the execution of the actual microtask queue ends.

how to use

Basically, microtasks are used when we want to handle asynchronous tasks in a synchronous way (for example, we need to execute a task directly after a certain piece of code, like a Promise).

In other cases, use macrotask directly.

The specific implementation of both

  • macrotasks: setTimeout setInterval setImmediate I/O UI渲染
  • microtasks: Promise process.nextTick Object.observe MutationObserver

understand from the specification

Specification: https://html.spec.whatwg.org/multipage/webappapis.html#task-queue

  • An event loop (event loop) will have one or more task queues (task queue) task queue is macrotask queue
  • Each event loop has a microtask queue
  • task queue == macrotask queue != microtask queue
  • A task can be placed in the macrotask queue or in the microtask queue
  • When a task is put into the queue (macro or micro), the task can be executed immediately

Let's review the flow of how the event loop executes a task

When the call stack is empty, start executing in sequence:

  1. Put the oldest task (task A) into the task queue
  2. If task A is null (then the task queue is empty), skip directly to step 6
  3. Set the currently running task to task A
  4. Execute task A (that is, execute the callback function)
  5. Set currently running task to null and remove task A
  6. Execute the microtask queue
    1. Select the earliest task task X in the microtask
    2. If task X is null (the microtask queue is empty), jump directly to g
    3. Set the currently running task to task X
    4. execute task X
    5. Set currently running task to null and remove task X
    6. Select the earliest task in microtask, skip to b
    7. end microtask queue
  7. skip to first step

The above is even a simple event-loop execution model

It can be summed up simply as:

  1. Execute the earliest task in the macrotask queue, then remove it
  2. Execute all available tasks in the microtask queue, then remove
  3. In the next loop, execute the task in the next macrotask (skip to step 2 again)

other

  1. When a task (in the macrotask queue) is being executed, new events may be registered, and new tasks will be created. For example the following two
    1. The callback of promiseA.then() is a task
    1. PromiseA is resolved or rejected: then this task will be put into the microtask queue of the current event loop round
    1. promiseA is pending: this task will be put into the microtask queue of a future (possibly next) round of the event loop
    1. The callback of setTimeout is also a task, it will be put into the macrotask queue even if it is 0ms
    
  2. The tasks in the microtask queue will be executed in the current round of the event loop, so the tasks in the macrotask queue can only wait until the next round of the event loop to execute
  3. The callbacks of click ajax setTimeout are all tasks, and at the same time, the js code wrapped in a script tag is also a task, to be precise, a macrotask.

references

[^3]:  let statement (JavaScript)  .aspx)
[^2]:  https://www.zhihu.com/question/36972010 
[^1]:  https://github.com/ccforward/cc/issues/ 48

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326473633&siteId=291194637