如何在循环中打破一系列异步操作?

时间:2017-03-16 14:57:21

标签: dojo promise deferred

遵循此示例

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函数调用 - 例如当下一个字符是&#39; d&#39;并将计算值返回到该点?

编辑:到目前为止,我尝试使用deferred cancel()方法,但它只是杀死了进程,并且什么也没有返回。

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);

2 个答案:

答案 0 :(得分:1)

您可以通过检查promise中返回的值来决定是否再次调用异步请求。这与您在break循环中添加for不同。但结果将是你想要的。

将调用所有9个promise.then,但doNext将不会被调用9次。以下是相同的片段。

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

您可能认为这不存在循环。这是因为在调用回调函数之前循环已经完成。但是,回调函数只是返回值,而不是调用异步函数。这导致循环快速完成。下面是一个链接到JSBin,我已经增加了超时,你会看到,最初需要更多的时间,直到返回所需的结果然后快速退出。

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;
}

希望这有用。

答案 1 :(得分:1)

当您总是想要处理所有项目(或同步决定您需要的项目数量)时,您应该只使用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);
});