我的任务是使用 JavaScript 和 API 将大部分数据从一个数据库传输到另一个数据库。是的,我知道有更好的方法来完成这项任务,但我被要求尝试这种方法。
我编写了一些 javascript,对返回数据数组的 api 进行 GET 调用,然后我将其转而调用另一个 api 以将这些数据作为单独的 POST 请求发送。
到目前为止我所写的内容似乎运行得相当好,并且我已经能够发送超过 50k 个单独的 POST 请求而没有任何错误。但当 POST 请求数量增加到超过 100k 左右时,我遇到了麻烦。我最终耗尽了内存并且浏览器崩溃了。
据我目前对 Promise 的了解,可能存在一个问题,即 Promise(或其他东西?)在解决后仍保留在堆内存中,这会导致在太多请求后内存不足。
在过去几天的搜索后,我尝试了 3 种不同的方法来使所有记录成功 POST。这包括使用 Bluebirds Promise.map,以及先将数组分成 block ,然后再将其作为 POST 请求发送。每个方法似乎都能正常工作,直到处理完大约 100k 条记录后才会崩溃。
async function amGetRequest(controllerName) {
try{
const amURL = "http://localhost:8081/api/" + controllerName;
const amResponse = await fetch(amURL, {
"method": "GET",
});
return await amResponse.json();
} catch (err) {
closeModal()
console.error(err)
}
};
async function brmPostRequest(controllerName, body) {
const brmURL = urlBuilderBRM(controllerName);
const headers = headerBuilderBRM();
try {
await fetch(brmURL, {
"method": "POST",
"headers": headers,
"body": JSON.stringify(body)
});
}
catch(error) {
closeModal()
console.error(error);
};
};
//V1.0 Send one by one and resolve all promises at the end.
const amResult = await amGetRequest(controllerName); //(returns an array of ~245,000 records)
let promiseArray = [];
for (let i = 0; i < amResult.length; i++) {
promiseArray.push(await brmPostRequest(controllerName, amResult[i]));
};
const postResults = await Promise.all(promiseArray);
//V2.0 Use bluebirds Promise.map with concurrency set to 100
const amResult = await amGetRequest(controllerName); //(returns an array of ~245,000 records)
const postResults = Promise.map(amResult, async data => {
await brmPostRequest(controllerName, data);
return Promise.resolve();
}, {concurrency: 100});
//V3.0 Chunk array into max 1000 records and resolve 1000 promises before looping to the next 1000 records
const amResult = await amGetRequest(controllerName); //(returns an array of ~245,000 records)
const numPasses = Math.ceil(amResult.length / 1000);
for (let i=0; i <= numPasses; i++) {
let subset = amResult.splice(0,1000);
let promises = subset.map(async (record) => {
await brmPostRequest(controllerName, record);
});
await Promise.all(promises);
subset.length = 0; //clear out temp array before looping again
};
在解决这些 promise 后,我是否遗漏了将其从内存中清除的过程?
或者也许是完成此任务的更好方法?
编辑:免责声明 - 我对 JS 还很陌生,并且仍在学习中。
最佳答案
“好吧-l-l-l ...你需要在这件事上加一个 throttle !”
不要(请原谅我......)尝试太深入地研究您的代码,“无论您需要传输多少记录,您都需要控制浏览器尝试执行的请求数量一次。”
现在可能发生的情况是,您在本地内存中堆积了数百或数千个“ promise 的”请求 - 但是,浏览器实际上可以一次传输多少个请求?这应该控制浏览器实际尝试执行的请求数量。返回每个回复后,您的软件将决定是否启动另一个请求,如果是,则针对哪条记录。
从概念上讲,根据您的浏览器可以同时执行的实际网络请求数量,您有很多“工蜂”。您的软件绝不会尝试同时启动更多请求:它只是在每个请求完成后启动一个新请求。每个请求完成后都会触发决定启动下一个请求的代码。
所以 - 你永远不会“发送数千个获取请求”。您可能一次只发送少量请求,尽管以这种您控制的方式,“最终确实发送了数千个请求。”
关于javascript - 发送数千个获取请求会导致浏览器崩溃。内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57700505/