在Excel中使用Office.js的竞争条件

时间:2017-06-14 01:37:49

标签: javascript async-await office-js

我在以下代码中遇到某种竞争条件,我试图将HTTP请求的响应写入活动单元格。我已经阅读了" InvalidObjectPath"的一些可能的解决方案。来自Office.js的错误(我特意使用ScriptLab),但我不认为我试图在多个上下文中使用任何东西。

当前行为有时会起作用,但有时候什么都不会写入单元格。

var counter = 0;
$("#run").click(run);
async function run() {
    try {

        await Excel.run(async (ctx) => {
            var user; 
            const sUrl = "https://jsonplaceholder.typicode.com/users/1";
            var client = new HttpClient();
            var range = ctx.workbook.getSelectedRange(); 
            counter++;
            client.get(sUrl, function (response) {
                var obj = JSON.parse(response);
                user = obj.username;
                range.values = [[user + counter]];
                ctx.sync();
            });
            await ctx.sync();
        });
    }
    catch (error) {
        OfficeHelpers.UI.notify(error);
        OfficeHelpers.Utilities.log(error);
    }
}

var HttpClient = function() {
    this.get = function(aUrl, aCallback) {
        var anHttpRequest = new XMLHttpRequest();
        anHttpRequest.onreadystatechange = function() { 
            if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200)
                aCallback(anHttpRequest.responseText);
        }
        anHttpRequest.open( "GET", aUrl, true );            
        anHttpRequest.send(null);
    }
}

1 个答案:

答案 0 :(得分:0)

问题是您没有等待client.get的完成。这意味着[某些时候],Excel.run将完成并且“垃圾收集”(ish)执行range内部回调之前的一些对象(client.get

您可以通过多种方式解决问题:

  1. 在执行Excel.run之前,请先调用Web服务。在这里的示例中(对于许多其他场景可能不太现实,但它就在这里),在进行Web调用之前,您实际上并不依赖文档中的任何内容。在这种情况下,根本不需要在Excel.run内,您可以让Excel.run成为Web服务调用回调的一部分。

  2. 将您的网络服务电话包含在承诺中,以便等待它。这样的事情: var HttpClient = function() { this.get = function(aUrl) { return new Promise(function (resolve, reject) { var anHttpRequest = new XMLHttpRequest(); anHttpRequest.onreadystatechange = function () { if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200) { resolve(anHttpRequest.responseText); } else { reject(anHttpRequest.statusText); } } anHttpRequest.open("GET", aUrl, true); anHttpRequest.send(null); }); } }

  3. 我在一本书中描述了这两种方法(以及更多......),我一直在撰写有关使用Office.js构建Office加载项的书:https://leanpub.com/buildingofficeaddins/。我正在粘贴一些相关书籍内容的下面几张截图。

    顺便说一句,我应该说,当你不想延迟sync时,获取选择是少数几次之一,因为你想要捕捉稍纵即逝的时间点选择而不是一旦网络呼叫成功,从现在起成为X秒的选择。因此,即使您在技术上不需要,也可能需要插入额外await context.sync()的少数情况之一。有关详细信息,请参阅本书中的“ 5.8.2:何时同步”。

    =====

    宣传API

    Promisifying an API

    =====

    关于Promises

    From about Promises

    =====

    从实施细节部分:

    From the implementation-details section