2016-01-24 46 views
3

因此,我發現Promise.defer現在已被棄用,現在我們應該使用new Promise來代替。對於這個例子,我看不到如何做到這一點?如何用新的Promise()替換Promise.defer()

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

回答

5

在一般情況下,建議,因爲你想要一個承諾的創造者是負責解決或拒絕它移動從舊延遲模式了 - 這只是作爲控制流的一噸更容易執行。您不想將解決或拒絕其他代碼的責任傳遞給其他代碼。

如果決定解決或拒絕外部代碼(例如您的rollDice()函數),則它可以返回用於解析或拒絕的信息。例如,在你的代碼示例中,它可以像這樣完成。

請注意,rollDice()功能現在只是一個骰子滾動功能,告訴你是否滾動了一個特定的數字。然後由其他函數使用它來確定控制流程,而不是將控制流程放入骰子滾動函數本身。變化的

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(),你通過它你想要它達到的數字。

雖然上述方案是更普遍的(利用外部函數提供有關是否應該解決與否反饋),在這種特殊情況下,如果你甚至不需要的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>

1

使用new Promise(constructorFn)是寫interval = setInterval(...)constructorFn試試這個

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); 
    }); 
} 
+1

'rollDice()'函數真的沒有理由必須知道任何有關某個promise的任何信息,因此真的沒有理由將promise的解析委託給promise構造函數之外。 'rollDice()'在生活中的工作就是隨機滾動。 'rollTill7()'中的代碼可以使用'rollDice()'中的返回值,然後'rollTill7()'可以確定是否已經達到了期望的數量以及是否應該解析promise。承諾最容易理解,如果它們是在同一代碼塊中創建和解析的。 – jfriend00

+0

@ jfriend00,你是對的。我只是用'new Promise'來代替'defer'。但是,對於您的建議,這是更好的做法...... – zangw

1

直接等同,並constructorFn決心參數傳遞給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()也被移動到了承諾的構造。不僅兩個成員從外部命名空間中移除,而且還避免了通過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表達作爲一個匿名函數。這可能會導致命名函數的問題,它不僅僅是「擲骰子」 - 它也可以解決。

+0

接受此作爲答案,因爲我欣賞改進的範圍解決方案。 – GroovyDotCom

+0

@GroovyDotCom - 我不會認爲這些解決方案都是理想的。第一個方案仍然負責解決對一個外部函數的承諾,而這個外部函數根本就不是必需的,並且可以使人們理解和遵循代碼的能力真正複雜化,特別是在更大的代碼體系中。首先不使用延期的關鍵在於保持本地化的解決和拒絕責任,而不是在其他地方傳遞它。第二個例子很方便,但它隱藏了'rollDice()'函數,因此它不能在其他地方使用 – jfriend00

+0

@GroovyDotCom - 雖然在這個特定的例子中隱藏'rollDice()'函數可能是確定的,大小寫就是該函數在外部聲明的地方,因爲它在別處被使用(否則,它甚至不需要是一個函數)。您可以在這裏看到其他解答之一,以獲得更爲一般的解決方案。 – jfriend00

相關問題