我在以下代码中遇到某种竞争状况,试图将HTTP请求的响应写入活动单元格。我已经阅读了Office.js中“ InvalidObjectPath”错误的一些可能的解决方案(我正在专门使用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);
}
}
最佳答案
问题是您不等待client.get
的完成。这意味着[有时],Excel.run
将在执行range
内部的回调之前完成并“垃圾回收”(ish)某些对象(client.get
)。
您可以通过多种方式解决此问题:
在执行Excel.run
之前,请先调用Web服务。在此处的示例中(对于许多其他情况可能并不现实,但在此处),在进行网络调用之前,您实际上根本没有依赖文档中的任何内容。在那种情况下,根本不需要放在Excel.run
内,您可以让Excel.run
成为Web服务调用中的回调的一部分。
将您的Web服务呼叫包装在Promise中,以便可以等待。像这样: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); }); }}
在我一直在写的有关使用Office.js构建Office加载项的书中,我描述了这两种方法(以及更多...):https://leanpub.com/buildingofficeaddins/。我在下面粘贴了一些相关书籍内容中的一些屏幕截图。
顺便说一句,我应该说,当您不想延迟sync
时,获得选择只是少数几次,因为您想捕获短暂的时间点选择,而不是成为选择X的时间从现在开始,一旦网络通话成功。因此,这是少数情况下您可能想要插入一个额外的await context.sync()
的情况之一,即使您在技术上不需要它。有关更多信息,请参见本书中的“ 5.8.2:何时同步”。
=====
宣传API:
=====
关于承诺:
=====
从实施细节部分: