循环中的异步回调

时间:2017-03-17 03:34:54

标签: javascript asynchronous promise ms-office office-js

我有一个变量BindingDataChanged,它记录了Excel表的所有现有绑定。我基于oldBindings构建了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

由于releaseByIdAsynccallback是使用promise而不是callback构建的,因此我需要使用removeEventHandlers整理整个代码。我不确定有两件事:

1)在cb()中,addEventHandlers总是会在删除所有听众后执行吗?我怎么能确保这个?

2)我是否必须callback作为removeEventHandlers ImportError: DLL load failed: The specified module could not be found来确保执行顺序?

1 个答案:

答案 0 :(得分:2)

  

1)在removeEventHandlers中,cb()是否会在删除所有侦听器后执行?

没有。它将在删除的启动之后被调用。但是如果删除是异步的,则可以在删除完成之前调用它。

  

2)我是否必须将addEventHandlers作为removeEventHandlers的回调以确保其执行顺序?

是的,但不是你的方式。你的方式就像做

removeEventHandlers();
addEventHandlers();

因为您在cb结束时致电removeEventHandlers而无需等待任何事情完成。

  

由于removeHandlerAsyncreleaseByIdAsync是使用callback而非promise构建的,因此我需要使用callback整理整个代码。

或者你可以给自己的Promise版本。稍等一下。

使用非Promise回调方法,确保在完成所有工作后从cb致电removeEventHandlers,记住您预计会有多少回调,并等到有多少回调在致电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);
        });
    });
}

或者,您可以为任何返回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);
        });
    });
}