JavaScript Learning Notes [setTimeout]

Let’s look at two examples

console.log(1);
setTimeout(function () {
    console.log(2);
}, 0);
console.log(3);
Copy the code

The code above outputs 1, 3, 2

Regardless of the execution time of setTimeout is 0 or 1000, the result is 3 followed by 2

for (var i = 0; i < 4; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
Copy the code

The output is 4, 4, 4, 4

Single threaded JavaScript

The first thing we need to know is that JavaScript is single-threaded. JS can only do one thing at a time, which is often referred to as “blocking execution.”

Asynchrony can be used for non-blocking execution.

Task queue: A first-in, first-out queue that holds events and tasks.

All tasks can be categorized into two types, synchronous and asynchronous.

Synchronization task: a task that is queued to be executed on the main thread can be executed only after the previous task is completed.

  • The output
  • Declaration of variables
  • Synchronization function

Asynchronous tasks:

  • SetTimeout and setInterval
  • DOM events
  • Promise
  • process.nextTick
  • fs.readFile
  • http.get
  • An asynchronous function

In addition, task queues are divided into macro-tasks and micro-tasks. In ES5 standard, they are called tasks and jobs respectively.

Second, setTimeout operation mechanism

SetTimeout is asynchronous, and the running mechanism is the specified code. It will not be executed until all synchronous code has been executed.

Priority relationship: Asynchronous tasks are suspended and executed first. Asynchronous tasks respond to asynchronous tasks only after they are completed.

Here is an example of asynchronous execution:

The browser has a timer module, and the timer will not put the asynchronous task into the asynchronous queue until the execution time. During the execution of the for loop, setTimeout is not put into the asynchronous queue, but given to the timer module.

The four loop bodies execute very fast (less than 1 millisecond). The timer (4 ms by default even if 0 is set) does not place the setTimeout statement on the asynchronous queue until the set time.

The source calls me Townsson

Third, solutions

For the second example above to get 0, 1, 2, 3, you can use the following method.

Method 1: Use let

Use let, not var, because let is scoped, so the value of setTimeout points to the value in each loop body

for (let i = 0; i < 4; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
Copy the code

Method two: Use closures

for (var i = 0; i < 4; i++) {
    (function (i) {
        setTimeout(function () {
            console.log(i);
        }, 1000 * i)
    })(i);
}
Copy the code

Because the value of each I is passed into function, the scope of I in setTimeout is in this closure

Promise based solution

const tasks = [];

const output = (i) = > new Promise((resolve) = > {
    setTimeout(() = > {
        console.log(i);
        resolve();
    }, 1000 * i);

});

// Generate all asynchronous operations
for (var i = 0; i < 5; i++) {
    tasks.push(output(i));
}
// When the synchronization operation is complete, print the last I
Promise.all(tasks).then(() = > {
    setTimeout(() = > {
        console.log(i);
    }, 1000)})Copy the code

A solution using the async await feature in ES7

const sleep = (timeountMS) = > new Promise((resolve) = > {
    setTimeout(resolve, timeountMS);
});

(async() = > {// Declare async to be executed
    for (var i = 0; i < 5; i++) {
        await sleep(1000);
        console.log(i);
    }

    await sleep(1000);
    console.log(i); }) ();Copy the code

References:

www.cnblogs.com/tangjianqia… www.jianshu.com/p/3facc9bd8…