How do I set a specific order of execution when as

2019-02-20 23:55发布

I am new(2 days!!) to the world of JavaScript and my only prior coding experience is in Java where execution of statements takes place sequentially. I understand that or at least I've read that JavaScript is asynchronous which means that if there is a statement that takes a long time to execute, the next statement is executed without holding up the program for the first statement. I came across callbacks(a lot actually!!) but I couldn't see how they could be used to determine the order of execution. I wrote a piece of code just to understand how it could be done and I sure could use some help.

console.log("Beginning");

function Test(callback){
   setTimeout(function(callback){
       console.log("Something that takes a lot of time");
   },5000);
   callback();
}

function tstCallBack(){
    console.log("Should come last");
}

Test(tstCallBack);

What I want is for the output to display -

Beginning
Something that takes a lot of time
Should come last

But the output I am getting is -

Beginning
Should come last
Something that takes a lot of time

Is there anything I can do to get the output in the way I want it?

4条回答
冷血范
2楼-- · 2019-02-20 23:58

A lot of what you've said is wrong. JavaScript is sequential in the same way as Java, but asynchronous calls are made more often. If you want your callback to be called after the long thing, you must call it after the long running program. Like so -

console.log("Beginning");
function Test(callback){
   setTimeout(function(callback){
    console.log("Something that takes a lot of time");
    callback();
   },5000);

 }
function tstCallBack(){
   console.log("Should come last");
}
Test(tstCallBack);
查看更多
Bombasti
3楼-- · 2019-02-21 00:03

Place the callback inside setTimeout and not outside as the callback will be executed first before the setTimeout does as javascript won't wait for setTimeout execution(as JS is synchronous by nature) and executes the next line and hence you won't get the desired output.

console.log("Beginning");
function Test(callback){
   setTimeout(function(){
    console.log("Something that takes a lot of time");
    callback();
   },5000);
 }
function tstCallBack(){
   console.log("Should come last");
}
Test(tstCallBack);

Demo

查看更多
孤傲高冷的网名
4楼-- · 2019-02-21 00:12

Let's clear some things up in what you said:

I am new(2 days!!) to the world of JavaScript and my only prior coding experience is in Java where execution of statements takes place sequentially. I understand that or at least I've read that JavaScript is asynchronous which means that if there is a statement that takes a long time to execute, the next statement is executed without holding up the program for the first statement.

This is not how it works. A given function is either asynchronous or its synchronous by design. It has absolutely nothing to do with how long it takes to execute. You can have a very quick async function or a very long synchronous function. What determines whether the function is asynchronous or not is how it is designed. If it uses async I/O or timers or any other async infrastructure, then at least some of the execution of the function is asynchronous. That means that some of the function will finish LATER and some of the code right after this function call will execute BEFORE the async portion finishes.

I came across callbacks(a lot actually!!) but I couldn't see how they could be used to determine the order of execution. I wrote a piece of code just to understand how it could be done and I sure could use some help.

Callbacks are used to notify the calling code when some asynchronous operation has completed. This can be used either to consume the result of the asynchronous operation or can be used to execute the next piece of code that wants to run in sequence after the async operation has finished.

In your code example, if you want the desired sequence, then you must call the callback inside the setTimeout() callback so that it gets called AFTER the setTimeout() called executes, thus giving you the desired sequence.

You also have to remove the callback argument to the setTimeout callback. That callback is not passed with that argument so declaring it there is just wrong. It can be accessed directly from the parent function via a closure as shown here:

console.log("Beginning");

function Test(callback){
   setTimeout(function(){
       console.log("Something that is asynchronous");
       // call the callback here to indicate to the calling code
       // that the asynchronous operation is now complete
       callback();
   },5000);
   console.log("After Setting Timer");
}

function tstCallBack(){
    console.log("Should come last");
}

Test(tstCallBack);

This will generate a sequence in the console of:

Beginning

After Setting Timer

Something that is asynchronous

Should come last


Conceptually, the Javascript engine runs a single thread and that single thread uses an event queue. So, in your function above, this is what happens.

  1. The first console.log("Beginning"); is executed.
  2. Test(tstCallback) is called.
  3. As part of executing the Test() function, a timer is scheduled. This registers a timer internal to the JS engine.
  4. The execution of code in Test() continues, console.log("After Setting Timer"); is executed and then that function finishes.
  5. The current thread of JS execution finishes and if there is nothing else in the event queue, then the JS engine has nothing to do, but wait for the next event to occur.
  6. Some time later (the 5 seconds that your timer is set for), the internal timer fires and it puts the timer event in the JS event queue.
  7. Since there is no other JS executing at the moment, the timer event is pulled out of the event queue and executed. This means that the original callback that was registered for the timer is called.
  8. As the timer callback is called, it executes the console.log("Something that is asynchronous"); line and then calls callback().
  9. Your tstCallback function is then called and console.log("Should come last"); is executed.
  10. The async event finishes execution and the JS engine looks to see if there are any more events in the event queue. If so, the next event is pulled out of the queue and it is run.

There are a number of very good references on how Javascript handles asynchronous operations:

How does JavaScript handle AJAX responses in the background?

How Javascript Timers Work

Do I need to be concerned with race conditions with asynchronous Javascript?

查看更多
Viruses.
5楼-- · 2019-02-21 00:14

I have modified your code as below to get the desired output.

console.log("Beginning");
function Test(callback){

    console.log("Something that takes a lot of time");
    setTimeout(callback,5000);
 }

function tstCallBack(){
   console.log("Should come last");
}
Test(tstCallBack);

setTimeout takes a callback function that will be executed after the specified time interval

The use of setTimeout is the asynchronous part. When the above code is executed,first the "Begining" console statement is printed and then the Test function is called passing in a function that needs to be executed asynchronously after 500ms .

查看更多
登录 后发表回答