1

I've been reading about setTimeout and other such timers. But I'm wondering if it's possible to work up a custom function so that all you would need to do is something like this:

//code
delay(time);
//more code

Is this possible?

UPDATE: Ok, I kind of get it. So if that isn't reasonably possible, how would you go about delaying a loop AFTER the first time. I want it to run immediately upon execution but they delay on each iteration afterward.

New UPDATE: I figure since my initial thought fell through, it might just be easier to show you the code I have.

function autoFarm (clickEvent){

var farmTargets = [
            "6_300_1",
            "6_300_3",
            "6_300_4",
            "6_300_5",
            "6_300_7"];


setTimeout(function() {
 $.each (farmTargets, function(index, target){     
    var extraData = '{"end_pos":"' + target + '","purpose":0,"upshift":1,"bring_res":{"0":0,"2":0,"1":0},"bring_ship":{"1":25,"11":0},"rate":100,"start_pos":"6_300_2"}';

var finalData = baseDataDora + extraData + "&type=1";

 setTimeout(function(){
    for (i = 0; i < farmTargets.length; i++){
        postRequest(sendFleetURL + getSign(extraData). finalData, function(json){               
        });             
    }       
 }, 15000); 
 });//End each loop
}, 1320000);    
}//End autoFarm

Basically, it should execute immediately and run the for loop 5 times on the first array element 15 seconds apart. Then 22 minutes later move to the next set and repeat for the entire array.

8
  • It is possible with generators. Commented Apr 25, 2015 at 23:41
  • stackoverflow.com/questions/951021/… Commented Apr 25, 2015 at 23:42
  • I'm not familiar with generators. Commented Apr 25, 2015 at 23:42
  • 1
    No, it's not possible reasonably, in JavaScript every function operates synchronously. You can make it busy wait with a while loop but it'll be stuck. Generators aren't exactly what you're asking for but are pretty close when used with promises as coroutines. Commented Apr 25, 2015 at 23:42
  • To answer the new question, like this -> jsfiddle.net/adeneo/08oyjecL Commented Apr 25, 2015 at 23:52

4 Answers 4

1

You can achieve something along those lines with generators. The idea is that continuation passing style (callback hell) can be flattened. The generator uses the yield keyword to pause the function, until the callback resumes it by calling its next method:

var async = function(gen) {
  var g = gen()
  function next(x) {
    var cur = g.next(x)
    if (cur.done) {
      return cur.value
    }
    cur.value(next)
  }
  next()
}

var delay = function(time) {
  return function(f) {
    setTimeout(f, time)
  }
}

async(function* () {
  console.log('before')
  yield delay(1000) // waits one second
  console.log('middle')
  yield delay(1000) // waits one second
  console.log('after')
})

In CPS it would read something like:

console.log('before')
setTimeout(function() {
  console.log('middle')
  setTimeout(function() {
    console.log('after')
  }, 1000)
}, 1000)

This works in Chrome, Firefox and iojs today.

Sign up to request clarification or add additional context in comments.

1 Comment

+1. Another option is the async/await syntax proposed for ES7 (see pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html) which can be achieved today with Babel
0

This isn't possible because of the way single-threaded event loops work. If this function were to exist, it would cause the entire UI thread to freeze until the delay was satisfied. setTimeout(cb, delay) is the nearest facility which schedules a function to be executed no earlier than the delay and at the end of the current event loop tick.

Update: Before somebody calls me on it, yes, you can theoretically engineer a delay function that freezes everything in place for a set amount of time. However, there is no reasonable excuse to do it this way.

To your second question:

function hello() {
    console.log('hello');
}

// execute immediately
hello();

// then every 5 seconds
setInterval(hello, 5000);

3 Comments

Ok. One question I have is this. I have a for loop running inside an each loop. If I put the setTimeout function on the bottom to call the function over again on a delay, do those loops hold their place so to speak?
If I understand you correctly, no. They will execute in order, but, if your loop looped 1000 times and you did 1000 setTimeout(fn, 1000), after one second 1000 function calls would happen one after another.
There can be some reasonable excuses for this delay, it is very helpful when you want to simulate big delays on external API requests, for an instance.
0

As-written, no that's not possible.

If, instead you were to use a queue, delays in that manner are trivial.

jQuery's .queue() and .delay() functions are a good example of how this works, so I will use them as an example, however the general point stands for any queueing library.

Instead of:

//code
delay(time)
//more code

With a queue, you'd write:

$('...') //some selector to act on for jQuery
.queue(function (next) {
    //code

    //Indicate that the queued call is finished.
    next();
    //This allows async code to be executed in the queue,
    //such as ajax and animations
})
.delay(time)
.queue(function (next) {
    //more code
    next();
});

Now, even if you ignore the lines used for comments, you can tell that there's a bit more boilerplate to achieve the desired behavior. I don't feel that it's excessive, because I find it relatively easy to read:

  1. queue something to happen
  2. wait for some number of milliseconds
  3. queue something else to happen

Comments

0

Using a Promise, calling it inside an asynchronous function.

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const any_function = async() => {
   await delay(2000); 
   console.log('this log has been delayed 2 secs')
} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.