javascript - 发送数千个获取请求会导致浏览器崩溃。内存不足

标签 javascript promise bluebird fetch-api

我的任务是使用 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/

相关文章:

javascript - 使用 ReactJS 动态表中的列总计

javascript - Promise 未使用 async/await 解决

webpack - 如何在 webpack 配置中等待一段代码?

javascript - 如何用 Bluebird 包装 promise

javascript - 是否可以在 XmlHttpRequest 中发送 Windows 登录凭据?

javascript - 嵌套 Bootstrap Collapse 事件类问题

javascript - 调整图像大小使其完美适合幻灯片,问题仍然是用 for-loop 将我的图像替换 css 代码

javascript - 无法捕获使用 Promise 'catch' 在 Promise 中抛出的错误

node.js - Redis multi 与 Bluebird promise

node.js - 用于使用同步代码模拟异步 promise 的 Bluebird 模式