2016-06-21 91 views
0

(*我修改了最初的問題。*)從承諾中回報價值:回調或承諾?

我有一個異步函數calculate從而重新計算Excel工作簿和打印需要多長時間。

然後,我想讓函數返回計算時間,以便我可以記錄它。它認爲使一個異步函數返回一個值。我看過幾個線程,並編寫以下2種方式,其工作:

function calculate1 (mode, fn) { 
    return Excel.run(function (ctx) { 
     ctx.workbook.application.calculate(mode); 
     var before = performance.now(); 
     return ctx.sync().then(function() { 
      var after = performance.now(); 
      var t = after - before; 
      document.getElementById("b").value += 'inside: ' + t + '\n'; 
      fn(t); 
     }) 
    }) 
} 

function calculate2 (mode) { 
    return new Promise(function (resolve, reject) { 
     return Excel.run(function (ctx) { 
      ctx.workbook.application.calculate(mode); 
      var before = performance.now(); 
      return ctx.sync().then(function() { 
       var after = performance.now(); 
       var t = after - before; 
       document.getElementById("b").value += 'inside: ' + t + '\n'; 
       resolve(t); }) 
      }) 
    }) 
} 

下面是測試:

function test() { 
    var a = []; 
    var pm = new OfficeExtension.Promise(function(resolve, reject) { resolve (null); }); 

    pm 
     .then(function() { return calculate1('FullRebuild', function (t) { 
      a.push(t); }); }) 
     .then(function() { return calculate1('FullRebuild', function (t) { 
      a.push(t); }); }) 
     .then(function() { return calculate2('FullRebuild').then(function (result) { 
      a.push(result); }); }) 
     .then(function() { return calculate2('FullRebuild').then(function (result) { 
      a.push(result); }); }) 
     .then(function() { 
      document.getElementById("b").value += a.toString() + '\n'; }); 
} 

我猜calculate1使用callback,而calculate2使用promise。有誰能告訴我哪種方式更好?

此外,是fn(t)(或resolve(t))在正確的地方,或者我應該包裝在另一個then

PS:Excel.runctx.sync()JavaScript API for Office的功能;他們都回報了一個承諾。

+2

乘坐看看這個http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it。您正在混合回調和承諾。我建議讓計算解決't',這是你想要的。 – Putty

+0

我最初的回調方式沒有錯(錯誤信息是由於其他原因)。請看我的更新... – SoftTimur

+0

你更喜歡的是「更好」。 – zerkms

回答

1

calculate1()是承諾和回調的錯誤混合,calculate2()正在參展Explicit Promise Construction Antipattern

這裏是你如何正確使用的承諾沒有任何多餘的浪費:

function calculate1 (mode) { 
    return Excel.run(function (ctx) { 
     ctx.workbook.application.calculate(mode); 
     var before = performance.now(); 

     return ctx.sync().then(function() { 
      var after = performance.now(); 
      var t = after - before; 
      document.getElementById("b").value += 'inside: ' + t + '\n'; 

      return t; 
     }); 
    }); 
} 

然後你就可以消費它這樣。注意,它使用比你嘗試的功能相當少:

return calculate1('FullRebuild') 
    .then(function(res) { 
     a.push(res); 
     return calculate1('FullRebuild'); 
    }) 
    .then(function(res) { 
     a.push(res); 
     return calculate1('FullRebuild'); 
    }) 
    .then(function(res) { 
     a.push(res); 
     return calculate1('FullRebuild'); 
    }) 
    .then(function(res) { 
     a.push(res); 
     document.getElementById("b").value += a.toString() + '\n'; 
    }); 
+0

'Promise'構造函數實際上可能需要包裝'Excel.run'。儘管如此,爲了避免反模式,它應該看起來像'resolve(ctx.sync()。then(...))' – Bergi

+0

代碼工作...我看到'resolve(t)'常常用於傳遞值'then'中的'function(res){...}'。然而,你直接使用'return t',爲什麼它可能以及它是如何被調用的呢? – SoftTimur

+1

@SoftTimur需要'resolve()'函數來創建非承諾代碼的承諾。由於'Excel.run()'和'ctx.sync()'是基於promise的,所以這裏不需要'resolve()'。這個工作的原因是'then()'返回一個承諾,該承諾解析爲'then()'返回的值。 'then()'中返回一個promise,'then()'返回的promise將會「採納」那個promise和它的解析或拒絕。 – JLRishe

0

如果你想要一個異步函數返回值 - 而不是傳遞迴調到它 - 返回值需要被包裹在一個承諾和決心像在你的第二個例子中。

承諾的方便之處在於它避免了回調嵌套 - >當回調需要另一個回調... 和錯誤的方式傳播到最近Promise.catch()塊

function calculate2 (mode) { 
    return new Promise(function (resolve, reject) { 

     Excel.run(function (ctx) {  
      ctx.workbook.application.calculate(mode); 
      var before = performance.now(); 

      ctx.sync().then(function() { 
       var after = performance.now(); 
       var t = after - before; 

       resolve(t); 
      }) 
     }) 
    }) 
} 

calculate2('FullRebuild') 
    .then(function (t) { 
     document.getElementById("b").value += 'inside: ' + t + '\n'; 
     // the return value of a promise resolver is wrapped in a promise too 
     // and the value of t will be available as parameter of the following .then(funtion(t)) block 
     return t; 
}) 
.catch(function(err) { 
    // Addresses potential async errors raised since calling calculate2() 
});