2016-06-18 28 views
2

有許多討論關於保證循環中promise的執行順序的線程。我想知道什麼是Office API加載項的JavaScript API的最佳做法。大多數時候,有關的承諾是ctx.sync()用於在Office API的API中編寫帶有承諾(ctx.sync)的循環的最佳方法

下面是一個打印Excel範圍列表地址的代碼片段。測試表明它很好地尊重了Excel範圍的順序。但問題是是否以及如何保證的執行順序?

function loadAll() { 
    var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
    var sheet = "Sheet1"; 
    for (var i = 0; i < ranges.length; i++) { 
     loadRange(ranges[i], sheet);   
    } 
} 

function loadRange (range, sheet) { 
    Excel.run(function (ctx) { 
     var r = ctx.workbook.worksheets.getItem(sheet).getRange(range); 
     r.load('address'); 
     return ctx.sync().then(function() { 
      console.log(r.address); 
     }); 
    }); 
} 

任何人都可以幫忙嗎?

+0

爲什麼您關心執行順序?什麼'Excel.run'返回? – Bergi

+0

Excel.run()執行一個在Excel對象模型上執行操作的批處理腳本。批處理命令包括本地JavaScript代理對象和sync()方法的定義,這些方法同步本地和Excel對象之間的狀態並承諾解析。 ([overview](http://dev.office.com/docs/add-ins/excel/excel-add-ins-javascript-programming-overview)) – SoftTimur

+0

我關心執行順序...因爲我要去到一些複雜的東西而不是'loadRange'或'console.log(r.address)',它們依賴於順序... – SoftTimur

回答

3

因爲Excel.run返回承諾,您可以鏈接它與.then並保證順序。即,

Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    .then(function() { 
     return Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    }) 
    .then(function() { 
     return Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    }); 

這就是說...這將是相當沒有效率。更好的方法是先裝載您在一個批處理需要的所有對象,只創建一個網絡往返(與Excel在線尤爲重要......但明顯甚至在桌面上):

function loadAll() { 
    Excel.run(function(ctx) { 
     var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
     var sheet = "Sheet1"; 

     var loadedRanges = []; 
     for (var i = 0; i < ranges.length; i++) { 
      var r = ctx.workbook.worksheets.getItem(sheet).getRange(ranges[i]); 
      r.load('address'); 
      loadedRange.push(r); 
     } 

     return ctx.sync() 
      .then(function() { 
       for (var i = 0; i < loadedRanges.length; i++) { 
        console.log(loadedRanges[i].address); 
       } 
      }); 
    }); 
} 

UPDATE

如果按照評論,你最終需要做的是互相依賴的,並且每一個需要往返,因此就需要通過鏈接Excel.run進行測序獨立的任務,我會推薦一些如下:

function loadAll() { 
    var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
    var sheet = "Sheet1"; 

    // Create a starter promise object 
    var promise = new OfficeExtension.Promise(function(resolve, reject) { resolve (null); }); 

    for (var i = 0; i < ranges.length; i++) { 
     // Create a closure over i, since it's used inside a function that won't be immediately executed. 
     (function(i) { 
      // Chain the promise by appending to it: 
      promise = promise.then(function() { 
       return loadRange(ranges[i], sheet); 
      }) 
     })(i);  
    } 
} 

function loadRange (range, sheet) { 
    return Excel.run(function (ctx) { 
     var r = ctx.workbook.worksheets.getItem(sheet).getRange(range); 
     r.load('address'); 
     return ctx.sync().then(function() { 
      console.log(r.address); 
     }); 
    }); 
} 

〜Office Extensibility團隊開發人員Michael Zlatkovsky,MSFT

+0

加載地址不是一個好例子;實際上,我正在逐步操縱單元格值和公式。我需要通過一個循環鏈接'then'來實現串行異步調用:當前'then'中的單元格值和公式取決於之前的'then'中的操作;預計會創造網絡往返。在這種情況下,你是否建議遞歸或'Array.prototype.reduce()'或其他? – SoftTimur

+0

查看我的更新回答 –

+0

謝謝你這個很好的結構,邁克爾......另外,我意識到如果我們在'loadAll'結尾添加'return promise',我們可以在'loadAll'後面加上'then',例如。 ,'globalPromise.then(f1)。then(f2).then(loadAll).then(f4)...'。 – SoftTimur