如何跳出循环中的一系列异步操作?

How to break out of a sequence of asynchronous operations in a loop?

按照这个例子

Dojo FAQ: How can I sequence asynchronous operations?

function doNext(previousValue) {
    var dfd = new Deferred();

    // perform some async logic; resolve the promise
    setTimeout(function () {
        var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
        dfd.resolve(previousValue + next);
    }, 50);

    return dfd.promise;
}

var promise = doNext('a');

for (var i = 0; i < 9; i++) {
    promise = promise.then(doNext);
}

promise.then(function (finalResult) {
    // 'doNext' will have been invoked 10 times, each
    // invocation only occurring after the previous one completed

    // 'finalResult' will be the value returned
    // by the last invocation of 'doNext': 'abcdefghijk'
    console.log(finalResult);
});

如何跳出循环——即当 doNext 满足特定条件时停止处理后续的 doNext 函数调用——例如当下一个字符为 'd' 和 return 计算值时停止到那个时候?

编辑: 到目前为止,我尝试使用延迟的 cancel() 方法,但它只是终止了进程,return什么都没有。

setTimeout(function () {
    var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
    if(previousValue + next == 'abc')
        dfd.cancel('abc');
    else
    dfd.resolve(previousValue + next);
}, 50);

您可以通过检查 return 从承诺中编辑的值并决定是否再次调用异步请求来做到这一点。它不像您在 for 循环中添加 break 。但结果会如你所愿。

所有 9 promise.then 都会被调用,但 doNext 不会被调用 9 次。下面是相同的代码段。

for (var i = 0; i < 9; i++) {
    promise = promise.then(function(val){
        return val === "abcd" ? val : doNext(val);
    });
}

您可能认为这不是循环。这是因为循环会在调用回调函数之前完成。但是,回调函数不会调用异步函数,而是简单地 return 该值。这会导致循环快速完成。下面是一个 link 到 JSBin,我在其中增加了超时,您会看到,最初需要更多时间才能获得所需的结果 returned 然后快速退出。

https://jsbin.com/qiwesecufi/edit?js,console,output

另一个可以进行检查的地方是 doNext 函数本身。

function doNext(previousValue) {
    var dfd = new Deferred();

    if(previousValue === "abcd")
        return previousValue;

    // perform some async logic; resolve the promise
    setTimeout(function () {
        var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
        dfd.resolve(previousValue + next);
    }, 1000);

    return dfd.promise;
}

希望这对您有所帮助。

当您总是想处理所有项目(或同步决定您需要多少)时,您应该只使用 reduce(或 promise = promise.then(doNext))循环方法。

要循环任意次数并在任何一步中断,递归是更好的方法:

function wait(t, v) {
    var dfd = new Deferred();
    // asynchronously resolve the promise
    setTimeout(function () {
        dfd.resolve(v);
    }, t);
    return dfd.promise;
}

function doNext(previousValue) {
    var next = String.fromCharCode(previousValue.charCodeAt(previousValue.length - 1) + 1);
    return wait(50, previousValue + next);
}

function loop(v, i) {
    if (i <= 0) return when(v);
    if (v == "abc") return when("abc");
    return doNext(v).then(function(r) {
        return loop(r, i-1);
    });
}

loop('a', 9).then(function (finalResult) {
    console.log(finalResult);
});