Receive a response in fragments from express on the browser

As I work on creating a progress bar to track long-running server-side tasks that may take up to a few minutes, I am exploring different methods to display the progress of each task. While WebSockets and interval polling are options, I prefer using long-polling to write progress updates directly to the stream without having to individually track each task.

To give you an idea of what the server route should look like, here is a demo:

app.get('/test', (req, res) => {
    let num = 0;
    const interval = setInterval(() => res.write(num++ + ' '), 300);
    setTimeout(() => {
        clearInterval(interval);
        res.send();
    }, 5000);
});

cURL works smoothly when used with the -N flag on this endpoint. However, I encountered some challenges while attempting to implement this functionality in the browser.

I initially tried using fetch in the following manner:

const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
    const { done, value } = await reader.read();
        if (done)
            break;  
    console.log(decoder.decode(value));
}

This method worked well in Chrome but faced compatibility issues in Firefox as highlighted here.

As an alternative, I experimented with XHR:

const xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.onprogress = function () {
    console.log(xhr.responseText);
};
xhr.send();

While this approach performed effectively in Firefox, Chrome's onProgress event only triggered once the entire request was processed. Attempts with onReadyStateChange yielded similar results.

>_< How can I retrieve data in chunks as it updates in both browsers? Should I consider using Axios?

EDIT: It is noteworthy that Chrome and Firefox handle fetch behavior differently. In Chrome, I can manipulate the fetch object before completion, which is not the case in Firefox. This distinction impacts my ability to interact with the response body accordingly.

Answer №1

After researching on the GitHub platform, it has been discovered that the issue at hand is related to a bug in Chrome and Webkit. To resolve this bug, it is recommended to adjust the Content-Type of the request to anything other than text/plain, which will enable compatibility with XHR in Chrome.

To implement this fix, you can modify the server response as shown below:

app.get('/test', (req, res) => {
    let num = 0;
    let interval = setInterval(() => res.write(num++ + ' '), 300);
    // Implementation to address Chrome compatibility
    res.setHeader('Content-Type', 'text/html');
    setTimeout(() => {
        clearInterval(interval);
        res.send();
    }, 5000);
});

Interestingly, this adjustment not only resolves the issue with fetch streaming in Firefox without any additional modifications, but it also makes the XHR method more compatible. However, working with the fetch version may be preferred due to its ease of processing new data chunks individually.

AHHHHHHHHH

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When a single object is entered, JSON returns 'undefined', however, it works successfully when using the .map() function

Utilizing Axios to fetch data from DeezerAPI, I initially rendered information using .map() and everything worked smoothly when passing it to a Component. However, when attempting to access a single JSON object, I encountered an 'undefined' error ...

Using Boolean as a prop in Vue.js

Creating a Vue form to ask a question involves making a component: <template> <div class="flex flex-col items-center justify-center gap-2"> <div class="flex w-[80%] items-center justify-center gap-2 rounded-3xl p-2" ...

Ways to apply the .not selector efficiently in jQuery

I have a situation with two separate divs, one named task1 and the other named task2. Each of these tasks contains panels with various names. Within task2, there is a duplicate name (Greg), who also belongs to the duplicate class. I'm trying to figure ...

A guide to integrating ffmpeg with NuxtJS

I am completely new to Nuxt and currently in the process of migrating a Vue application that generates gifs using ffmpeg.wasm over to Nuxt.js. However, every time I try to access the page, the server crashes with the following error message: [fferr] reques ...

Tips for effectively incorporating customized validation into an array using vuelidate

My array of objects has a specific structure that looks like this varientSections: [ { type: "", values: [ { varientId: 0, individualValue: "" } ] } ] To ensure uniqueness, I implemented a c ...

use javascript or jquery to conceal the textbox control

Looking to conceal a textbox control using javascript or jquery. I attempted the following code: document.getElementsByName('Custom_Field_Custom1').style.display="none"; Unfortunately, I received an error in the java console: document.getEle ...

Identify Unintended Javascript Modifications in Ajax Request

We have developed a unique Javascript file for our clients to utilize. This innovative snippet captures a screenshot of the website it is executed on and then securely transmits it back to our server using jQuery.post() Given the sensitive nature of our i ...

The output varies with each reload even though the function remains constant

Essentially, my webpage functions as an online store where the content is dynamically generated using PHP shortcodes. Here is an example of how it is structured: <?php get_header(); ?> <div id="main-content"> <div id="page-content"> ...

What could be causing Jquery's $.ajax to trigger all status codes even when the call is successful?

Here is a simple Jquery ajax function call I have. function fetchData(){ var jqxhr = $.ajax({ url: "../assets/js/data/users.json", type: "GET", cache: true, dataType: "json", statusC ...

A React child error has occurred in Next.js due to invalid objects being used

Within my project, I have integrated the latest version of next.js and encountered an issue where objects are not valid as a React.js child. https://i.stack.imgur.com/MCO7z.png The problem arises after importing the Head component from Next.js and implem ...

Can you explain the contrast between onsubmit="submitForm();" and onsubmit="return submitForm();"?

Is it possible that the form below is causing double submissions? <form name="myForm" action="demo_form.asp" onsubmit="submitForm();" method="post"> function submitForm(){ document.myForm.submit(); } I've noticed a bug where sometimes two ...

Sending parameter and ng-click to the angular directive

I am looking for a way to transfer data from HTML to the directive, allowing the directive to be clickable using ng-click. How can I pass the parameter of the link function to the template? app.directive("hello", function(){ return { restrict: "E" ...

Tips for having <script> update onchange instead of just onload

Is there a way to update the output of the <table id="mortgagetable"> each time a user changes the input values in the form? Currently, it only updates on load. Additionally, the content of the <div id="years" style="display:inline-block;">25 ...

Implementing a function or template from one component into another within a Vue.js application, despite lacking a direct connection between the two components

Working on my Vue.js app, I encountered an interesting challenge: The layout of the app is simple: it consists of a header, a main view, and a navigation section at the bottom. Depending on the current page the user is on, I want to display a main action ...

Creating an Editor for Input Text Field in HTML: A Step-by-Step Guide

In the vast landscape of JS libraries that can achieve this function, like Trumbowyg and more. However, prior to my rails project displaying that slim version, I need to ensure JavaScript is properly escaped! Therefore, I need to create an editor using o ...

Steer clear of 405 errors by implementing AJAX in combination with Flask and JINJA templ

Hey there, I'm fairly new to backend work so please bear with me. I've been doing some research but haven't found the answer yet. Currently, I'm working on an application that fetches search results from a 3rd party API. I'm tryi ...

Utilizing Chart.js for generating a sleek and informative line graph

After executing a MySQL query, I obtained two tables named table1 (pl_pl) and table2 (act_act) with the following data: table1: label act_hrs Jan-19 7 Feb-20 8 Mar-20 9 table2: label pl_hrs Mar-20 45 Apr-20 53 I am looking to create a line cha ...

Efficiently generating and managing numerous toggle buttons in Reactjs with Material-ui ToggleButtons

Currently, I am exploring the idea of designing a sidebar that incorporates a variable number of toggle buttons generated from an object containing keys and values. However, I am encountering difficulties in utilizing the "key" value to adjust the corres ...

Showing canvas lines while dragging (using only plain JavaScript, with React.JS if needed)

Is there a way to add lines with two clicks and have them visible while moving the mouse? The line should only be drawn when clicking the left mouse button. Any suggestions on how I can modify my code to achieve this functionality? Currently, the lines are ...

Display and conceal div with Jquery as you scroll to specific points on a mobile device

I'm looking to create a dynamic div that appears and disappears based on the user's scroll position. Here is what I have so far: $(document).scroll(function() { var y = $(this).scrollTop(); if (y > 200) { $('.float-contai ...