Node runs all your Javascript on a single thread so it strongly discourages writing f(g(x)) if g is slow or expensive. Instead you write g(x, f) in continuation-passing style so the framework can start g (send a request or whatever), give up control, and do something useful when the result is available (a response arrives or whatever). But if g fails, either f has to expect to receive an error object that came from g, or you need some glue that checks that g succeeded before invoking f.
Eventually Javascript will probably let you write f(await g(x)) and transform one async function into a chain of Promises and continuation functions (await will throw if g fails), but it's not yet a standard part of the language and not everyone wants to preprocess this experimental dialect into something Node can run today.
Eventually Javascript will probably let you write f(await g(x)) and transform one async function into a chain of Promises and continuation functions (await will throw if g fails), but it's not yet a standard part of the language and not everyone wants to preprocess this experimental dialect into something Node can run today.