0

I am doing a data import using php (Laravel), which has 4-5 different statges.
So, I want to list all of them and the status of each product whether it was an insert or update.
Is there is a way in ajax, where I can fetch the string returned from the server immediately it was echoed line by line? And not at once after everything is completed?
Like

Starting ...
Copying Files ...
Executing ...
Product 1 ...
Product 2 ...
finished ...

        $.ajax({
            url: "product-import.php",
            type: 'POST',
            data: new FormData(this),
            dataType:'text',
            contentType: false,
            cache: false,
            processData: false,
            success: function (data) {
                console.log(data);
                $('#importStatus').append(data);
            }
        });
user3765227
  • 155
  • 1
  • 2
  • 11

1 Answers1

0

Yes, but as far as I know jQuery Ajax doesn't provide an API that exposes it.

The fetch API supports streaming response bodies. The response object's body has a getReader method which returns a reader.

Each time you call read() on the reader, you get back a promise that resolves to an object with a value and done state, so you can loop until done becomes a true value.

Note that since you get a stream of bytes you need to decode them to text.

Given a test script like this (note how it sends the data to the client as soon as it is available, if your existing script buffers all the data then this won't work!):

<?php

$counter = 20;

while ($counter) {
    echo $counter--;
    ob_end_flush();
    sleep(2);
}

You can access the response as a stream like this:

<!DOCTYPE HTML>
<title>Stream Test</title>
<h1>Stream Test</title>
<script>
async function init() {
    const response = await fetch("api.php");
    const reader = await response.body.getReader();
    let going = true;
    while (going) {
        const {value, done} = await reader.read();
        const string = new TextDecoder("utf-8").decode(value);
        if (done) {
            going = false;
        } else {
            const paragraph = document.createElement("p");
            const text = document.createTextNode(string);
            paragraph.appendChild(text);
            document.body.appendChild(paragraph);
        }
    }
}

init();
</script>

Keep in mind that this demo uses very small, well-spaced chunks of data. Larger bits of data may well be split into smaller chunks even if they arrived closely together. You'll probably want to buffer them client-side until the server sends an explict "end of section" token.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335