我正在使用新的office.js。我正在使用返回promise的Excel.run功能。我对库实现的promises模式有疑问。
样本都显示此模式
<div class="sonar-wrapper">
<div class="square">
<div></div>
<a href="#">Click</a>
</div>
</div>
问题是Excel.run()中包含的ctx.sync()。then() 它的呈现方式,你不能按照promises规范链接promises,因为如果你尝试处理Excel.run()之外的then(),你将失去上下文对象 因此,该模式似乎是在促进嵌套函数调用,这是承诺应该消除的。
我想要做的是通过像这样的链接来排序几个调用:
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
});
这可能吗?
答案 0 :(得分:9)
通常,Excel.run
的目的是针对OM的顺序操作,最后自动清理。也就是说,Excel.run
创建一个上下文,运行您的操作,然后清除已分配的任何主机对象。
话虽如此,正如Gab Royer所说,可以传递对象。而且,每个Excel对象都有一个指向其&#34; context&#34;的后向指针。通过&#34; .context&#34;属性。例如,您可以这样做:
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)
})
它会遇到一个&#34; InvalidObjectPath&#34;错误。
但是,您可以通过手动将对象添加到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
之后使用对象。您只需要对需要跟踪&#34;的任何对象负责内存管理。在上面的示例中,没有 reason 来完成这项工作,因为您可以在Excel.run中使用相同的代码(请记住,您可以链接承诺 / em> Excel.run中的批处理 - 不需要在外部执行此操作)。但是,如果您有一个场景,比如说,您有一个需要经常运行的计时器作业(例如,更新股票报价器),或者您想要为特定对象创建一个带有onclick处理程序的按钮,等等上面的技术将允许您在Excel.run中创建对象,然后在它之外使用它们。
PS :关于需要嵌套的模式:如果你需要在Excel.run中链接ctx.sync()
调用,你最终会得到一层嵌套 - - 但只是一个单额外的图层。在内部,您仍然可以在没有回调金字塔的情况下链接您的承诺。 。E.g,:
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);
});
答案 1 :(得分:1)
虽然这是可能的,因为Excel.RequestContext.sync
接受传递值,Excel.run
的目标是管理它传入的函数的trackedObjects。在{{1}之后链接的promises中你必须自己管理trackedObjects,因此无法实现Excel.Run的目的。
如果您不喜欢添加的缩进,或者创建自己的Excel.Run
对象,我建议您在Excel.Run
之外声明您的功能。