📜 ⬆️ ⬇️

We show the work process of a continuous task on the server using one connection.

I needed to show the interactive execution of the script to the user. I implemented a multi-threaded PHP bot that performs a background task while receiving execution requests. The results of his activities, he writes in the database. Next, I had to somehow inform the user about the process.

Usually, in this case, for example, a long request is made, at the end of which the current status is answered from the server, after which it is repeated again, or the status is checked every couple of seconds. But I wanted to realize this in a more lively form, using one connection.

The resulting method can be used to continuously receive a response from the server and processing it in parallel without interruption. That is, it is possible not only to use it to obtain the state of readiness of the process, but also, for example, it is possible to process huge data in the process of obtaining it, without waiting for it to be fully loaded.

How are we going to act?


The method is to force the PHP script to give the data to the client in predetermined portions. And in the reception of these portions on the client side.
')
Unfortunately, many browsers do not know how to properly handle the data transfer status in AJAX, so we will do conditional data synchronization in seconds. Every 2 seconds we will reset the data from the server, and every 2 seconds we will check the arrival of new data on the client side. In this case, inconsistencies often occur, some data has come already newer than needed, or there is no new data yet. I will consider only the first case, since It is assumed that your ping is high enough to ensure the arrival of data in abundance.

We force the server to give the data


To do this, we need to disable all compression methods, tell the browser that we are transmitting the stream, and force it to reset all output data to the user.

Also one of the most data points - you must close the recording of an open session. The fact is that PHP cannot open the same session in two parallel threads, so if your process runs and uses a parallel request, it will hang in the queue. As a result, all AJAX functions will be paralyzed.

header('Content-Encoding: none;'); //  header('Content-type: application/octet-stream'); //   ini_set('output_buffering', 'off'); //     php ini_set('zlib.output_compression', false); //         ini_set('implicit_flush', true); ob_implicit_flush(true); //    ,          (!) session_write_close(); for ($i = 0;$i < 20; $i++) { echo '|'.$i.str_repeat(' ', 4096).PHP_EOL; flush(); sleep(2); } 

Above, I use the separator | to output only fresh data and divide the transferred data into logical parts.

Notice - we hammer in extra 4096 bytes to force the packet to be sent to the user. Otherwise, the web server will cache the data until it is collected in the necessary packet to send. Perhaps there is a method to send without it, I will be ready to listen to the decisions in the comments.

The script above will transmit numbers from 0 to 19 every 2 seconds. The browser will display only the most recent data.

Client part


 var xhr; var timerlive; function live(cont){ try{ xhr.abort(); }catch(e) { } var temp; clearTimeout(timerlive); var prevtext = ''; xhr = new XMLHttpRequest(); xhr.open('POST', 'ajax.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send("type=live"); timerlive = setInterval(function() { if (xhr.readyState == 4) { clearTimeout(timerlive); } temp=xhr.responseText.substring(prevtext.length); $('#'+cont).html(temp.substr(temp.lastIndexOf("|")+1)); prevtext = xhr.responseText; }, 2000); } function breaklive(){ try{ xhr.abort(); }catch(e) { } clearTimeout(timerlive); } 


Calling the live () function will first interrupt the previous live channel, and then initialize a new connection to the server. We will record old data to know the starting point for new data. Also using the delimiter | we will trim only the most recent data from the obtained. In general, you can simply separate only the most recent data, but you can process all the new data, if you for example generate an online log.

Below is a function to interrupt the connection, it can be embedded in your AJAX scripts so that when you switch to another page, you close the connection.

Source: https://habr.com/ru/post/252983/


All Articles