使用 debounce 监听多个范围的值变化
Listen to the value change of multi ranges with debounce
目前我使用如下代码监听Sheet1!A1:B2
的变化:
function addEventHandler() {
Office.context.document.bindings.addFromNamedItemAsync("Sheet1!A1:B2", "matrix", { id: "myBind" }, function (asyncResult) {
Office.select("binding#myBind").addHandlerAsync(Office.EventType.BindingDataChanged, onBindingDataChanged2016);
})
}
function onBindingDataChanged2016(eventArgs) {
Excel.run(function (ctx) {
var foundBinding = ctx.workbook.bindings.getItem(eventArgs.binding.id);
var myRange = foundBinding.getRange();
myRange.load(["address", 'values']);
return ctx.sync().then(function () {
console.log(JSON.stringify({ "address": myRange.address, "value": myRange.values }));
// costly reaction
})
})
}
因为我对改变的反应是相当代价高昂,所以我只想在确实有必要时才进行改变。我有两个问题:
1) 如果我想听多音域,是否可以只为"Sheet1!A1:B2, Sheet1!A9:B10, Sheet1!A100:B120"
定义一个监听器?我必须为每个范围添加一个处理程序吗?
2)是否可以表达I listen only to the change of VALUES
,而不是格式等?
可选问题:
是否可以在某处指定 去抖动?例如,
我们用0
初始化一个时钟
如果监听器被触发,我们记录变化的binding id
,并将时钟设置为0
当时钟到达1 second
时(即已经安静1秒),我们对所有记录的变化做出反应(即加载所有变化的范围并承担代价高昂的反应)
Office JS 没有允许监听多个绑定的事件处理程序,就像 HTML 无法同时监听多个 DOM 节点一样。即使有这样一个 API 函数,它也必须在内部创建多个侦听器,因此您不会获得任何性能优势。
不幸的是,no event type available 区分数字更改和格式更改。
然而,您可以去抖动以获益匪浅!
假设您有一些功能 debounce(func, wait, immediate = false)
可用。*
只需将 on change 函数包装在 debounce()
调用中。
function addEventHandler() {
Office.context.document.bindings.addFromNamedItemAsync("Sheet1!A1:B2", "matrix", { id: "myBind" }, function (asyncResult) {
Office.select("binding#myBind").addHandlerAsync(
Office.EventType.BindingDataChanged,
debounce(onBindingDataChanged2016, 5000)
);
})
}
这将消除对 onBindingDataChanged2016
的所有调用。如果您想对每个特定的绑定 ID 进行去抖动,事情就会变得有点棘手。您必须创建自己的去抖功能,它会跟踪每个绑定 ID 的超时:
function debounceByBindingId(func, wait, immediate) {
var timeouts = {};
return function() {
var context = this, args = arguments;
var eventArgs = arguments[0];
var bindingId = eventArgs.binding.id;
var later = function() {
timeouts[bindingId] = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeouts[bindingId]);
timeouts[bindingId] = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
*一如既往地在JavaScript土地上,有太多的选择可供选择!
目前我使用如下代码监听Sheet1!A1:B2
的变化:
function addEventHandler() {
Office.context.document.bindings.addFromNamedItemAsync("Sheet1!A1:B2", "matrix", { id: "myBind" }, function (asyncResult) {
Office.select("binding#myBind").addHandlerAsync(Office.EventType.BindingDataChanged, onBindingDataChanged2016);
})
}
function onBindingDataChanged2016(eventArgs) {
Excel.run(function (ctx) {
var foundBinding = ctx.workbook.bindings.getItem(eventArgs.binding.id);
var myRange = foundBinding.getRange();
myRange.load(["address", 'values']);
return ctx.sync().then(function () {
console.log(JSON.stringify({ "address": myRange.address, "value": myRange.values }));
// costly reaction
})
})
}
因为我对改变的反应是相当代价高昂,所以我只想在确实有必要时才进行改变。我有两个问题:
1) 如果我想听多音域,是否可以只为"Sheet1!A1:B2, Sheet1!A9:B10, Sheet1!A100:B120"
定义一个监听器?我必须为每个范围添加一个处理程序吗?
2)是否可以表达I listen only to the change of VALUES
,而不是格式等?
可选问题:
是否可以在某处指定 去抖动?例如,
我们用
0
初始化一个时钟
如果监听器被触发,我们记录变化的
binding id
,并将时钟设置为0
当时钟到达
1 second
时(即已经安静1秒),我们对所有记录的变化做出反应(即加载所有变化的范围并承担代价高昂的反应)
Office JS 没有允许监听多个绑定的事件处理程序,就像 HTML 无法同时监听多个 DOM 节点一样。即使有这样一个 API 函数,它也必须在内部创建多个侦听器,因此您不会获得任何性能优势。
不幸的是,no event type available 区分数字更改和格式更改。
然而,您可以去抖动以获益匪浅!
假设您有一些功能 debounce(func, wait, immediate = false)
可用。*
只需将 on change 函数包装在 debounce()
调用中。
function addEventHandler() {
Office.context.document.bindings.addFromNamedItemAsync("Sheet1!A1:B2", "matrix", { id: "myBind" }, function (asyncResult) {
Office.select("binding#myBind").addHandlerAsync(
Office.EventType.BindingDataChanged,
debounce(onBindingDataChanged2016, 5000)
);
})
}
这将消除对 onBindingDataChanged2016
的所有调用。如果您想对每个特定的绑定 ID 进行去抖动,事情就会变得有点棘手。您必须创建自己的去抖功能,它会跟踪每个绑定 ID 的超时:
function debounceByBindingId(func, wait, immediate) {
var timeouts = {};
return function() {
var context = this, args = arguments;
var eventArgs = arguments[0];
var bindingId = eventArgs.binding.id;
var later = function() {
timeouts[bindingId] = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeouts[bindingId]);
timeouts[bindingId] = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
*一如既往地在JavaScript土地上,有太多的选择可供选择!