[英]use forEach() with promises while access previous promise results in a .then() chain?
我有承諾的以下功能:
const ajaxRequest = (url) => {
return new Promise(function(resolve, reject) {
axios.get(url)
.then((response) => {
//console.log(response);
resolve(response);
})
.catch((error) => {
//console.log(error);
reject();
});
});
}
const xmlParser = (xml) => {
let { data } = xml;
return new Promise(function(resolve, reject) {
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(data,"text/xml");
if (xmlDoc.getElementsByTagName("AdTitle").length > 0) {
let string = xmlDoc.getElementsByTagName("AdTitle")[0].childNodes[0].nodeValue;
resolve(string);
} else {
reject();
}
});
}
我正在嘗試為JSON數組中的每個對象應用這些函數:
const array = [{"id": 1, "url": "www.link1.com"}, {"id": 1, "url": "www.link2.com"}]
我提出了以下解決方案:
function example() {
_.forEach(array, function(value) {
ajaxRequest(value.url)
.then(response => {
xmlParser(response)
.catch(err => {
console.log(err);
});
});
}
}
我想知道這個解決方案是否可以接受兩件事:
在以下事項中對承諾申請Each()是一種好的做法。
有沒有更好的方法將先前的promise結果作為then()鏈中的參數傳遞? (我正在通過response
)。
您可以使用.reduce()
來訪問以前的Promise
。
function example() {
return array.reduce((promise, value) =>
// `prev` is either initial `Promise` value or previous `Promise` value
promise.then(prev =>
ajaxRequest(value.url).then(response => xmlParser(response))
)
, Promise.resolve())
}
// though note, no value is passed to `reject()` at `Promise` constructor calls
example().catch(err => console.log(err));
注意,在ajaxRequest
函數中不需要Promise
構造函數。
const ajaxRequest = (url) =>
axios.get(url)
.then((response) => {
//console.log(response);
return response;
})
.catch((error) => {
//console.log(error);
});
您提供的代碼的唯一問題是xmlParser的結果丟失,forEach循環只是迭代但不存儲結果。 為了保持結果,你需要使用Array.map作為結果得到Promise,然后Promise.all等待並將所有結果都放到數組中。
我建議使用ES2017的async / await來簡化處理promises。 由於提供的代碼已經使用了箭頭函數,這需要轉換為較舊的瀏覽器兼容性,因此您可以添加轉換插件以支持ES2017。
在這種情況下,您的代碼將是:
function example() {
return Promise.all([
array.map(async (value) => {
try {
const response = await ajaxRequest(value.url);
return xmlParser(response);
} catch(err) {
console.error(err);
}
})
])
}
上面的代碼將並行運行所有請求,並在所有請求完成后返回結果。 您可能還希望逐個觸發和處理請求,如果這是您的問題,這也將提供對先前承諾結果的訪問:
async function example(processResult) {
for(value of array) {
let result;
try {
// here result has value from previous parsed ajaxRequest.
const response = await ajaxRequest(value.url);
result = await xmlParser(response);
await processResult(result);
} catch(err) {
console.error(err);
}
}
}
另一個解決方案是使用Promise.all
來做這件事,我認為這是一個比循環ajax請求更好的解決方案。
const array = [{"id": 1, "url": "www.link1.com"}, {"id": 1, "url": "www.link2.com"}]
function example() {
return Promise.all(array.map(x => ajaxRequest(x.url)))
.then(results => {
return Promise.all(results.map(data => xmlParser(data)));
});
}
example().then(parsed => {
console.log(parsed); // will be an array of xmlParsed elements
});
有沒有更好的方法將先前的promise結果作為then()鏈中的參數傳遞?
事實上,您可以按任何順序和代碼的任何位置鏈接和解決承諾。 一個通用規則 - 使用then
或catch
分支的任何鏈式承諾只是新的承諾,應該在以后鏈接。
但沒有限制。 使用循環,最常見的解決方案是reduce
左側foldl,但您也可以使用簡單的let
-variable並重新分配新的承諾。
例如,您甚至可以設計延遲的承諾鏈:
function delayedChain() {
let resolver = null
let flow = new Promise(resolve => (resolver = resolve));
for(let i=0; i<100500; i++) {
flow = flow.then(() => {
// some loop action
})
}
return () => {
resolver();
return flow;
}
}
(delayedChain())().then((result) => {
console.log(result)
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.