Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace Promise.defer with new Promise()

So I see that Promise.defer is now deprecated and we are now supposed to use new Promise instead. I don't see how to do this however for this example?

var Promise = require('bluebird');
var interval;

var rollDice = function (resolver) {
  console.log("rolling");
  if (Math.floor(Math.random() * 10) == 7) {
    clearInterval(interval);
    resolver.resolve();
  }
}

var rollTill7 = function (ms) {
    var resolver = Promise.defer();
    interval = setInterval(function(){rollDice(resolver);},ms);
    return resolver.promise;
}

rollTill7(100).then(function(){
    console.log("rolled a 7");
});
like image 208
GroovyDotCom Avatar asked Jan 24 '16 01:01

GroovyDotCom


People also ask

How do you resolve a Promise in another function?

You can wrap the Promise in a class. class Deferred { constructor(handler) { this. promise = new Promise((resolve, reject) => { this. reject = reject; this.

What does Promise () method do?

The . promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended. By default, type is "fx" , which means the returned Promise is resolved when all animations of the selected elements have completed.

What is Promise resolve () then?

The Promise.resolve() method "resolves" a given value to a Promise . If the value is a promise, that promise is returned; if the value is a thenable, Promise.resolve() will call the then() method with two callbacks it prepared; otherwise the returned promise will be fulfilled with the value.

What is defer in Promise?

The deferred. promise() method allows an asynchronous function to prevent other code from interfering with the progress or status of its internal request.


1 Answers

In general, it is recommended to move away from the old defer model because you want the creator of a promise to be responsible for resolving or rejecting it - this just makes the control flow a ton easier to follow. You don't want to pass on the responsibility for resolving or rejecting to some other code.

If outside code is involved in the decision to resolve or reject (such as your rollDice() function), then it can return info which is used to resolve or reject. For example, in your code example, it can be done like this.

Note that the rollDice() function is now just a dice rolling function that tells you whether you rolled a specific number of not. It is then used by the other function to determine control flow rather than putting control flow in the dice rolling function itself.

var rollDice = function() {
  console.log("rolling");
  return Math.floor(Math.random() * 10) + 1;
}

var rollTillNum = function(num, ms) {
    return new Promise(function(resolve) {
        var interval = setInterval(function(){
            if (rollDice() === num) {
               resolve();
               clearInterval(interval);
            }
        }, ms);
    });
}

rollTillNum(7, 100).then(function(){
    console.log("rolled a 7");
});

Summary of Changes:

  1. Promise management is self-contained, not delegated to some other function (makes logic of the code easier to follow) which is one of the main reasons to use the new Promise constructor and not the deferred construct.
  2. The interval variable is now contained to a local scope.
  3. The rollDice() function is now generic so it can be used in other contexts.
  4. rollDice() now returns a 1-based value, not a 0-based value (since that's how dice work).
  5. Rather than hardwire rollTill7(), it's now rollTillNum() and you pass it the number you want it to achieve.

While the above solution is more general (using an external function to provide feedback on whether you should resolve or not), in this specific case, if you don't even need the rollDice() function to be externally usable, then it can just be subsumed entirely inside of the rollTillNum() function:

var rollTillNum = function(num, ms) {
    return new Promise(function(resolve) {
        var interval = setInterval(function(){
            if ((Math.floor(Math.random() * 10) + 1) === num) {
               resolve();
               clearInterval(interval);
            }
        }, ms);
    });
}

rollTillNum(7, 100).then(function(){
    console.log("rolled a 7");
});

Here's the above code made into a working demo:

document.getElementById("roll").addEventListener("click", function() {
    var start = Date.now();
    rollTillNum(7, 100).then(function(cnt) {
        var elapsed = ((Date.now() - start) / 1000).toFixed(1);
        log("It took " + elapsed + " seconds and " + cnt + " rolls to roll a 7");
    });
});

var rollDice = function() {
  console.log("rolling");
  return Math.floor(Math.random() * 10) + 1;
}

var rollTillNum = function(num, ms) {
    return new Promise(function(resolve) {
        var cntr = 0;
        var interval = setInterval(function(){
            ++cntr;
            if (rollDice() === num) {
               resolve(cntr);
               clearInterval(interval);
            }
        }, ms);
    });
}

function log(x) {
    var div = document.createElement("div");
    div.innerHTML = x;
    document.body.appendChild(div);
}
<button id="roll">
Roll a 7
</button><br><br>
like image 147
jfriend00 Avatar answered Nov 06 '22 00:11

jfriend00