Node exits without error and doesn't await promise (Event callback)

I've got a really weird issue whereby awaiting a Promise that has passed its resolve to an event-emitter callback just exits the process without error.

const {EventEmitter} = require('events');

async function main() {

  let ev = new EventEmitter();

  let task =  new Promise(resolve=>{
    ev.once("next", function(){resolve()}); console.log("added listener");

  await task;



process.on("uncaughtException", (e)=>console.log(e));

I'm expecting the process to halt when I run this because clearly "next" is currently never emitted. but the output I get is:

added listener

and then the nodejs process terminates gracefully.

I thought it was something to do with the Garbage Collector, but ev and task are clearly still in scope on main. So I'm really at a loss as to why the process exits entirely without error.

Obviously I would eventually emit the event, but I've simplified my code to the above to reproduce. I'm on node v8.7.0. Is there something wrong with my code or is this a node bug?



This question is basically: how does node decide whether to exit the event loop or go around again?

Basically node keeps a reference count of scheduled async requests — setTimeouts, network requests, etc.. Each time one is scheduled, that count increases, and each time one is finished, the count decreases. If you arrive at the end of an event loop cycle and that reference count is zero node exits.

Simply creating a promise or event emitter does not increase the reference count — creating these objects isn't actually an async operation. For example, this promise's state will always be pending but the process exits right away:

const p = new Promise( resolve => {
    if(false) resolve()


In the same vein this also exits after creating the emitter and registering a listener:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

If you expect Node to wait on an event that is never scheduled, then you may be working under the idea that Node doesn't know whether there are future events possible, but it does because it keeps a count every time one is scheduled.

So consider this small alteration:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

const timer = setTimeout(() => ev.emit("event", "fired!"), 1000)
// ref count is not zero, event loop will go again. 
// after timer fires ref count goes back to zero and node exits

As a side note, you can remove the reference to the timer with: timeout.unref(). This, unlike the previous example, will exit immediately:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

const timer = setTimeout(() => ev.emit("event", "fired!"), 1000)

There's a good talk about the event loop by Bert Belder here that clears up a lot of misconceptions:


As a general note, your code is combining three similar, but different methods: async/await, promises, event listeners. I'm not sure what you mean by "bombs out." But looking at the code, the result seems expected.

Your process exits, because you called promise on adding your event listener. It successfully resolves, and therefore exits. If you try to log task, it will give you undefined. Instead of logging "exit" in your then statement, log the result. Task will be undefined since the program does not wait to resolve its value and its "code block has finished".

You can simplify your code to the following. As you can see it resolves immediately since you call the resolve function.

const { EventEmitter } = require('events');

let ev = new EventEmitter()
var p = new Promise(( resolve ) => {
    ev.once("next", resolve("Added Event Listener"));

    .then(res => console.log(res))
    .catch(e => console.log(e))


Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.