React - 控制对服务器的 AJAX 次调用
React - Controlling AJAX calls made to the server
在我的 React 应用程序中,我有一个参数数组(例如一些 ID),它们应该用作 ajax 调用队列的参数。问题是数组可能包含超过 1000 个项目,如果我只是使用 forEach 循环递归地进行 ajax 调用,浏览器页面最终会在每个请求得到解决之前停止响应。
有没有一个库可以发送ajax个请求,比如一次异步维护5个请求。
这是我现在使用的代码。
async function makeBatchCalls(arrayIds, length)
{
//convert arrayIds to two dimensional arrays of given length [[1,2,3,4,5], [6,7,8,9,10] ....]
let test = arrayIds.reduce(
(rows, key, index) => (index % length == 0
? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
let Batchresults = [];
for (calls of test) {
Batchresults.push(await Promise.all(calls.map((call)=>fetch(`https://jsonplaceholder.typicode.com/posts/${call}`))));
}
return Promise.all(Batchresults); //wait for all batch calls to finish
}
makeBatchCalls([1,2,3,4,5,6,7,8,9,10,12,12,13,14,15,16,17,18,19,20],5)
此代码的问题是它等待 5 个调用完成,然后发送另一批 5 个调用。这不是对网络的有效利用。我想要的是在任何时间点应该有 5 个请求。
是否可以调整上面的代码本身以满足要求?
这是一个需要解决的有趣问题。我能想到的一种方法是在第一批中的任何一个完成后立即进行 6th
ajax 调用。这样,任何时候都会有 5 ajax 个请求在处理中。我试图实现类似的东西。虽然我的解决方案没有进行 ajax 调用,但我猜你可以更改 process
函数来进行 ajax 调用和 return 承诺。
/**
This function processes the jobs in batches, once a job is finished in batch it then processes the next job. This can be used to make network calls.
*/
function processBatch(queue, batchSize, processJob) {
// remove a batch of items from the queue
const items = queue.splice(0, batchSize);
let count = items.length;
// no more items?
if (!count) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
return items.forEach((item, i) => {
return processJob(item).then(result => {
return processBatch(queue, 1, processJob)
.then(_ => --count || resolve());
});
});
})
}
// create queue
var queue = [];
for (var i = 1; i <= 20; i++) {
queue.push(i);
}
// a per-item action
function process(item) {
console.log('starting ' + item + '...');
return new Promise((resolve, reject) => {
// (simulating ajax)
return setTimeout(function() {
console.log('completed ' + item + '!');
resolve();
}, Math.random() * 1000);
});
}
// start processing queue!
processBatch(queue, 5, process)
.then(result => console.log("All jobs processed"));
我只是尝试使用 promises 实现一个通用函数。您可以尝试 运行 与 ajax 调用相同。我很想知道这个解决方案如何为您服务。
如您所见,我在成功执行每个作业后递归调用 processBatch
函数,并且连续的 batchSize
被硬编码为 1
,但这可以更改并参数化。此外,此功能仅适用于快乐路径情况,因为它不考虑被拒绝的承诺。
有趣的问题,我将提出一个与你提出的不同的解决方案,这个解决方案将确保每次最多处理 5 个请求。
function makeBatchCalls(arrayIds, length) {
// determines how many queries are being sent at any given time
let queued = 0;
// determines the index of the query to send at any given time
let currentIndex = 0;
// recursive function that launches queries and makes sure the queue is respected
let launchNext = function() {
if (queued === length) {
return;
}
fetch(`https://jsonplaceholder.typicode.com/posts/${arrayIds[currentIndex]}`).then((results) => {
queued--;
launchNext();
// do something with your results here...
});
queued++;
currentIndex++;
};
// launch the first length queries as the queue is empty at first
for (let i = 0; i < length; i++) {
launchNext();
}
}
希望对您有所帮助。
您可以将 Async 库用于您的用例。有一个队列函数可以做到这一点。它维护一个要执行的任务队列并执行它们,并始终保持所需的并发性。
以下是如何更改您的函数以使用异步队列。
async function makeBatchCalls(arrayIds, length)
{
// create a queue object with concurrency 5(equal to batch length in your case)
var q = async.queue(function(task, callback) {
//Call your api for this task here
fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)
.then(function (response) {
//Once your task executes successfully, call the Q callback so that next pending task can be picked up.
//This ensures all your tasks keep running one after the other with desired concurrency
callback();
})
.catch(function (err) {
//in case of failure, either you can return, or you can move to next task by calling callback
});
}, 5);
// Is called when all the tasks have completed
q.drain = function() {
console.log('all items have been processed');
};
// push all items to queue
for(var i=0; i < arrayIds.length; i++){
q.push(arrayIds[i]);
}
}
makeBatchCalls([1,2,3,4,5,6,7,8,9,10,12,12,13,14,15,16,17,18,19,20],5)
在我的 React 应用程序中,我有一个参数数组(例如一些 ID),它们应该用作 ajax 调用队列的参数。问题是数组可能包含超过 1000 个项目,如果我只是使用 forEach 循环递归地进行 ajax 调用,浏览器页面最终会在每个请求得到解决之前停止响应。
有没有一个库可以发送ajax个请求,比如一次异步维护5个请求。
这是我现在使用的代码。
async function makeBatchCalls(arrayIds, length)
{
//convert arrayIds to two dimensional arrays of given length [[1,2,3,4,5], [6,7,8,9,10] ....]
let test = arrayIds.reduce(
(rows, key, index) => (index % length == 0
? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
let Batchresults = [];
for (calls of test) {
Batchresults.push(await Promise.all(calls.map((call)=>fetch(`https://jsonplaceholder.typicode.com/posts/${call}`))));
}
return Promise.all(Batchresults); //wait for all batch calls to finish
}
makeBatchCalls([1,2,3,4,5,6,7,8,9,10,12,12,13,14,15,16,17,18,19,20],5)
此代码的问题是它等待 5 个调用完成,然后发送另一批 5 个调用。这不是对网络的有效利用。我想要的是在任何时间点应该有 5 个请求。
是否可以调整上面的代码本身以满足要求?
这是一个需要解决的有趣问题。我能想到的一种方法是在第一批中的任何一个完成后立即进行 6th
ajax 调用。这样,任何时候都会有 5 ajax 个请求在处理中。我试图实现类似的东西。虽然我的解决方案没有进行 ajax 调用,但我猜你可以更改 process
函数来进行 ajax 调用和 return 承诺。
/**
This function processes the jobs in batches, once a job is finished in batch it then processes the next job. This can be used to make network calls.
*/
function processBatch(queue, batchSize, processJob) {
// remove a batch of items from the queue
const items = queue.splice(0, batchSize);
let count = items.length;
// no more items?
if (!count) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
return items.forEach((item, i) => {
return processJob(item).then(result => {
return processBatch(queue, 1, processJob)
.then(_ => --count || resolve());
});
});
})
}
// create queue
var queue = [];
for (var i = 1; i <= 20; i++) {
queue.push(i);
}
// a per-item action
function process(item) {
console.log('starting ' + item + '...');
return new Promise((resolve, reject) => {
// (simulating ajax)
return setTimeout(function() {
console.log('completed ' + item + '!');
resolve();
}, Math.random() * 1000);
});
}
// start processing queue!
processBatch(queue, 5, process)
.then(result => console.log("All jobs processed"));
我只是尝试使用 promises 实现一个通用函数。您可以尝试 运行 与 ajax 调用相同。我很想知道这个解决方案如何为您服务。
如您所见,我在成功执行每个作业后递归调用 processBatch
函数,并且连续的 batchSize
被硬编码为 1
,但这可以更改并参数化。此外,此功能仅适用于快乐路径情况,因为它不考虑被拒绝的承诺。
有趣的问题,我将提出一个与你提出的不同的解决方案,这个解决方案将确保每次最多处理 5 个请求。
function makeBatchCalls(arrayIds, length) {
// determines how many queries are being sent at any given time
let queued = 0;
// determines the index of the query to send at any given time
let currentIndex = 0;
// recursive function that launches queries and makes sure the queue is respected
let launchNext = function() {
if (queued === length) {
return;
}
fetch(`https://jsonplaceholder.typicode.com/posts/${arrayIds[currentIndex]}`).then((results) => {
queued--;
launchNext();
// do something with your results here...
});
queued++;
currentIndex++;
};
// launch the first length queries as the queue is empty at first
for (let i = 0; i < length; i++) {
launchNext();
}
}
希望对您有所帮助。
您可以将 Async 库用于您的用例。有一个队列函数可以做到这一点。它维护一个要执行的任务队列并执行它们,并始终保持所需的并发性。
以下是如何更改您的函数以使用异步队列。
async function makeBatchCalls(arrayIds, length)
{
// create a queue object with concurrency 5(equal to batch length in your case)
var q = async.queue(function(task, callback) {
//Call your api for this task here
fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)
.then(function (response) {
//Once your task executes successfully, call the Q callback so that next pending task can be picked up.
//This ensures all your tasks keep running one after the other with desired concurrency
callback();
})
.catch(function (err) {
//in case of failure, either you can return, or you can move to next task by calling callback
});
}, 5);
// Is called when all the tasks have completed
q.drain = function() {
console.log('all items have been processed');
};
// push all items to queue
for(var i=0; i < arrayIds.length; i++){
q.push(arrayIds[i]);
}
}
makeBatchCalls([1,2,3,4,5,6,7,8,9,10,12,12,13,14,15,16,17,18,19,20],5)