Расовые условия с использованием Office.js в Excel

1

Я встречаю какое-то состояние гонки в следующем коде, где я пытаюсь написать ответ 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);
    }
}
Теги:
async-await
office-js

1 ответ

0
Лучший ответ

Проблема в том, что вы не ожидаете завершения client.get. Это означает, что [некоторое время], Excel.run завершит и "собирает мусор" (ish) некоторые из объектов (range) до выполнения обратного вызова внутри client.get.

Вы можете решить проблему несколькими способами:

  1. Excel.run вызов веб-службы перед выполнением Excel.run. В вашем примере здесь (что может быть нереалистичным для многих других сценариев, но оно здесь), вы фактически не полагаетесь ни на что из документа, прежде чем выполнять свой веб-вызов. В этом случае вам вообще не нужно находиться внутри Excel.run, вы можете иметь Excel.run, Excel.run частью обратного вызова в вызове веб-службы.

  2. Оберните свой веб-сервисный вызов в 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); }); } } 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: https://leanpub.com/buildingofficeaddins/. Я вставляю несколько скриншотов из некоторых соответствующих материалов.

Кстати, я должен сказать, что получение выбора является одним из нескольких случаев, когда вы не хотите задерживать sync, так как вы хотите захватить мимолетный выбор по времени, а не то, что станет выбором через X секунд, как только веб-вызов будет успешным. Таким образом, это один из немногих случаев, когда вам может понадобиться вставить дополнительный await context.sync() даже если вам это не требуется. Дополнительную информацию см. В разделе "5.8.2: Когда синхронизировать" в книге.

=====

Продвижение API:

Изображение 174551

=====

От приблизительно обещаний:

Изображение 174551

=====

В разделе сведений о реализации:

Изображение 174551

  • 0
    Не могли бы вы предоставить эти выдержки в виде цитируемого текста вместо картин, пожалуйста?
  • 0
    Вам не нужно (и не следует) использовать new Promise конструктор new Promise для «обещания» вызова jQuery ajax. Просто return Promise.resolve($.ajax(…)).then(…, …) - jQuery уже возвращает таблицу (вы могли бы даже await отложенную jQuery напрямую)
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню