Создание цепочки обещаний в Office.js с помощью Excel.run()

Я работаю с новым office.js. Я использую функцию Excel.run, которая возвращает обещание. У меня есть вопрос о шаблоне обещаний, реализованном библиотекой.

Все образцы показывают эту модель

Excel.run( function (ctx) {

  //set up something

  return ctx.sync().then (function () {
    //call another function somewhere to chain operations
  });

}).then ( function () {
  //do something else if you want
}).catch (function (error) {
  handle errors
});

Проблема заключается в том, что ctx.sync(). Then() содержится в Excel.run(). Как он представлен, вы не можете связывать обещания в соответствии со спецификацией обещаний, потому что вы теряете объект контекста, если пытаетесь обрабатывать then() вне Excel.run() Итак, шаблон, по-видимому, способствует вызовам вложенных функций, что и должно исключать обещания.

То, что я хочу сделать, это объединить несколько вызовов в цепочку следующим образом:

Excel.run( function (ctx) {
  return ctx.sync();
}).then ( function (ctx) {
  return ctx.sync();
}).then ( function (ctx) {
  return ctx.sync();
}).then ( function (ctx) {
  return ctx.sync();
}).catch (function (error) {

});

Это возможно?

2 ответа

В общем, цель Excel.run для последовательной операции против OM с автоматической очисткой в ​​конце. То есть, Excel.run создает контекст, запускает вашу операцию, а затем очищает любые объекты хоста, которые были выделены.

При этом, как сказал Габ Ройер, вы можете раздавать предметы. Более того, каждый объект Excel имеет обратный указатель на свой "контекст" через свойство ".context". Так, например, вы можете сделать это:

Excel.run(function (ctx) {
    var worksheet = ctx.workbook.worksheets.getActiveWorksheet();
    return ctx.sync(worksheet);
}).then(function(worksheet) {
    worksheet.name = "Test"
    return worksheet.context.sync();
}).catch(function(e) {
    console.log(e)  
});

Как вы можете видеть, в приведенном выше коде вы создали объект листа внутри Excel.run, но используют его снаружи.

Если у вас есть что-то вроде объекта Range, он становится немного сложнее. Диапазоны, в отличие от рабочих таблиц, не имеют постоянных идентификаторов (как они могли? Существует по существу бесчисленное количество перестановок всех возможных комбинаций ячеек). Вместо этого во время Excel.runМы автоматически создаем постоянные указатели на базовые объекты Range, которые корректируются и отслеживаются Excel. Когда партия внутри Excel.run В завершение мы говорим хозяину уничтожить эти ссылки. Так что, если у вас был такой код:

Excel.run(function (ctx) {
    var range = ctx.workbook.getSelectedRange();
    return ctx.sync(range);
}).then(function(range) {
    range.format.fill.color = "red";
    return ctx.sync();
}).catch(function(e) {
    console.log(e)  
})

Это приведет к ошибке "InvalidObjectPath".

Однако вы можете отказаться от очистки отслеживаемого объекта, добавив объект вручную в ctx.trackedObjects коллекция. Делая это, однако, вы берете на себя обязательство убирать в конце - и вам нужно быть очень осторожным, помнить, чтобы убирать не только на успехе, но и на неудаче. В противном случае вы по существу создаете утечку памяти, которая будет замедлять работу хост-приложения Excel.

var range;
Excel.run(function (ctx) {
    range = ctx.workbook.getSelectedRange();
    ctx.trackedObjects.add(range);
    return ctx.sync(range);
}).then(function(range) {
    range.format.fill.color = "red";
    return range.context.sync();
}).then(function() {
    // Attempt to clean up any orphaned references
    range.context.trackedObjects.remove(range);
    range.context.sync(); // don't need to await it, since it's just the final cleanup call
}).catch(function(e) {
    console.log(e);
})

Короче говоря: это, безусловно, выполнимо, и вы можете использовать объекты после Excel.run, Вам просто нужно будет отвечать за управление памятью для любых объектов, которые требуют "отслеживания". В приведенном выше примере нет смысла проходить это усилие, так как вы могли бы иметь тот же код внутри Excel.run (помните, что вы также можете связывать обещания внутри пакета внутри Excel.run - не нужно делать это снаружи). Но если у вас есть сценарий, где, скажем, у вас есть задание таймера, которое нужно запускать время от времени (например, для обновления биржевого индикатора), или вы хотите создать кнопку с обработчиком onclick для определенного объекта и т. Д. Приведенная выше методика позволит вам создавать объекты внутри Excel.run, а затем использовать их вне его.

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

Excel.run(function (ctx) {
    var range = ctx.workbook.worksheets.getActiveWorksheet().getRange("A1:C3");
    range.load("values");
    return ctx.sync()
        .then(function () {
            // Some set of actions against the OM, now that the "values"
            // property has been loaded and can be read from the "range" object.
        })
        .then(ctx.sync)
        .then(function () {
            // Another set of actions against the OM, presumably after doing
            // another load-requiring operation (otherwise could have
            // been part of the same .then as above)
        })
        .then(ctx.sync)
        .then(function() {
            // One final set of actions
        });     
}).catch(function(error) {
    console.log("Error: " + error);
});

Хотя это было бы возможно, так как Excel.RequestContext.sync принимает сквозное значение, цель Excel.run должен управлять trackedObjects для функции, в которую это передано. В обещаниях, связанных после Excel.Run вам придется управлять trackedObjects самостоятельно, что приведет к поражению цели Excel.Run.

Я бы предложил либо объявить вашу функцию за пределами Excel.Run если вам не нравится добавленный отступ или создание собственного RequestContext объект.

Другие вопросы по тегам