Search code examples
node.jsmeteorasync-awaitpromise

Promise.await() vs. Top-Level Await?


This does not work:

function myFunction(myObject){
    let IM = await connectors.myModel.update({
        myField: true,
    }, {
        where: {id: myObject.id},
        returning: true,
    });
}

But this does work:

function myFunction(myObject){
    let IM = Promise.await(connectors.myModel.update({
        myField: true,
    }, {
        where: {id: myObject.id},
        returning: true,
    }));
}

I understand that you can't use await outside of an async function. What's the difference between Promise.await() and the upcoming node.js feature, Top-Level await?


Solution

  • Fibers and Promise.await

    Meteor uses fibers (coroutines, repo here) under the hood to support asynchronous programming. This is why you can write in Meteor synchronous-style code on the server, allthough it may be async in nature:

    const doc = MyCollection.findOne()
    doc.someProp // yeay it's there without await
    

    Same goes with Promise.await, which uses the current fiber as execution environment. You can run the following code in a Meteor Method:

    Meteor.methods({
      test () {
        const someAsyncFn = async () => 'foo'
        const foo = Promise.await(someAsyncFn())
        return foo // 'foo'
      }
    })
    

    Top-Level await and native async/await

    Now you amy wonder why in 2022 Meteor still won't use real antive async/await. Simply it's a 10 year old framework with high stability and backwards compatibility. The step towards native async/await requires to drop fibers, which itself is deeply built into the core of Meteor!

    However, the discussion to move to native async/await already led to development of it: https://github.com/meteor/meteor/discussions/11505

    With upcoming Meteor 2.8 there will be the first native async/await support. Top-Level async will be available after that and is still wip.

    What should I do?

    For now you should start slowly rewriting code to async/await with beginning of Meteor 2.8 and try to avoid Promise.await unless not possible otherwise.

    You can already write server methods async-style without affecting behaviour that much:

    Meteor.methods({
      test: async function () {
        const someAsyncFn = async () => 'foo'
        const foo = await someAsyncFn()
        return foo // 'foo'
      }
    })
    

    For now you can't use top-level await and need to wrap it in an IIFE block:

    (async () => {
    
    })()
      .then(res => {})
      .catch(e => {})