2017-03-16 35 views
1

按照這個示例如何擺脫循環中的一系列異步操作?

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 '並將計算值返回到該點?

編輯:到目前爲止我嘗試使用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); 

回答

1

您可以通過檢查承諾返回的值並決定是否再次調用異步請求來做到這一點。它不像您在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); 
    }); 
} 

您可能認爲這不存在循環。這是因爲循環在調用回調函數之前完成。但是,而不是調用異步函數,回調函數將簡單地返回值。這會導致循環快速完成。下面是一個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

當您始終要處理所有項目(或同時決定需要多少項目)時,您應該只使用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); 
}); 
+0

我是想你的榜樣,但兩個問題1) - 什麼是「何時」? 2)單步執行代碼,它從不將最終結果寫入控制檯,是否應該這樣做? – erotavlas

+0

['when when](https://dojotoolkit.org/reference-guide/1.10/dojo/when.html)似乎是dojo寫作方式['Promise.resolve'](https://developer.mozilla .ORG/EN-US /文檔/網絡/的JavaScript /參考/ Global_Objects /無極/解析)。關於最終結果,是的,它絕對應該,儘管我沒有測試過代碼(並且只是注意到我忘記了通過'i')。 – Bergi