在 Excel 中使用 Office.js 的竞争条件
Race conditions using Office.js in Excel
我在尝试将 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
将完成并且 "garbage-collect"(ish) 一些对象 (range
) 在执行 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:
=====
关于Promises:
=====
来自实施细节部分:
我在尝试将 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
将完成并且 "garbage-collect"(ish) 一些对象 (range
) 在执行 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:
=====
关于Promises:
=====
来自实施细节部分: