Safari / IOS WKWebView waiting for 250 bytes before rendering content. Delaying execution of external .js

We have observed that safari / IOS WKWebView waits for ~250 renderable bytes before it starts to render HTML as received in the browser. This is different from the behaviour in chrome / Firefox where they start to render the content as soon as the first byte is available. We wanted to know if there’s a way to stop this behaviour, to bring parity across the two browsers. Also is there any official doc / announcement establishing this limit of ~250 characters which we’ve found experimentally.

Details of our experiment:

We created a simple HTTP Server In python that:

  • Emits a stream of (100) characters
  • Sleeps for 3 seconds
  • Emits some more characters

You can find the experiment code towards the end of the post

The ideal behaviour (which we observed in chrome) is that the content should be rendered progressively. Implying that the 100 characters before the .sleep() should be rendered immediately. This should be followed by a gap of 3 seconds, and then the rest of the characters are displayed. You can see this behaviour where I reload the page:

https://drive.google.com/file/d/1JD_ZbghX3OOz_CpSR2iGn_Se7_2HDRTw/view?usp=sharing

The text "Before Sleep" followed by a line of 100 dashes is the content before .sleep() which appears immediately. The text “After Sleep” apears after a time of 3 seconds which is the desired behaviour.

In safari however, all of the content appears at once after 3 seconds, instead of being rendered progressively as seen here when I reload the page :

https://drive.google.com/file/d/1RiD7eFuwGYL5lGIcU1CF2gcpoSysHJ9C/view?usp=sharing

However if we increase the number of characters emitted before the .sleep() to ~250 (256 to be exact) safari behaves similar to chrome and the content appears progressively. You can see this here on page reload :

https://drive.google.com/file/d/1JlHFbZPdFuIiaAlkgYCWo61amBIysKL1/view?usp=sharing

We found this value of ~250 experimentally via hit and trial.

Not only rendering, we also found this delaying the execution of external .js (that is present in a separate .js file embedded via <script> tag). To prove this, I added a simple console.log(performance.now()) at the top of the .js file (outside of any function).

In safari with artificially inserted ~260 extra bytes this log was printed at ~1 - 1.5 secs. However without the extra bytes this log came at ~3 - 4 seconds. This gap corresponds to the time taken to make rest of the page ready. Note that embedded .js present in the HTML was not affected by this.

Wondering if other’s have faced the same problem and if there's an official doc stating this limit / any workarounds.

Python HTTP Server code that we executed for our experiment

from http.server import BaseHTTPRequestHandler, HTTPServer
import time
import sys
 
class handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.flush_headers()

        # Content before .sleep()

        message = f' <!DOCTYPE html> \
                    <html lang="en"> \
                    <head> \
                        <meta charset="UTF-8"> \
                        <title></title> \
                    </head> \
                   <body> \
                   '

        self.wfile.write(bytes(message, "utf8"))
        self.wfile.flush()

        beforeSleep = 'Before Sleep'
        self.wfile.write(bytes(beforeSleep, "utf8"))
        self.wfile.flush()

        lineBreak = '<br/>'
        self.wfile.write(bytes(lineBreak, "utf8"))
        self.wfile.flush()

        blankChar = "-"
        fillerString = "";

        for x in range(260):
            fillerString = fillerString + blankChar
        self.wfile.write(bytes(fillerString, "utf8"))

        # Sleep for 3 seconds

        time.sleep(3)
    
        self.wfile.write(bytes(lineBreak, "utf8"))
        self.wfile.flush()
         
        # Content after .sleep() which should be rendered progressively
        
        afterSleep = "After Sleep"
    
        self.wfile.write(bytes(afterSleep, "utf8"))
        self.wfile.flush()

with HTTPServer(('', 8000), handler) as server:
    server.serve_forever()```
Safari / IOS WKWebView waiting for 250 bytes before rendering content. Delaying execution of external .js
 
 
Q