Best way to write loops with promises (ctx.sync) in JavaScript API for Office

后端 未结 2 1785
生来不讨喜
生来不讨喜 2020-12-16 08:06

There are many threads that discuss about guaranteeing execution order of promises in loops. I would like to know what is the best practice in JavaScript API for Office Add-

2条回答
  •  鱼传尺愫
    2020-12-16 08:27

    Because Excel.run returns a Promise, you can chain it with a .then and guarantee order. I.e.,

    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(); ... })
        });
    

    That being said... this would be pretty dang inefficient. A much better approach would be to load all the objects you need in one batch, creating only one network roundtrip (especially important with Excel Online... but noticeable even on the Desktop):

    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

    If, as per comment, you do end up needing to do separate tasks that depend on each other and that each require a roundtrip, and hence do need to be sequenced via chaining Excel.run, I would recommend something as follows:

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

    ~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT

提交回复
热议问题