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.

  • It is possible with generators. – elclanrs Apr 25 '15 at 23:41
  • http://stackoverflow.com/questions/951021/what-do-i-do-if-i-want-a-javascript-version-of-sleep – drs9222 Apr 25 '15 at 23:42
  • I'm not familiar with generators. –  Apr 25 '15 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. – Benjamin Gruenbaum Apr 25 '15 at 23:42
  • To answer the new question, like this -> http://jsfiddle.net/adeneo/08oyjecL/ – adeneo Apr 25 '15 at 23:52
  • Just checking (in response to your update)...have you looked at setInterval()? – Matt Browne Apr 25 '15 at 23:55
  • Note that setTimeout() and setInterval() aren't 100% accurate...so when you say you want it to move to the next set 22 minutes later, it's important to be aware that it might not be *exactly* 22 minutes. If accuracy is important, you could implement the timing on the server and have the server push updates to the client using WebSockets (e.g. with socket.io). – Matt Browne Apr 26 '15 at 00:45
  • It doesn't have to be exact. Just fairly close. –  Apr 26 '15 at 05:11

4 Answers4

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.

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • +1. Another option is the async/await syntax proposed for ES7 (see http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html) which can be achieved today with [Babel](http://babeljs.io/docs/usage/transformers/other/async-to-generator/) – Matt Browne Apr 26 '15 at 00:34
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);
brian
  • 2,745
  • 2
  • 17
  • 33
  • 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? –  Apr 25 '15 at 23:55
  • 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. – brian Apr 25 '15 at 23:57
  • 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. – Banzy Sep 17 '21 at 12:26
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
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
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')
} 
Banzy
  • 1,590
  • 15
  • 14