Skip to content

Instantly share code, notes, and snippets.

@numtel
Created September 23, 2019 04:28
Show Gist options
  • Save numtel/79097f61519f41ed9da5ea8e49fad60b to your computer and use it in GitHub Desktop.
Save numtel/79097f61519f41ed9da5ea8e49fad60b to your computer and use it in GitHub Desktop.
Node.js server example for chunked server events response handling
const http = require('http');
const url = require('url');
const querystring = require('querystring');
http.createServer((req, res) => {
const parsedUrl = url.parse(req.url);
switch(parsedUrl.pathname) {
case '/task':
// Browser RPC method
const PROGRESS_COUNT = 10, PROGRESS_INTERVAL = 300;
const globalHandlerKey = querystring.parse(parsedUrl.query).x;
const sendMessage = (value, done) =>
res.write(
// This will be executed as the browser receives it
'<script>' +
// Inside iframe, there is a window.parent property
// referencing the parent window property
'parent.' +
// Each invokation has a different callback endpoint
globalHandlerKey +
// Invoke the callback with the current status
'(' + JSON.stringify({ done, value }) + ')' +
// Script must finish to parse javascript
'</script>');
res.writeHead(200, {
// Charset allows partial rendering
// From https://stackoverflow.com/a/11210088
'Content-Type': 'text/html; charset=UTF-8',
});
// Queue up each progress message
for(let i=0;i<=PROGRESS_COUNT;i++) {
setTimeout(() => {
if(i<PROGRESS_COUNT) sendMessage(i); else {
sendMessage('Done', true);
res.end();
}
}, PROGRESS_INTERVAL * i);
}
break;
case '/':
// Test frontend
res.writeHead(200, { 'Content-Type': 'text/html; charset=UTF-8' });
res.write(`
<html>
<body>
<script>
// Wrapper for multiple concurrent requests
function task(handler) {
var key;
while(!key || key in window)
key = '__' + Math.random().toString(36).slice(2);
var frame = document.createElement('iframe');
frame.src = '/task?x=' + key;
frame.style = 'display:none';
document.body.appendChild(frame);
window[key] = msg => {
if(msg.done) {
document.body.removeChild(frame);
delete window[key];
}
handler(msg.value);
};
}
</script>
<button onclick="task(x=>event.target.innerHTML=x)">Start</button>
</body>
</html>
`);
res.end();
break;
default:
res.writeHead(404);
res.end('Not found');
}
}).listen(3000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment