Home  >  Article  >  Web Front-end  >  Detailed explanation of using timers to execute functions regularly in Node.js_node.js

Detailed explanation of using timers to execute functions regularly in Node.js_node.js

WBOY
WBOYOriginal
2016-05-16 16:39:341348browse

If you are familiar with client-side JavaScript programming, you may have used the setTimeout and setInterval functions, which allow a delay in running a function for a period of time. For example, the following code, once loaded into the web page, will append "Hello there" to the page document after 1 second:

Copy code The code is as follows:

var oneSecond = 1000 * 1; // one second = 1000 x 1 ms

setTimeout(function() {

document.write('

Hello there.

');

}, oneSecond);

And setInterval allows the function to be executed repeatedly at specified intervals. If the following code is injected into a Web page, it will cause "Hello there" to be appended to the page document every second:

Copy code The code is as follows:

                var oneSecond = 1000 * 1; // one second = 1000 x 1 ms

setInterval(function() {

document.write('

Hello there.

');

            }, oneSecond);

Because the Web has long become a platform for building applications, rather than simple static pages, this kind of similar demand is increasingly emerging. These task scheduling functions help developers implement periodic form validation, delayed remote data synchronization, or UI interactions that require delayed responses. Node also fully implements these methods. On the server side, you can use them to repeat or delay many tasks, such as cache expiration, connection pool cleanup, session expiration, polling, etc.

Use setTimeout delay function to execute

setTimeout can formulate an execution plan to run the specified function once in the future, such as:

Copy code The code is as follows:

                      var timeout_ms = 2000; // 2 seconds

var timeout = setTimeout(function() {

console.log("timed out!");

                 }, timeout_ms);

Exactly the same as client-side JavaScript, setTimeout accepts two parameters. The first parameter is the function that needs to be delayed, and the second parameter is the delay time (in milliseconds).

setTimeout returns a timeout handle, which is an internal object. You can use it as a parameter to call clearTimeout to cancel the timer. Otherwise, this handle has no effect.

Use clearTimeout to cancel the execution plan

Once you obtain the timeout handle, you can use clearTimeout to cancel the function execution plan, like this:

Copy code The code is as follows:

                    var timeoutTime = 1000; // one second

var timeout = setTimeout(function() {

console.log("timed out!");

                }, timeoutTime);

clearTimeout(timeout);

In this example, the timer will never be triggered, nor will the words "time out!" be output. You can also cancel the execution plan at any time in the future, as in the following example:

Copy code The code is as follows:

var timeout = setTimeout(function A() {

console.log("timed out!");

                      }, 2000);

                                       setTimeout(function B() {

                                                                                                                                                                                                                                                          
                     }, 1000);

The code specifies two delayed execution functions A and B. Function A is scheduled to be executed after 2 seconds, and B is scheduled to be executed after 1 second, because function B is executed first and it cancels A’s execution plan. , so A will never run.

Make and cancel repeated execution plans for functions

setInterval is similar to setTimeout, but it will execute a function repeatedly at specified intervals. You can use it to periodically trigger a program to complete tasks such as cleaning, collection, logging, data acquisition, polling, etc. that need to be performed repeatedly.

The following code will output a "tick" to the console every second:


Copy code The code is as follows:
                var period = 1000; // 1 second
setInterval(function() {

console.log("tick");

             }, period);


If you don’t want it to run forever, you can use clearInterval() to cancel the timer.

setInterval returns an execution plan handle, which can be used as a parameter of clearInterval to cancel the execution plan:

Copy code The code is as follows:
                var interval = setInterval(function() {
console.log("tick");

             }, 1000);

                                                 // …

clearInterval(interval);


Use process.nextTick to delay function execution until the next round of the event loop

Sometimes client-side JavaScript programmers use setTimeout(callback,0) to delay the task for a short period of time. The second parameter is 0 milliseconds, which tells the JavaScript runtime to wait immediately after all pending events have been processed. Execute this callback function. Sometimes this technique is used to delay the execution of operations that do not need to be performed immediately. For example, sometimes you need to start playing animation or do some other calculations after the user event is processed.

In Node, just like the literal meaning of "event loop", the event loop runs in a loop that processes the event queue. Each round of the event loop's work process is called a tick.

You can call the callback function once every time the event loop starts the next round (next tick) of execution. This is exactly the principle of process.nextTick, and setTimeout and setTimeout use the execution queue inside the JavaScript runtime, and Not using event loop.

By using process.nextTick(callback) instead of setTimeout(callback, 0), your callback function will be executed immediately after the event in the queue is processed, which is much faster than JavaScript's timeout queue (in CPU time to measure).

You can delay the function until the next round of the event loop as follows:

Copy code The code is as follows:

process.nextTick(function() {

my_expensive_computation_function();

             });

Note: The process object is one of the few global objects in Node.

Blocking the event loop

The runtime of Node and JavaScript uses a single-threaded event loop. Each time it loops, the runtime processes the next event in the queue by calling the relevant callback function. When the event is executed, the event loop obtains the execution result and processes the next event, and so on until the event queue is empty. If one of the callback functions takes a long time to run, the event loop will not be able to handle other pending events during that time, which can make the application or service very slow.

When processing events, if memory-sensitive or processor-sensitive functions are used, the event loop will become slow, and a large number of events will accumulate, which cannot be processed in time, or even block the queue.

Look at the following example of blocking the event loop:

Copy code The code is as follows:

process.nextTick(function nextTick1() {

var a = 0;

while(true) {

a ;

                                                                                                                      }

             });

process.nextTick(function nextTick2() {

console.log("next tick");

             });

setTimeout(function timeout() {

console.log("timeout");

             }, 1000);


In this example, the nextTick2 and timeout functions have no chance to run no matter how long they wait, because the event loop is blocked by the infinite loop in the nextTick function. Even if the timeout function is scheduled to be executed after 1 second, it will not run.

When using setTimeout, the callback functions will be added to the execution plan queue, and in this example they will not even be added to the queue. This is an extreme example, but you can see that running a processor-intensive task can block or slow down the event loop.

Exit the event loop

Using process.nextTick, you can postpone a non-critical task to the next round (tick) of the event loop, which releases the event loop so that it can continue to execute other pending events.

Look at the example below. If you plan to delete a temporary file, but don’t want the callback function of the data event to wait for this IO operation, you can delay it like this:


Copy code The code is as follows:
                   stream.on("data", function(data) {
stream.end("my response");

process.nextTick(function() {

fs.unlink("/path/to/file");

                                                                                                  

             });


Use setTimeout instead of setInterval to ensure the seriality of function execution

Suppose you plan to design a function called my_async_function, which can perform certain I/O operations (such as parsing log files), and intend to let it execute periodically. You can use setInterval to implement it like this:

Copy code The code is as follows:

                var interval = 1000;

setInterval(function() {

my_async_function(function() {

console.log('my_async_function finished!');

                                                                                                  

                      },interval);//Translator’s Note: The previous “,interval” was added by me, the author may have omitted it due to a typographical error


You must be able to ensure that these functions will not be executed at the same time, but you cannot guarantee this if you use setinterval. If the my_async_function function takes one millisecond longer to run than the interval variable, they will be executed at the same time instead of in order. Serial execution.

Translator’s Note: (The bolded parts below are added by the translator and are not the content of the original book)

In order to facilitate the understanding of this part of the content, you can modify the author's code so that it can actually run:

Copy code The code is as follows:
                var interval = 1000;
setInterval(function(){

(function my_async_function(){

setTimeout(function(){

console.log("1");

                                                                                                                                                     },5000);

                                                                                                                                                              

             },interval);


Run this code and take a look. You will find that after waiting for 5 seconds, "hello" is output every 1 second. Our expectation is that after the current my_async_function is executed (it takes 5 seconds), wait for 1 second before executing the next my_async_function. There should be an interval of 6 seconds between each output. This result is caused by the fact that my_async_function is not executed serially, but multiple ones are running at the same time.

Therefore, you need a way to force the interval between the end of execution of one my_async_function and the start of execution of the next my_async_function to be exactly the time specified by the interval variable. You can do this:


Copy code The code is as follows:

                  var interval = 1000; // 1 second

(function schedule() { //Line 3

setTimeout(function do_it() {

my_async_function(function() { //Line 5

console.log('async is done!');

schedule();

                                                                                                                                                                                    

                        }, interval);

                    }());


In the previous code, a function called schedule is declared (line 3), and it is called immediately after the declaration (line 10). The schedule function will run the do_it function after 1 second (specified by interval). After 1 second, the my_async_function function on line 5 will be called. When it completes execution, its own anonymous callback function (line 6) will be called, and this anonymous callback function will reset do_it's execution plan again. , let it be executed again after 1 second, so that the code begins to execute serially and continuously in a loop.

Summary

You can use the setTimeout() function to preset the execution plan of the function, and use the clearTimeout() function to cancel it. You can also use setInterval() to repeatedly execute a function periodically. Correspondingly, you can use clearInterval() to cancel this repeated execution plan.

If the event loop is blocked by using a processor-sensitive operation, functions that were originally scheduled to be executed will be delayed or even never executed. So don't use CPU-sensitive operations inside the event loop. Also, you can use process.nextTick() to delay function execution until the next iteration of the event loop.

When I/O is used with setInterval(), you cannot guarantee that there will be only one pending call at any point in time. However, you can use recursive functions and the setTimeout() function to avoid this tricky problem.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn