the question is considered in the context of native code
without the towers of Babel and other transpilers !

why might it be necessary?

here is a simple example
there is a function to measure the execution time of another function

/** * @param _f функция */ test(_f) { if (!_f) throw new TypeError('!_f') let result = null // результат выполнения функции let time = null try { time = performance.now() // засекаем время result = _f() // вызоваем тестируемую функциию time = performance.now() - time // вычисляем время } catch (_e) { time = null console.log(_e) } return time } 

there are three test functions

 function foo() { return 'res' } async function bar() { return 'res' } function baz() { return Promise.resolve('res') } 

if we try to test them

 console.log('foo',lib.test(foo))//foo 0.10000006295740604 console.log('bar',lib.test(bar))//bar 0.20000000949949026 console.log('baz',lib.test(baz))//baz 0.09999994654208422 

then we will get the result, it will even look like a real one, BUT THIS IS NOT SO

 void function() { /** * @param _f функция */ let test = (_f) => { if (!_f) throw new TypeError('!_f') let result = null // результат выполнения функции let time = null try { time = performance.now() // засекаем время result = _f() // вызоваем тестируемую функциию time = performance.now() - time // вычисляем время } catch (_e) { time = null console.log(_e) } return [time, result] } function foo() { return 'res' } async function bar() { return 'res' } function baz() { return Promise.resolve('res') } console.log('foo', test(foo)) //foo (2) [0.10000006295740604, "res"] console.log('bar', test(bar)) //bar (2) [0.09999994654208422, Promise] //<-- !!!Promise console.log('baz', test(baz)) //baz (2) [0.09999994654208422, Promise] //<-- !!!Promise }() 

    1 answer 1

    so.
    First, a sample code that detects a promis or an asynchronous function, in which case time and result null .

    Please pay attention to two blocks:

    • #region проверка на страрте
    • #region проверка в процессе

     void function() { /** * @param _f функция */ let test = (_f) => { //#region проверка на страрте if (!_f || !(_f instanceof Function)) throw new TypeError('!_f of _f not Function') // -- // if (_f[Symbol.toStringTag] === 'AsyncFunction') throw new TypeError('AsyncFunction') // -- // const AsyncFunction = (async () => {}).constructor; // if (_f instanceof AsyncFunction) throw new TypeError('AsyncFunction') // -- //#endregion проверка на страрте let isPromiseOrAsync = (_f) => (_f == Promise.resolve(_f)) //проверка в процессе let result = null // результат выполнения функции let time = null // время выполнения try { time = performance.now() // засекаем время result = _f() // вызоваем тестируемую функциию time = performance.now() - time // вычисляем время //#region проверка в процессе if (isPromiseOrAsync(result)) { result = null throw new TypeError('PromiseOrAsync') } //#endregion проверка в процессе } catch (_e) { time = null console.log(_e) } return [time, result] } function foo() { return 'res' } async function bar() { return 'res' } function baz() { return Promise.resolve('res') } console.log('foo', test(foo)) //foo (2) [0, "res"] //TypeError: PromiseOrAsync console.log('bar', test(bar)) //bar (2) [null, null] //TypeError: PromiseOrAsync console.log('baz', test(baz)) //baz (2) [null, null] }() 

    #region проверка на страрте

    Of course, it is preferable to perform TypeError detection at the very beginning of the function, and in the case of asynchronous functions this is possible, not in the case of promise.

    asynchronous function detection

    I will give two examples taken from stackoverflow.com

    1. first example:

       if (_f[Symbol.toStringTag] === 'AsyncFunction') throw new TypeError('AsyncFunction') 
    2. second example:

       const AsyncFunction = (async () => {}).constructor; if (_f instanceof AsyncFunction) throw new TypeError('AsyncFunction') 

    and one from here at stackoverflow.com

     function isAsync (func) { const string = func.toString().trim(); return !!( // native string.match(/^async /) || // babel (this may change, but hey...) string.match(/return _ref[^\.]*\.apply/) // insert your other dirty transpiler check // there are other more complex situations that maybe require you to check the return line for a *promise* ); } 

    promise detection

    1. out of

    #region проверка в процессе

    And so, let's talk about promises, and what is a 'check in process'

    what is a 'check in process'

    look, there is a baz function

     function baz() { return Promise.resolve('res') } 

    it is a function, just a function, the most ordinary
    but she returns promis
    but we will not know about it until we call it (we do not take into account the third example given earlier)

     void function() { function baz() { return Promise.resolve('res') } let p = baz() console.log('baz', p instanceof Promise) //baz true console.log('baz', p.then !== void 0) //baz true //<---категорически не рекомендую async function bar() { return 'res' } let a = bar() console.log('bar', a instanceof Promise) //bar true console.log('bar', a.then !== void 0) //bar true let isPromiseOrAsync = (_o) => (_o == Promise.resolve(_o)) //проверка в процессе console.log('baz', isPromiseOrAsync(p)) //baz true console.log('bar', isPromiseOrAsync(a)) //bar true }() 

    I personally liked the isPromiseOrAsync method peeking here source . The author of the answer refers to the specs, gives proofs and complains about the instanceof method and safari.