使用Excel.run()在Office.js中链接承诺

我正在使用新的office.js。 我正在使用返回承诺的Excel.runfunction。 我有一个关于图书馆实施的承诺模式的问题。

样品都显示这种模式

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()之外的()所以,模式似乎是促进嵌套函数调用,这是承诺应该消除。

我想要做的是通过像这样链接几个呼叫:

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

这可能吗?

一般来说, Excel.run的目的是针对最终自动清理的操作系统。 也就是说, Excel.run创build一个上下文,运行你的操作,然后清理所有分配的主机对象。

这就是说,正如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创build了工作表对象,但是在外部使用它。

如果你有一个Range对象,它会变得有点棘手。 与工作表不同,不同于工作表的范围没有持久性ID(它们怎么可能?基本上所有可能的单元组合都有无数的排列)。 相反,在Excel.run期间,我们自动创build持久指针,指向由Excel调整并保持跟踪的支持Range对象。 当Excel.run内部的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集合来退出跟踪对象清理。 然而,在这样做的时候,你最后要自己去清理 – 而且你需要格外小心,记住不仅要清除成功,还要清除失败。 否则,你本质上是创build一个内存泄漏,将不断减慢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之后使用对象。 您只需要为需要“跟踪”的任何对象负责内存pipe理。 在上面的例子中,没有理由去完成这个工作,因为你可以在Excel.run里面有相同的代码(记住,你也可以 Excel.run的批处理内链接promise,不需要在外面做这个)。 但是,如果你有一个场景,例如,你有一个需要频繁运行的计时器作业(例如,更新股票代码),或者你想创build一个button与一个特定的对象onclick处理程序等上面的技巧可以让你创buildExcel.run里面的对象,然后在它之外使用它们。

PS :关于需要嵌套的模式:确实,如果您需要在ctx.sync()中链接ctx.sync()调用,最终将会有一层嵌套 – 但只是一个额外的层。 在内部,你仍然可以链接你的承诺,没有callback金字塔。 例如,:

 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的目标是pipe理trackedObjects的函数,它被传入英寸在承诺链接Excel.Run后,你将不得不pipe理跟踪自己,从而击败了Excel.Run的目的。

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