1
async function sleep(msecs){

    if (!somebodyAwaitsMe())            // that's the unknown
        throw ("call me with await");

    return new Promise(resolve => setTimeout(resolve, ms));
}

await sleep(5000);                    // correct

sleep(5000);                     // forgot await, returns immediately,

I want to know, inside an async function, if it has been called with await or not, is that possible?

The code exemplifies a possible situation to help detect mistakes but it may be useful in other situations where a function may be invoked by design, with or without await.

tru7
  • 6,348
  • 5
  • 35
  • 59
  • 2
    I don't think that's an issue you should worry about. There are many ways to incorrectly call a function, and you can't cover all those cases. This is a job for a static analysis tool, not runtime code. – deceze Mar 15 '18 at 10:38
  • 2
    To add to what deceze said, more specifically this: https://eslint.org/docs/rules/require-await – devius Mar 15 '18 at 10:41
  • Thanks for the require-await that will be useful. Anyway this was a simple example, in fact I needed it for another more complex case when the function is not always invoked with await. – tru7 Mar 15 '18 at 10:45
  • 1
    For now, async functions are just promises and generators under the hood. That means that your question could be asked as follow : `Is it possible to know if a then method wil be called after my function call from inside that function ?`. Formulated this way, it's clear that there is no easy solution – Logar Mar 15 '18 at 10:49
  • @Logar, yeah, it seems not easy, that's why I asked but seeing the call stack in the debugger it's clear if it is or isn't ... – tru7 Mar 15 '18 at 10:54
  • I did not test it and I would never do this, but [this](https://stackoverflow.com/questions/16697791/nodejs-get-filename-of-caller-function/23890280) might help you : get the caller function, call toString() on it, parse it to identify your `sleep` call, and check that await is used... I don't want to post this as an answer because I don't think it's the right thing to do – Logar Mar 15 '18 at 11:13

1 Answers1

5

No, this is not possible (without a debugger). And it's not the responsibility of your function anyway to check what its caller does. You should just always return your promise.

While you cannot inspect and verify the code of your caller (or its caller or …) if for security reasons alone, or also because static analysis is hard, you still can dynamically observe whether your promise is awaited. All you need to do is emit a warning when the .then() method isn't called immediately:

function expectMethodInvocation(o, p) {
    const t = setTimeout(() => {
        console.warn("You should call my "+p+" method!");
        delete o[p];
    }, 0);
    o[p] = function(...args) {
        clearTimeout(t);
        delete o[p];
        return o[p].call(this, ...args);
    };
    return o;
}

function sleep(ms) {
    const p = new Promise(resolve => setTimeout(resolve, ms));
    return expectMethodInvocation(p, "then");
}

(async function() {
    await sleep(1000);
    console.log("OK");
    sleep(1000); 
    console.log("Ooops");
})();
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • thank you! it works perfectly, you can even, in debug, find the caller deep in the stack – tru7 Mar 15 '18 at 17:26