1

I was wondering if I could use promises with my countdown timer. My code looks something like this:

function countdown(duration, callback) {
  ...
}

function sayHi() {
  console.log('hi');
}

and I call it by doing something like

countdown(15, sayHi);

Is there a way I could do this instead?

countdown(15).then(sayHi); 

Here is a JSFiddle of my current code.

Saad
  • 49,729
  • 21
  • 73
  • 112
  • 2
    That would be an asynch operation, wouldn't it. ? – Jaromanda X Nov 25 '15 at 06:58
  • Google about promises, then you'll be able to answer your question. – Bhojendra Rauniyar Nov 25 '15 at 06:59
  • Is it really? All the code inside my `countdown` function is synchronous, [this](http://jsfiddle.net/amhLwqd4/1/) is what it looks like right now. I basically just call the callback manually. – Saad Nov 25 '15 at 07:00
  • "*Are promises only for async operations?*" - Yes. "*Is there a way I could do `countdown(15).then(sayHi);` instead?*" - Yes. Show us what `...` is and we may be able to help you with the transformation. – Bergi Nov 25 '15 at 07:01
  • Count down timer implies asynchronicity. My bad – Jaromanda X Nov 25 '15 at 07:03
  • @meh_programmer: `setInterval`, which you are using inside your `countdown` function, is *not synchronous*. – Bergi Nov 25 '15 at 07:04
  • @Bergi Sorry about that, I updated my post with a JSFiddle. And oh, I see that makes sense. – Saad Nov 25 '15 at 07:04
  • @Bergi I want to choose an answer so this question can be resolved. Do you think the answer by ShanShan is the best way to do this? – Saad Nov 25 '15 at 07:07

4 Answers4

3

Yes, promises are a way to "hide" callbacks. For your example, you could use promises like this:

function countdown(duration) {
    return new Promise(function (resolve, reject) {
        // wait for duration and resolve
        setTimeout(function () {
            resolve();
        }, duration);
    });
}

function sayHi() {
    console.log('hi');
}

countdown(1000).then(sayHi);
Shanoor
  • 13,344
  • 2
  • 29
  • 40
  • Not all callbacks can be hidden using promises. – Bergi Nov 25 '15 at 07:02
  • Do you have an example? Instead of passing the callback as an argument, it goes to the `then()` and no other change is needed. – Shanoor Nov 25 '15 at 07:04
  • 1
    [Many examples](http://stackoverflow.com/a/21884813/1048572), actually :-) Your code is fine, I just disagree with the generality of the statement "*promises are a way to "hide" callbacks*". – Bergi Nov 25 '15 at 07:07
  • 1
    Ah, I see. I just realised that when a callback is called multiple times (sync or async), a promise can't (easily?) replace it. That's where pipes/streams come in play in NodeJS. Interesting. – Shanoor Nov 25 '15 at 08:01
  • Exactly - promises can never be used in such situations. They're only suited for callbacks that are called exactly once (and usually asynchronous). – Bergi Nov 25 '15 at 08:06
2

A promise is suitable for any operation that won't necessarily run immediately.

Javascript is single-threaded. So if you call a function, it will necessarily run immediately on the same thread. A promise is a convenient way to run code some time later (still on the same thread, but as part of a different event handler).

So in the case of a timeout, when the callback should be called later, using a promise is a good idea.

And if you're unsure whether to use a promise or a simple callback, both serve more-or-less the same purpose, but promises normally make the code more readable.

ES7 async-await is even more readable!

Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
  • Thank you for the explanation! Gave you an upvote. Also thanks for the link to the async-await, that looks pretty cool – Saad Nov 25 '15 at 07:09
0

yes you can resolve them at your own specific time like.use closures to escape from bad response from multiple calls simultaneously.

function countdown(duration, callback) {
 var deferred = Promise.defer();
    (function(duration,deferred){setTimeout(function(){
        deferred.resolve();
    },duration);
  })(duration,deferred);
}

Previous one is outdated check this one.

  function countdown(duration, callback) {
     return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve();
            }, duration);
        });


}
ngLover
  • 4,439
  • 3
  • 20
  • 42
0
function countdown(duration) {
  return new Promise(function(resolve, reject) {
    var interval = setInterval(function() {
      console.log(duration--);
      if (!duration) {
        clearInterval(interval);
        resolve();
      }
    }, 1000);
  });
}
countdown(15).then(function() { console.log("DONE"); });
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • It's more reasonable to promisify `setTimeout` and use that as an asynchronous primitive. Using `console.log` inside `setInterval` like you did gives you none of the advantages of promises. – Bergi Nov 25 '15 at 07:03
  • @Bergi: The promise is for the end of countdown, just as it seems to be in OP's post. The `console.log` simulates the UI updates one would do for the duration of the countdown. I guess I took "countdown" literally. – Amadan Nov 25 '15 at 07:05
  • Yeah, but if you're using promises, you should be doing the UI updates from promises as well :-) – Bergi Nov 25 '15 at 07:09
  • Why reinvent `setTimeout`? – jib Dec 02 '15 at 02:30