[英]ES6 promises with timeout interval
我正在嘗試將我的一些代碼轉換為承諾,但我無法弄清楚如何在承諾中鏈接一個新的承諾。
我的 promise 函數應該每隔一秒左右檢查一次數組的內容,如果里面有任何項目應該解決。 否則它應該等待 1s 並再次檢查等等。
function get(){
return new Promise((resolve) => {
if(c.length > 0){
resolve(c.shift());
}else{
setTimeout(get.bind(this), 1000);
}
});
}
let c = [];
setTimeout(function(){
c.push('test');
}, 2000);
這就是我希望我的 get() 承諾函數工作的方式,它應該在最多 2 或 3 秒后打印“測試”:
get().then((value) => {
console.log(value);
});
顯然它不起作用,什么也沒有打印
setTimeout
本身具有糟糕的鏈接和錯誤處理特性,因此請始終將其包裝起來:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); function get(c) { if (c.length) { return Promise.resolve(c.shift()); } return wait(1000).then(() => get(c)); // try again } let c = []; get(c).then(val => console.log(val)); wait(2000).then(() => c.push('test'));
雖然您沒有問,但為了他人的利益,這是async
/ await
大放異彩的絕佳案例:
const wait = ms => new Promise(r => setTimeout(r, ms)); async function get(c) { while (!c.length) { await wait(1000); } return c.shift(); } let c = []; get(c).then(val => console.log(val)); wait(2000).then(() => c.push('test'));
注意我們這次不需要Promise.resolve()
,因為async
函數隱式地做到了這一點。
問題是你的遞歸調用沒有傳遞resolve
函數,所以else
分支永遠不能調用resolve
。
解決此問題的一種方法是在 promise 的回調中創建一個閉包,以便遞歸調用可以訪問與初始調用相同的resolve
變量get
。
function get() { return new Promise((resolve) => { function loop() { if (c.length > 0) { resolve(c.shift()); } else { setTimeout(loop, 1000); } } loop(); }); } let c = []; setTimeout(function() { c.push('test'); }, 2000); get().then(val => console.log(val));
在else
情況下,您永遠不會解決該承諾。 get
可能會創建另一個,但它返回到無處。
你應該promisify您的異步函數( setTimeout
上的最低水平),然后只鏈中的承諾。 通過從then
回調中return
遞歸調用的結果,最終的 Promise 將使用相同的結果解析:
function delayAsync(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
function get(c) {
if (c.length > 0){
return Promise.resolve(c.shift());
} else {
return delay(1000).then(() => {
return get(c); // try again
});
}
}
您需要的是輪詢服務,它在進行承諾解析之前定期檢查特定條件。 目前當你運行setTimeout(get.bind(this), 1000);
您正在創建 Promise 的新實例,而沒有實際解析初始 Promise,因為您沒有引用您創建的初始resolve
函數。
解決方法:
resolve
和reject
作為參數傳遞,例如setTimeout(HandlePromise, 1000, resolve, reject, param3, param4 ..);
設置超時API function get() { var handlerFunction = resolve => { if (c.length > 0) { resolve(c.shift()); } else { setTimeout(handlerFunction, 1000, resolve); } }; return new Promise(handlerFunction); } let c = []; setTimeout(function() { c.push("test"); }, 2000); get().then(value => { console.log(value); });
你可以試試這個解決方案。 由於 JS 需要釋放自己來下載圖像,我在異步函數和異步調用中使用 await 在延遲后喚醒 JS
private async onBeforeDoingSomething() : void {
await this.delay(1000);
console.log("All images are loaded");
}
private delay (ms : number = 500) : Promise<number> {
return new Promise((resolve,reject) => {
const t = setTimeout( () => this.areImgsLoaded(resolve), ms);
});
}
private async areImgsLoaded (resolve) {
let reload = false;
const img = document.querySelectorAll('img');
console.log("total of images: ",img.length);
for (let i = 0; i < img.length; i++){
if (!img[i]["complete"]) {
console.log("img not load yet");
reload = true;
break;
}
}
if (reload) {
await this.delay();
}
resolve();
}
使用setInterval
每秒檢查一次。 運行這個腳本來理解。
let c = []; function get(){ return new Promise((resolve) => { var i = setInterval(function(){ if(c.length > 0){ resolve(c.shift()); clearInterval(i); } }, 1000); }); } setTimeout(function(){ c.push('test'); }, 2000); get().then((value) => { console.log(value); });
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.