fetch stream html like ajax onprogress

Issue

is it possible to do simple simple modification to this ?

the goal if to "draw" the html as it’s being received.

possible scenario : a php that takes 5 to 8 seconds to execute, and push every echo while processing.

The regular fetch.then is WAITING for all lines to BEGIN the render.

I would like that it begins to render AS SOON as the data comes in.

I have nginx with output buffer off so that every echo is pushed to the browser lines (i don’t have to wait for the completion of the php to start seeing the echos…) when I hit this php in a browser, I see live all lines appearing, but fetch is waiting for all lines.

here the regular fetch.then (working but waits)

// when I call this : it ask the php, php works, once php finished => boom => html render to a div ;)
function fetchajax (phpurl,stuff1,divid) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1); // random value to avoid cache reading
    var postix = []; // prepare array for post body
    postix["somestuff1"] = encodeURIComponent(stuff1); 
    postix["somestuff2"] = encodeURIComponent("test2");
    fetch(phpurl+"?pcache="+pcache, {
      method: "POST",
      body: JSON.stringify(Object.assign({}, postix)), // transforms the array to be sent as body for the post request
      headers: {"Content-type": "application/json; charset=UTF-8"}
    }).then(function (response) { return response.text(); })
    .then(function (html) { $("#"+divid).html(html); })
    .catch( err => console.log() );
}

here some inspiration I found there https://jakearchibald.com/2016/streams-ftw/ but I don’t know which of response,result,reader I could take the html out of…

// I want this to STREAM or render as soon as data is received to a div
function fetchajax (phpurl,stuff1,divid) { 
    fetch("/templates/account_ajax/topnavisub/"+sub+".php?pcache="+pcache+"&fetchx="+pcache, {
      method: "POST",
      body: JSON.stringify(Object.assign({}, postix)),
      headers: {"Content-type": "application/json; charset=UTF-8"}
    }).then(function(response) {
      var reader = response.body.getReader();
      var bytesReceived = 0;

      reader.read().then(function processResult(result) {
        if (result.done) { console.log("Fetch complete");return;}
        
        bytesReceived += result.value.length;console.log(response,result,reader);
        $("#"+divid+"_message").append('. ');

        return reader.read().then(processResult);
      });
    });
}

With this I see the dots during the processing of the php 😉 but how to have the text or response body there ?

you can see this example there https://jsbin.com/vuqasa/edit?js,console

Solution

🙂 I found an answer

Thanks to those 2 links

https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream

Uint8Array to string in Javascript

Here a mix and tested

the php can push ANY html with CSS AND javascript that will be executable as soon as it arrives YAY 😉

The test on the php was echo some html, echo ‘1’, sleep(3) and repear a couple times.

when I trigger that "fetchsrteam" function, I see each echo live streamed, I don’t have to wait to the completion of the php. That way i can see feedbacks of what’s going on (rare but possible) long php scripts that retreive info from APIs, do stuff, compute, etc.

** I also tested this from within webviews in IOS AND Android 😉

function fetchsrteam ( divid , sub , buttonid ) {
    
    var pcache = (Math.floor(Math.random() * 100000000) + 1); 
    var postix = [];
    postix["preventCache"] = pcache;
    postix["divid"] = encodeURIComponent(divid);
    postix["buttonid"] = encodeURIComponent(buttonid);
        
    fetch("/.........php?pcache="+pcache, {
      method: "POST",
      body: JSON.stringify(Object.assign({}, postix)),
      headers: {"Content-type": "application/json; charset=UTF-8"}
    }).then(response => response.body)
      .then(rb => {
        const reader = rb.getReader();
          return new ReadableStream({
            start(controller) {
              function push() {
                reader.read().then( ({done, value}) => {
                  if (done) {
                    console.log('done', done); controller.close(); return;
                  }
                  controller.enqueue(value); $("#"+divid).append(new TextDecoder().decode(value)); push();
                })
              }
            push();
            }
          });
    });

}

here the magic is this line $("#"+divid).append(new TextDecoder().decode(value)); ==>> the new TextDecoder().decode(value) wrapped inside a $("#id").append()…..

have fun 😉

Answered By – Jintor

Answer Checked By – Terry (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.