This doesn't look like a nice approach. For one, what's that 25ms waiting like polling? You don't really need it. So assuming that you're working with WebSockets like // Create WebSocket connection. const socket = new WebSocket('ws://localhost:8080'); // Listen for messages socket.addEventListener('message', (event) => { console.log('Message from server ', event.data); }); You may turn the async "message" event listener into an iterable and consume it in a `for await of` loop as folows. <!-- begin snippet: js hide: false console: true babel: false --> <!-- language: lang-js --> function wsMessageStream(url){ let _v, // previous resolve _x, // previous reject _msg = new Promise((v,x) => (_v = v, _x = x)), ws = new WebSocket(url); async function* emitterGen(ws){ ws.addEventListener("open", _ => ( _v({data: `Esatablished WebSocket connection for ${url}.`}) , _msg = new Promise((v,x) => (_v = v, _x = x)) )); ws.addEventListener("close", _ => ( _v({data: `Closed WebSocket connection for ${url}.`}) , _v = null , _x = null )); ws.addEventListener("message", msg => ( _v(msg) , _msg = new Promise((v,x) => (_v = v, _x = x)) )); ws.addEventListener("error", err => ( _x(err) , _msg = new Promise((v,x) => (_v = v, _x = x)) )); while (_v || _x){ try{ yield _msg; } catch(e){ console.log(e); } } } return { stream: emitterGen(ws) , socket: ws }; } let {stream,socket} = wsMessageStream('wss://ws.postman-echo.com/raw'), counter = 0; setTimeout(_ => socket.close(), 5000); (async function(){ for await (let msg of stream){ console.log(`Message received: ${msg.data}`); // run msg handlers here socket.readyState === 1 && socket.send(`Thank you. ${counter++}`); } })(); <!-- end snippet -->