如何用新的Promise()替换Promise.defer

时间:2016-01-24 01:11:32

标签: node.js promise

所以我看到Promise.defer现已弃用,我们现在应该使用new Promise。但是,对于这个例子,我不知道如何做到这一点?

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");
});

3 个答案:

答案 0 :(得分:10)

一般情况下,建议远离旧的延迟模型,因为您希望承诺的创建者负责解决或拒绝它 - 这只会使控制流更容易理解。您不想传递解决或拒绝其他代码的责任。

如果决定解决或拒绝外部代码(例如您的rollDice()函数),则它可以返回用于解析或拒绝的信息。例如,在您的代码示例中,可以这样做。

请注意,rollDice()函数现在只是一个骰子滚动函数,它告诉您是否滚动了特定数量的not。然后由另一个函数使用它来确定控制流,而不是将控制流放在骰子滚动功能本身中。

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");
});

更改摘要:

  1. 承诺管理是自包含的,不会委托给其他一些函数(使代码的逻辑更容易理解),这是使用新的Promise构造函数而不是延迟构造的主要原因之一。
  2. interval变量现在包含在本地范围内。
  3. rollDice()函数现在是通用的,因此可以在其他上下文中使用。
  4. rollDice()现在返回一个基于1的值,而不是一个从0开始的值(因为这是骰子的工作方式)。
  5. 而不是硬连线rollTill7(),而不是现在rollTillNum()并且您传递了它想要实现的数字。
  6. 虽然上述解决方案更为通用(使用外部函数提供是否应该解决的反馈),但在这种特定情况下,如果您甚至不需要rollDice()函数外部可用,然后它可以完全包含在rollTillNum()函数内:

    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");
    });
    

    以上代码制作成工作演示:

    
    
    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>
    &#13;
    &#13;
    &#13;

答案 1 :(得分:1)

试试这个

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

var rollTill7 = function (ms) {
    return new Promise(function(resolve) {
        interval = setInterval(function() {
            rollDice(resolve);
        }, ms);
    });
}

答案 2 :(得分:1)

使用new Promise(constructorFn)的直接等效项是在interval = setInterval(...)内写constructorFn并将constructorFn的resolve参数传递给rollDice()而不是原始的Deferred对象。

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

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

var rollTill7 = function (ms) {
    return new Promise(function(resolve, reject) {
        interval = setInterval(function() {
            rollDice(resolve);
        }, ms);
    });
};

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

如果将intervalrollDice()移动到promise的构造函数中,解决方案会变得更加整洁。不仅从外部命名空间中删除了两个成员,而且还避免了传递resolve的需要 - 由于关闭,rollDice()可以访问它。

var Promise = require('bluebird');

var rollTill7 = function (ms) {
    return new Promise(function(resolve, reject) {
        var interval;
        var rollDice = function () {
          console.log("rolling");
          if (Math.floor(Math.random() * 10) == 7) {
            clearInterval(interval);
            resolve();
          }
        };
        interval = setInterval(rollDice, ms);
    });
};

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

进一步微弱但可以说是重要的一步,您可能会选择将rollDice()作为匿名函数移动到setInterval表达式中。这将使命名函数的一个问题侧重于它不仅仅是&#34;滚动骰子&#34; - 它也解决了。