6

我正在使用新的 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
});

问题是 Excel.run() 中包含的 ctx.sync().then() 以它的呈现方式,你不能按照 Promise 规范链接 Promise,因为如果你尝试处理Excel.run() 之外的 then() 因此,该模式似乎在促进嵌套函数调用,而这是应该消除的承诺。

我想要做的是通过这样的链接将几个调用排序在一起:

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) {

});

这可能吗?

4

2 回答 2

11

通常, 的目的Excel.run是对 OM 进行顺序操作,并在最后进行自动清理。也就是说,Excel.run创建一个上下文,运行您的操作,然后清理任何已分配的主机对象。

话虽如此,正如 Gab Royer 所提到的,您可以将对象传递出去。此外,每个 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 对象的东西,它会变得有点棘手。范围,与工作表不同,没有持久的 ID(他们怎么可能?基本上所有可能的单元格组合有无数种排列)。相反,在 期间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);
});
于 2015-09-25T19:04:36.450 回答
1

虽然这是可能的,因为Excel.RequestContext.sync它接受了一个传递值,但目标Excel.run是管理它传入的函数的 trackedObjects。在Excel.Run你必须自己管理 trackedObjects 之后链接的 Promise 中,因此违背了 Excel.Run 的目的.

Excel.Run如果您不喜欢添加的缩进,我建议您在外部声明您的函数,或者创建您自己的RequestContext对象。

于 2015-09-25T18:21:21.517 回答