Created
September 23, 2019 04:28
-
-
Save numtel/79097f61519f41ed9da5ea8e49fad60b to your computer and use it in GitHub Desktop.
Node.js server example for chunked server events response handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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