循环中的异步回调
Asynchronous callbacks in a loop
我有一个变量 oldBindings
,它记录了 Excel table 的所有现有绑定。我已经基于 oldBindings
构建了 BindingDataChanged
个监听器。所以当 newBindings
出现时,我需要删除所有链接到 oldBindings
的旧监听器并添加基于 newBindings
的新监听器。目前,我已经编写了以下代码:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function () {
addEventHandlers(newBindings)
})
}
function removeEventHandlers(oldBindings, cb) {
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {});
});
}
cb()
}
由于 removeHandlerAsync
和 releaseByIdAsync
是用 callback
而不是 promise
构建的,我需要用 callback
来组织整个代码。有两件事我不确定:
1) 在 removeEventHandlers
中,cb()
会在移除所有侦听器后始终执行吗?我如何确保?
2) 我是否必须将 addEventHandlers
作为 removeEventHandlers
的 callback
来确保它们的执行顺序?
1) in removeEventHandlers
, will cb() ALWAYS be executed after the removal of all the listeners?
没有。它将在删除 启动 之后调用。但是如果移除是异步的,它可能会在移除完成之前被调用。
2) Do I have to make addEventHandlers
as a callback of removeEventHandlers
to ensure their execution order?
是的,但不是你的方式。你拥有的方式就像在做
removeEventHandlers();
addEventHandlers();
因为您在 removeEventHandlers
结束时调用了 cb
,没有等待任何事情完成。
As removeHandlerAsync
and releaseByIdAsync
are built with callback
rather than promise
, I need to organise the whole code with callback
.
或者您可以为自己提供它们的 Promise 版本。稍后会详细介绍。
使用非 Promise 回调方法,以确保您在完成所有工作后从 removeEventHandlers
调用 cb
,请记住您期望的回调次数并等待直到获得那么多在调用 cb
:
之前
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings, cb) {
var waitingFor = oldBindings.length;
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {
if (--waitingFor == 0) {
cb();
}
});
});
}
}
但是任何时候你有一个回调系统,你可以承诺它:
function removeHandlerPromise(obj, eventType) {
return new Promise(function(resolve, reject) {
obj.removeHandlerAsync(eventType, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
function releaseByIdPromise(obj, value) {
return new Promise(function(resolve, reject) {
obj.releaseByIdAsync(value, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
那么你可以这样做:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return removeHandlerPromise(Office.select("binding#"+binding), Office.EventType.BindingDataChanged).then(function() {
return releaseByIdPromise(Office.context.document.bindings, binding);
});
});
}
或者你可以为任何 returns 和 AsyncResult
:
的异步操作给自己一个通用的 Promise-ifier
function promisify(obj, method) {
var args = Array.prototype.slice.call(arguments, 2);
return new Promise(function(resolve, reject) {
args.push(function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
obj[method].apply(obj, args);
});
}
那么你可以这样做:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return promisify(Office.select("binding#"+binding), "removeHandlerAsync", Office.EventType.BindingDataChanged).then(function() {
return promisify(Office.context.document.bindings, "releaseByIdAsync", binding);
});
});
}
我有一个变量 oldBindings
,它记录了 Excel table 的所有现有绑定。我已经基于 oldBindings
构建了 BindingDataChanged
个监听器。所以当 newBindings
出现时,我需要删除所有链接到 oldBindings
的旧监听器并添加基于 newBindings
的新监听器。目前,我已经编写了以下代码:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function () {
addEventHandlers(newBindings)
})
}
function removeEventHandlers(oldBindings, cb) {
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {});
});
}
cb()
}
由于 removeHandlerAsync
和 releaseByIdAsync
是用 callback
而不是 promise
构建的,我需要用 callback
来组织整个代码。有两件事我不确定:
1) 在 removeEventHandlers
中,cb()
会在移除所有侦听器后始终执行吗?我如何确保?
2) 我是否必须将 addEventHandlers
作为 removeEventHandlers
的 callback
来确保它们的执行顺序?
1) in
removeEventHandlers
, will cb() ALWAYS be executed after the removal of all the listeners?
没有。它将在删除 启动 之后调用。但是如果移除是异步的,它可能会在移除完成之前被调用。
2) Do I have to make
addEventHandlers
as a callback ofremoveEventHandlers
to ensure their execution order?
是的,但不是你的方式。你拥有的方式就像在做
removeEventHandlers();
addEventHandlers();
因为您在 removeEventHandlers
结束时调用了 cb
,没有等待任何事情完成。
As
removeHandlerAsync
andreleaseByIdAsync
are built withcallback
rather thanpromise
, I need to organise the whole code withcallback
.
或者您可以为自己提供它们的 Promise 版本。稍后会详细介绍。
使用非 Promise 回调方法,以确保您在完成所有工作后从 removeEventHandlers
调用 cb
,请记住您期望的回调次数并等待直到获得那么多在调用 cb
:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings, function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings, cb) {
var waitingFor = oldBindings.length;
for (var i = 0; i < oldBindings.length; i++) {
Office.select("binding#"+oldBindings[i]).removeHandlerAsync(Office.EventType.BindingDataChanged, function (asyncResult) {
Office.context.document.bindings.releaseByIdAsync(oldBindings[i], function () {
if (--waitingFor == 0) {
cb();
}
});
});
}
}
但是任何时候你有一个回调系统,你可以承诺它:
function removeHandlerPromise(obj, eventType) {
return new Promise(function(resolve, reject) {
obj.removeHandlerAsync(eventType, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
function releaseByIdPromise(obj, value) {
return new Promise(function(resolve, reject) {
obj.releaseByIdAsync(value, function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
});
}
那么你可以这样做:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return removeHandlerPromise(Office.select("binding#"+binding), Office.EventType.BindingDataChanged).then(function() {
return releaseByIdPromise(Office.context.document.bindings, binding);
});
});
}
或者你可以为任何 returns 和 AsyncResult
:
function promisify(obj, method) {
var args = Array.prototype.slice.call(arguments, 2);
return new Promise(function(resolve, reject) {
args.push(function(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
resolve(asyncResult.value);
}
});
obj[method].apply(obj, args);
});
}
那么你可以这样做:
var oldBindings = ["myBind1", "myBind2"]; // can be updated by other functions
function updateEventHandlers(newBindings) {
removeEventHandlers(oldBindings).then(function() {
addEventHandlers(newBindings);
});
}
function removeEventHandlers(oldBindings) {
return Promise.all(oldBindings.map(function(binding) {
return promisify(Office.select("binding#"+binding), "removeHandlerAsync", Office.EventType.BindingDataChanged).then(function() {
return promisify(Office.context.document.bindings, "releaseByIdAsync", binding);
});
});
}