简体   繁体   English

发送数千个提取请求会使浏览器崩溃。 记不清

[英]Sending thousands of fetch requests crashes the browser. Out of memory

I was tasked with transferring a large portion of data using javascript and an API from one database to another. 我的任务是使用javascript和API将很大一部分数据从一个数据库传输到另一个数据库。 Yes I understand that there are better ways of accomplishing this task, but I was asked to try this method. 是的,我知道可以使用更好的方法来完成此任务,但是我被要求尝试这种方法。

I wrote some javascript that makes a GET call to an api that returns an array of data, which I then turnaround and make calls to another api to send this data as individual POST requests. 我写了一些JavaScript,该API对返回一个数据数组的api进行GET调用,然后我转过身对另一个api进行调用,以将这些数据作为单独的POST请求发送。

What I have written so far seems to works fairly well, and I have been able to send over 50k individual POST requests without any errors. 到目前为止,我写的内容似乎运行良好,并且能够发送5万多个单独的POST请求,而没有任何错误。 But I am having trouble when the number of POST requests increases past around 100k. 但是当POST请求的数量增加到超过10万左右时,我遇到了麻烦。 I end up running out of memory and the browser crashes. 我最终用完了内存,浏览器崩溃了。

From what I understand so far about promises, is that there may be an issue where promises (or something else?) are still kept in heap memory after they are resolved, which results in running out of memory after too many requests. 据我到目前为止对promise的了解,可能存在一个问题,即promise(或其他东西)在解析后仍保留在堆内存中,这导致在请求过多后内存不足。

I've tried 3 different methods to get all the records to POST successfully after searching for the past couple days. 搜索过去几天后,我尝试了3种不同的方法来将所有记录成功地发布到POST。 This has included using Bluebirds Promise.map, as well as breaking up the array into chunks first before sending them as POST requests. 这包括使用Bluebirds Promise.map,以及在将数组作为POST请求发送之前先将其分解为大块。 Each method seems to work up until it has processed about 100k records before it crashes. 每种方法似乎都可以工作,直到崩溃前已处理了约10万条记录。

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
};

Is there something that I am missing about getting these promises cleared out of memory after they have been resolved? 在解决这些诺言之后,将这些诺言从内存中清除,我是否缺少一些东西?

Or perhaps a better method of accomplishing this task? 还是完成这项任务的更好方法?

Edit: Disclaimer - I'm still fairly new to JS and still learning. 编辑:免责声明-我对JS还是很陌生,仍然在学习。

"Well-lll ... you're gonna need to put a throttle on this thing!" “好吧……你需要节制这东西!”

Without (pardon me ...) attempting to dive too deeply into your code, "no matter how many records you need to transfer, you need to control the number of requests that the browser attempts to do at any one time." 没有(请原谅……)尝试不深入代码,“无论需要传输多少记录,您都需要控制浏览器一次尝试进行的请求数量。”

What's probably happening right now is that you're stacking up hundreds or thousands of "promised" requests in local memory – but, how many requests can the browser actually transmit at once? 现在可能正在发生的事情是,您正在本地内存中堆积成百上千个“应许”请求-但是,浏览器一次可以实际传输多少个请求? That should govern the number of requests that the browser actually attempts to do. 这应控制浏览器实际尝试执行的请求数。 As each reply is returned, your software then decides whether to start another request and if so for which record. 在返回每个答复时,您的软件将决定是否启动另一个请求,以及是否为哪个记录。

Conceptually, you have so-many "worker bees," according to the number of actual network requests your browser can simultaneously do. 从概念上讲,您有很多“工蜂”,这取决于您的浏览器可以同时执行的实际网络请求数。 Your software never attempts to launch more simultaneous requests than that: it simply launches one new request as each one request is completed. 您的软件永远不会尝试同时发起更多的并发请求:仅在完成每个请求后才启动一个新请求。 Each request, upon completion, triggers code that decides to launch the next one. 每个请求在完成后都会触发决定启动下一个请求的代码。

So – you never are "sending thousands of fetch requests." 因此, 您永远不会 “发送数千个获取请求”。 You're probably sending only a handful at a time, even though, in this you-controlled manner, "thousands of requests do eventually get sent." 即使以这种您控制的方式,“成千上万的请求最终都会被发送”,您一次可能只发送少数几个。

As you are not intereted in the values delivered by brmPostRequest() , there's no point mapping the original array; 由于您不参与brmPostRequest()传递的值,因此映射原始数组没有任何意义。 neither the promises nor the results need to be acumulated. 诺言和结果都不需要累积。

Not doing so will save memory and may allow progress beyond the 100k sticking point. 不这样做将节省内存, 并可能使进度超过100k固定点。

async function foo() {
    const amResult = await amGetRequest(controllerName);
    let counts = { 'successes': 0, 'errors': 0 };
    for (let i = 0; i < amResult.length; i++) {
        try {
            await brmPostRequest(controllerName, amResult[i]);
            counts.successes += 1;
        } catch(err) {
            counts.errors += 1;
        }
    };
    const console.log(counts);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 发送套接字请求时浏览器内存泄漏 - Browser memory leak while sending socket requests fetch() 正在向我的 API 发送数千个请求 - fetch() is spamming my API with thousands of requests 运行重复 javascript 获取请求正在快速填满浏览器 memory。 有没有办法防止这种情况? - Running repeating javascript fetch requests is filling up browser memory quickly. Is there a way to prevent this? 用JavaScript获取请求时难以发送Cookie - Difficulty sending cookies with fetch requests in JavaScript jQuery在任何浏览器中都无法在此页面上使用。 我不知道为什么! - jQuery not working on this page in any browser. I can't figure out why! 在浏览器崩溃之前检测 memory 耗尽 - Detect memory exhaustion in the browser before it crashes iOS:由于内存不足导致浏览器崩溃 - iOS: Browser crashes due to low memory jQuery交互式滚动使浏览器崩溃。 我在重生崩溃后进行了调试-现在我很茫然 - jQuery interactive scrolling crashes browser. I've run a debug after reproducing crash- and now I'm at a loss 浏览器不发送CORS HTTP OPTION FOR POST REQUESTS - browser not sending CORS HTTP OPTION FOR POST REQUESTS 浏览器向服务器发送数据时发出 4 次请求 - The browser makes 4 requests when sending data to the server
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM