setTimeout little awkward

As we all know, Alert bomb built this box will block the subsequent code execution:

This is so because the JavaScript code in the browser is a single thread of execution. In other words, the browser only one main thread is responsible for running all the JavaScript code (without regard to Web Worker).

Mentioned browser JavaScript, basically only three sources:

  • BOM API code, so that we can operate and utilize the capacity provided by the browser

  • DOM API code, so that we can operate web content

  • Write our own code for ECMAScript

this is nothing. We also know, the setTimeout for "time" the code, such as the timing of implementation of a code which can (function) after 3 seconds:

Of course, we all know, the setTimeout "time" is not accurate, it can only guarantee delayCode function in three seconds after the execution, as after three seconds have to wait long to execute, just like it does not matter.

What's with that relationship? We know that the task queue / JavaScript event loop is a mechanism to perform asynchronous tasks. setTimeout as BOM API, it is responsible for setting a timer, point to add a function to be performed to the task queue. So that it complete the task. And to add functions to the task queue does not guarantee immediate execution. When can perform depends on the event loop when this function is dispatched to the main thread. Scheduling asynchronous event loop function on the premise that the main thread is idle. If the main thread is blocked, even if the function is added to the event queue, the event loop will not dispatch it immediately to the main thread. This is the setTimeout precise timing reasons can not execute a function.

Obviously, if your code dependencies setTimeout precise timing logic, it is possible embarrassed. For this purpose write code unless absolutely sure, we must try not to rely on our own precise timing of setTimout. However, the problem is that we can guarantee to write their own code does not depend on it, it is difficult to ensure that our code relies on third-party code does not depend on it.

Small Case

Here we have to introduce this awkward encounter a real case. The function of this case involved very simple, is jQuery's $ .ajax () function retransmission request when loading data failed. Because of its dependency timeout logic precise timing setTimeout, resulting in failure timeout setting.

The relevant code is also very simple, involving three main functions: 

asyncRequest function () { 
  $ .ajax ({ 
    URL: 'https://api.example.rs', 
    timeout: 15 
  }). the then (Success, Fail) 
} 

function Success (Data) { 
  // normal processing data 
} 

function Fail (XHR, errtext, errthrown) { 
  // retransmission request 
  asyncRequest () 
  // prompt box shells; block the main process 
  alert ( 'request timeout') 
} 
// first call 
asyncRequest ()

 

  • asyncRequest: function contains an Ajax request, will call again fail in

  • success: Ajax callback request successful

  • fail: Ajax callback request failed

Normal logic is this: call asyncRequest sends a request, the browser will succeed success added to the task queue, failed the browser will fail to add to the task queue. After the event loop will dispatch them to the main thread. success is the normal data processing, and fail will first call asyncRequest retransmission request, then call alert box prompts shells.

The test environment around Ajax request may return 100 milliseconds. The order to test the logic behind the timeouts , we deliberately timeout to 15 milliseconds, to ensure a certain time out. When the actual test, the first request times out, go fail branch, retransmission request, bomb box, no problem. However, the mouse click to close the box shells, they found a request for retransmission of a normal return, and is not to be canceled due to a timeout. Repeated tests are true.

This is embarrassing, in the end why? Found, jQuery kill timeout request the code is such that (https://j11y.io/jquery/#v=git&fn=jQuery.ajax):

In other words, we set the case timeout option, jQuery will by setting setTimeout function after a 15 millisecond timer executed for interrupting ( ABORT) request, we call interrupt function .

Under normal circumstances, after executing the above code, the browser function is added to the task queue interrupted after 15 ms. At this point if the main thread is idle, the event loop function will immediately dispatched to the main thread to perform, the request is canceled, the browser to add to fail the task queue, the event loop to dispatch it to the main thread. This is the first call to the situation of asyncRequet.

The second call asyncRequest time any different? The difference is that the complete call after asyncRequest, also playing the box blocked the main thread. Call the result of asyncRequest with before, the browser will still add to the task queue interrupt function after 15 ms. However, here to note, at this time because the main thread has been blocked due to bomb box in an occupied state, the event loop can only wait. Holding the mouse until we spend a second or two to bomb box closes, and free up the main thread, interrupt function will be scheduled to execute on the main thread. But before this, Ajax request already successful return, while the browser to add success to the task queue.

In theory, Ajax request after returning jqXHR ( state XMLHttpRequest) objects should not be any change (change no meaning). Therefore, the implementation of the interrupt function does not change "request has been successful return," this fact. More embarrassing is that - after interrupt function is executed, followed by the event loop again success scheduling function to the main thread. The fail function did not enter the job queue, let alone implemented.

Small harvest

Through the above case study, we see that this "time out" request failed because the interrupt function is delayed on the task queue delays in the execution, but ultimately successful return data. Of course, the root of the problem lies in alert boxes bomb blocked the main thread, as well as asynchronous JavaScript mechanism (event loop).

As for jQuery rely setTimeout cancellation logic timeout request, as long as the situation is not encountered cases like this article so long block the main process will have no problems. In this case, if not for the test and then the timeout is set too short, but is set to 5000 milliseconds for example, this embarrassing situation will not arise. If the actual server response time is really more than 5 seconds, turn off the box before playing in Ajax request as long as we return, interrupt function will still perform the first step, thereby eliminating outstanding requests. Of course, the use of practice bombs box system would have blocked the main process is not a recommended practice.

Anyway, by chance, we take this little awkward (or relive) in-depth understanding of the setTimeout and even JavaScript (It should be said that the browser provides JavaScript runtime) of asynchronous code enforcement mechanisms. So in the next programming practice, we can consciously avoid logic relies setTimeout precise timing, because its timing is not really reliable ah!

Guess you like

Origin www.cnblogs.com/axl234/p/11303455.html