The problem is I have a tasklist of APIs but the issue is I can't hit more than 3 APIs at once simultaneously from my endpoint to the server(it's the server restriction that it will not respond back to the same requested URL which has more than 3 API called in processing). So I have found a way around to achieve this task but there is a better approach that I know but have not any clue about that how to do but i found a simple solution which is sequentially hit API and wait for the response then hit another but this takes too much time
More optimized solution if N = 3, then I will execute 'task1', 'task2', and 'task3' in the taskList concurrently. Once task2 finishes, you then execute 'task4', and so on. This is the solution that I want to achieve without using any library.
const taskList = [
"task1",
"task2",
"task3",
"task4",
"task5",
"task6",
"task7",
"task8",
"task9",
"task10",
];
const dummyAPICalled = (task) => {
console.log(task, "started");
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(task, "ended");
resolve(true);
}, Math.random() * 20000);
});
};
Hit one by one API's called and wait for the responses.
for await (const task of taskList) {
await dummyAPICalled(task);
}
Hit all APIs at once parallel but didn't get a response because of server requirement
const promises = taskList.map((task) => dummyAPICalled(task));
CodePudding user response:
Concurrent Promises
Since you want concurrent API requests, you need to call multiple instances of a requesting function before the previous instances resolves. Then, once each individual request resolves, you can make another API request per instance. You can group multiple promises together with Promise.all
that resolves when all of the instances resolves.
It could look something like this:
function callTasks(taskLimit) {
var currentTask = 0;
async function createTaskInstance() {
while (currentTask < taskList.length) {
await dummyAPICalled(taskList[currentTask ]);
}
}
var tasks = [];
for (let i = 0; i < taskLimit; i ) {
tasks.push(createTaskInstance());
}
return Promise.all(tasks);
// or alternatively:
// return Promise.all([...Array(taskLimit)].map(createTaskInstance));
}
For example, using code from the question:
const taskList = [
"task1",
"task2",
"task3",
"task4",
"task5",
"task6",
"task7",
"task8",
"task9",
"task10",
];
const dummyAPICalled = (task) => {
console.log(task, "started");
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(task, "ended");
resolve(true);
}, Math.random() * 10000);
});
};
function callTasks(taskLimit) {
var currentTask = 0;
async function createTaskInstance() {
while (currentTask < taskList.length) {
await dummyAPICalled(taskList[currentTask ]);
}
}
var tasks = [];
for (let i = 0; i < taskLimit; i ) {
tasks.push(createTaskInstance());
}
return Promise.all(tasks);
}
callTasks(3).then(()=>console.log('all done'));
CodePudding user response:
Firstly, we want to call the server several times. Say we have callAPI
that would call the server. Without such limit we would do.
const params = [task1, task2, ... ]; // more than 3
const responses = await Promise.all(params.map(param => callAPI(param)));
Now we need an agent to keep count of concurrent calls being made and not exceed it.
const agent = limit(callAPI, 3);
const responses = await Promise.all(params.map(param => agent(param)));
We want agent
to run callAPI
as many as possible (but at most 3) concurrently. So
function limit(callAPI, max) {
let keepCount = 0;
return async function do(param) {
if (keepCount < max) {
keepCount ;
const res = await callAPI(param);
keepCount--;
return res;
} else {
return new Promise((resolve, reject) => {
setTimeout(async () => {
try {
const res = await do(param);
resolve(res);
} catch (err) {
reject(err);
}
}, 0);
});
}
};
}
We need that setTimeout
and promise construction to not block the event-loop.