批量调用 $http.post 并链接承诺
Calling $http.post in batches and chaining promises
我有一个用例,我必须对输入数据的批次调用 $http.post(request)
。
为此,我创建了一个请求数组。对于它们中的每一个,我需要获得 $http.post()
的响应,将其附加到现有数组并将其传递给渲染函数。我必须仅在前一个调用完成时才进行下一个调用,并且由于 $http.post()
returns 一个承诺 (according to this),我正在尝试使用 reduce
函数来执行此操作。
function callToHttpPost(request) {
return $http.post('someurl', request);
}
function outerFunc($scope, someId) {
let completeArray = [];
let arrayOfRequests = getRequestInBatches();
arrayOfRequests.reduce((promiseChain, currentRequest) => {
console.log(promiseChain);
return promiseChain.then((previousResponse) => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
return callToHttpPost(currentRequest);
});
}, Promise.resolve()).catch(e => errorHandler($scope, e, someId));
}
(我提到了MDN and this answer)
但这给了我 TypeError: previousResponse is undefined
。日志语句显示第一个承诺已解决(因为它是传递给 reduce
函数的初始值),但由于此错误,其他承诺显示为 rejected
。我该如何解决?
传递初始值时出错。在reduce函数的第一次迭代中,Promise.resolve()
returns undefined
。这就是作为 previousResponse
传递的内容。将 Promise.resolve({ data: [] })
作为 initialValue
传递给 reduce 函数解决了这个问题。
arrayOfRequests.reduce((promiseChain, currentRequest) => {
console.log(promiseChain);
return promiseChain.then((previousResponse) => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
return callToHttpPost(currentRequest);
});
}, Promise.resolve({ data: [] }))
.then(response => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
displaySuccessNotification();
})
.catch(e => errorHandler($scope, e, someId));
(编辑以处理最终回复)
使用原版 Javascript
如果 outerFunc
函数可以在 async
上下文中使用(看起来可以,因为它 returns 什么都没有,结果传递给 render
在构建时发挥作用),您可以直接清理它,将其削减为:
async function outerFunc ($scope, someId) {
const completeArray = [];
try {
for (const request of getRequestInBatches()) {
const { data } = await callToHttpPost(request);
completeArray.push(...data);
render($scope, completeArray, someId);
}
} catch (e) {
errorHandler($scope, e, someId);
}
}
顺序性质将由 async
/await
关键字强制执行。
使用 RxJS
如果您能够添加对 RxJS 的依赖,您可以将函数更改为:
import { from } from 'rxjs';
import { concatMap, scan } from 'rxjs/operators';
function outerFunc ($scope, someId) {
from(getRequestInBatches()).pipe(
concatMap(callToHttpPost),
scan((completeArray, { data }) => completeArray.concat(...data), [])
).subscribe(
completeArray => render($scope, completeArray, someId),
e => errorHandler($scope, e, someId)
);
}
围绕 Observable
instead of Promise
. In this version, the sequential nature is enforced by the concatMap
operator, and the complete array of results is reduced and emitted while being built up by the scan
运算符的使用。
我有一个用例,我必须对输入数据的批次调用 $http.post(request)
。
为此,我创建了一个请求数组。对于它们中的每一个,我需要获得 $http.post()
的响应,将其附加到现有数组并将其传递给渲染函数。我必须仅在前一个调用完成时才进行下一个调用,并且由于 $http.post()
returns 一个承诺 (according to this),我正在尝试使用 reduce
函数来执行此操作。
function callToHttpPost(request) {
return $http.post('someurl', request);
}
function outerFunc($scope, someId) {
let completeArray = [];
let arrayOfRequests = getRequestInBatches();
arrayOfRequests.reduce((promiseChain, currentRequest) => {
console.log(promiseChain);
return promiseChain.then((previousResponse) => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
return callToHttpPost(currentRequest);
});
}, Promise.resolve()).catch(e => errorHandler($scope, e, someId));
}
(我提到了MDN and this answer)
但这给了我 TypeError: previousResponse is undefined
。日志语句显示第一个承诺已解决(因为它是传递给 reduce
函数的初始值),但由于此错误,其他承诺显示为 rejected
。我该如何解决?
传递初始值时出错。在reduce函数的第一次迭代中,Promise.resolve()
returns undefined
。这就是作为 previousResponse
传递的内容。将 Promise.resolve({ data: [] })
作为 initialValue
传递给 reduce 函数解决了这个问题。
arrayOfRequests.reduce((promiseChain, currentRequest) => {
console.log(promiseChain);
return promiseChain.then((previousResponse) => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
return callToHttpPost(currentRequest);
});
}, Promise.resolve({ data: [] }))
.then(response => {
completeArray.push.apply(completeArray, previousResponse.data);
render($scope, completeArray, someId);
displaySuccessNotification();
})
.catch(e => errorHandler($scope, e, someId));
(编辑以处理最终回复)
使用原版 Javascript
如果 outerFunc
函数可以在 async
上下文中使用(看起来可以,因为它 returns 什么都没有,结果传递给 render
在构建时发挥作用),您可以直接清理它,将其削减为:
async function outerFunc ($scope, someId) {
const completeArray = [];
try {
for (const request of getRequestInBatches()) {
const { data } = await callToHttpPost(request);
completeArray.push(...data);
render($scope, completeArray, someId);
}
} catch (e) {
errorHandler($scope, e, someId);
}
}
顺序性质将由 async
/await
关键字强制执行。
使用 RxJS
如果您能够添加对 RxJS 的依赖,您可以将函数更改为:
import { from } from 'rxjs';
import { concatMap, scan } from 'rxjs/operators';
function outerFunc ($scope, someId) {
from(getRequestInBatches()).pipe(
concatMap(callToHttpPost),
scan((completeArray, { data }) => completeArray.concat(...data), [])
).subscribe(
completeArray => render($scope, completeArray, someId),
e => errorHandler($scope, e, someId)
);
}
围绕 Observable
instead of Promise
. In this version, the sequential nature is enforced by the concatMap
operator, and the complete array of results is reduced and emitted while being built up by the scan
运算符的使用。