[英]iterating over promises node js
嗨,我有一個問題,我試圖遍歷鍵列表,創建匹配實體列表,代碼看起來像這樣
let previous = undefined;
for (let i = offset; i < response.keys.length; i++) {
logger.debug("iteration " + i + " previous: " + previous)
logger.debug("instance key: " + response.keys[i])
if (previous) {
previous = previous
.then((entities) => {
if (entities.length === limit) {
i = response.keys.length;
} else {
readEntity(response.keys[i])
.then((instance) => {
matchInstance(instance, conditions)
logger.debug("is match: " + isMatch)
.then((isMatch) => {
if (isMatch)
entities.push(instance);
//resolve(entities);
}).catch((err) => {
reject(err)
})
}).catch((err) => {
reject(err)
})
}
}).catch((err) => {
reject(err)
})
} else {
previous = readEntity(response.keys[i])
.then((instance) => {
logger.debug("reading instance: " + instance.key)
matchInstance(instance, conditions)
.then((isMatch) => {
if (isMatch) {
return instance
} else {
logger.debug("instance does not match")
}
}).catch((err) => {
reject(err)
})
}).catch((err) => {
reject(err)
})
}
}
但它只經過一次for循環,例如,它什么都不返回?
我也有一些調試
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 0 previous: undefined
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/existing@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 1 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/test@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 2 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/unique@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 3 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/update@...
2017-10-04T15:09:59+0200 <debug> data.js:231 (readEntity.then) reading instance: existing@...
2017-10-04T15:09:59+0200 <debug> data.js:237 (matchInstance.then) instance does not match
請讓我知道是否需要更多信息。 謝謝
下次,如果您實際上用言語(連同代碼)解釋了您要完成的任務,而不僅僅是在問題中轉儲一堆代碼,那么將更容易提供幫助。 我試圖對代碼的目標進行逆向工程,這就是我想您正在嘗試做的事情:
response.keys
有一個值數組。 limit
匹配數,一旦有limit
匹配,就停止尋找更多匹配項。 response.keys
中的項目順序查找那些匹配項。 readEntity(val).then()
matchInstance().then()
測試檢測匹配。 limit
long。 這是三個獨立的設計模式,用於序列化數組的迭代,在該模式中,您要對每個數組元素執行異步操作,並希望一個接一個地進行操作(不是並行執行)。 由於要求在收集limit
結果后停止處理,因此使您的特殊情況稍微復雜一些。
.reduce()承諾鏈
序列化基於promise的異步操作的經典設計模式是使用.reduce()
,其中約簡中的累加器值是一個promise,您可以鏈接到該promise來強制序列化。 您可以這樣實現:
// get subset of response.keys that we can process with .reduce()
let keys = response.keys.slice(offset);
keys.reduce((p, val) => {
// return promise so we continually chain
return p.then(entities => {
// if entities is not yet full
if (entities.length < limit) {
return readEntity(val).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
// resolved value is entities so that is passed down the chain
return entities;
});
});
} else {
return entities;
}
});
}, Promise.resolve([])).then(entities => {
// process results here
}).catch(err => {
// process error here
});
示例實現: https : //jsfiddle.net/jfriend00/uspa8vgd/
在這個承諾鏈中,承諾的已解決價值是結果數組。 它使用Promise.resolve([])
初始化為空數組,並作為初始累加器值傳遞給.reduce()
,然后.reduce()
回調的.reduce()
值始終是相同的entities
數組。 這樣,它就沿着鏈向下傳遞,其中鏈中的每個鏈接都有機會添加到鏈中(或者不基於isMatch
測試)。
使用next()函數進行手動迭代和鏈接
這是依次迭代的另一種設計模式。 我通常會調用next()
一個內部函數。 該函數返回一個Promise或一個值。 如果返回值,則迭代完成。 如果返回承諾,則迭代將繼續,每次迭代都鏈接到前一個。 最終的解析值是您在迭代過程中累積的任何值。 在這里是entities
數組。
function runMatchIteration(data, offset, limit) {
let i = offset;
let entities = [];
function next() {
if (i < data.length && entities.length < limit) {
return readEntity(data[i++]).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
// now execute next cycle - chaining onto original promise
return next();
});
});
} else {
// done with loop here
return entities;
}
}
return Promise.resolve().then(next);
}
// usage
runMatchIteration(response.keys, offset, limit).then(entities => {
// process results here
}).catch(err => {
// process error here
});
實施范例: https : //jsfiddle.net/jfriend00/t5bmzkb6/
使用Bluebird的Promise.mapSeries()在Series中運行事物
藍鳥承諾庫具有許多有用的功能,用於管理和排序承諾。 其中之一是Promise.mapSeries()
,它將數組作為輸入並序列化對數組中每個項目的調用函數。 因為您要求在達到limit
結果后停止,所以我們必須使用與平時稍有不同的方法,但是它仍然使代碼相當簡單:
let entities = [];
Promise.mapSeries(response.keys.slice(offset), item => {
if (entities.length < limit) {
return readEntity(item).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
});
});
}
}).then(() => {
// process entities result here
}).catch(err => {
// handle error here
});
關於原始代碼的一些觀察結果:
.then()
處理程序中運行新的異步操作時,必須從.then()
回調中返回那些承諾,以便將它們鏈接到父承諾。 否則,您將創建各種獨立的未鏈接的承諾鏈,並且您永遠都不知道什么時候完成,也無法協調不同的承諾鏈。 for
循環索引。 for
循環是同步的,並且將在您執行任何異步回調之前完成很長時間。 因此,無論何時嘗試操縱它的索引, for
循環都已經完成。 您可以為此編寫一個遞歸函數(不推薦) :
let index = 0;
let errors = [];
function promiseIterator (index) {
if (response.keys[index]) {
readEntity(response.keys[index]).then((instance) => {
matchInstance(instance, conditions).then(() => {
logger.debug("is match: " + isMatch).then(() => {
if (isMatch) entities.push(instance);
promiseIterator(index+1);
});
});
}).catch((err) => {
//error handler
errors.push({keyIndex: index, err: err});
promiseIterator(index+1);
});
}
}
promiseIterator(offset);
// do your stuff with error array
上面的代碼可能不太准確,請根據您的要求進行調整。
但是由於您需要遍歷Promise,因此建議使用bluebird
庫並根據您的要求實現each
或all
功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.