web-dev-qa-db-ja.com

関数が非同期かどうかを知る方法は?

関数を別の関数に渡し、コールバックとして実行する必要があります。問題は、この関数が時々非同期であるということです:

_async function() {
 // Some async actions
}
_

だから私はawait callback()またはcallback()を受け取りたい関数のタイプに応じて実行したい。

関数のタイプを知る方法はありますか??

51
Facundo Matteo

@rndと@estusの両方が正しいです。

しかし、実際の実用的なソリューションで質問に答えるために、あなたは行き​​ます

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*
    );
}

これは非常に有効な質問であり、私は誰かが彼に反対票を投じたことに腹を立てています。このタイプのチェックの主な使用例は、ライブラリ/フレームワーク/デコレータです。

これらは初期の段階であり、[〜#〜] valid [〜#〜]の質問に投票するべきではありません。

19
Chad Scira

私はこの簡単な方法を好む:

theFunc.constructor.name == 'AsyncFunction'
13
Alexander

NodeJS 10.x以降を使用している場合

ネイティブutil関数 を使用します。

   util.types.isAsyncFunction(function foo() {});  // Returns false
   util.types.isAsyncFunction(async function foo() {});  // Returns true

ただし、上記の懸念からすべての懸念を念頭に置いてください。偶然に約束を返すだけの関数は、偽陰性を返します。

そしてその上に(ドキュメントから):

これは、JavaScriptエンジンが表示しているもののみを報告することに注意してください。特に、トランスピレーションツールが使用された場合、戻り値は元のソースコードと一致しない場合があります。

ただし、NodeJS 10でasyncを使用し、トランザクションを使用しない場合。これは素晴らしい解決策です。

5
Ian Segers

awaitは通常の関数にも使用できるようです。 「良い習慣」とみなすことができるかどうかはわかりませんが、ここにあります:

async function asyncFn() {
  // await for some async stuff
  return 'hello from asyncFn' 
}

function syncFn() {
  return 'hello from syncFn'
}

async function run() {
  console.log(await asyncFn()) // 'hello from asyncFn'
  console.log(await syncFn()) // 'hello from syncFn'
}

run()
2
gyo

TL; DR

短い答え: exposinginstaceofの後にAsyncFunctionを使用します-以下を参照してください。

長い答え:それをしないでください-以下を参照してください。

どうやってするの

関数がasyncキーワードで宣言されたかどうかを検出できます

関数を作成すると、それが関数型であることを示します。

> f1 = function () {};
[Function: f1]

instanceof演算子でテストできます:

> f1 instanceof Function
true

非同期関数を作成すると、それがAsyncFunction型であることを示します。

> f2 = async function () {}
[AsyncFunction: f2]

したがって、instanceofでもテストできると期待されるかもしれません。

> f2 instanceof AsyncFunction
ReferenceError: AsyncFunction is not defined

何故ですか? AsyncFunctionはグローバルオブジェクトではないためです。ドキュメントを参照してください:

ご覧のとおり、Reference/Global_Objects...

AsyncFunctionに簡単にアクセスする必要がある場合は、私のunexposedモジュールを使用できます。

ローカル変数を取得するには:

const { AsyncFunction } = require('unexposed');

または、グローバルAsyncFunctionを他のグローバルオブジェクトと一緒に追加するには:

require('unexposed').addGlobals();

そして今、上記は期待通りに動作します:

> f2 = async function () {}
[AsyncFunction: f2]
> f2 instanceof AsyncFunction
true

なぜそれをしてはいけないのか

上記のコードは、関数がasyncキーワードで作成されたかどうかをテストしますが、本当に重要なのは、関数の作成方法ではなく、関数がプロミスを返すかどうかです。

この「非同期」機能を使用できるすべての場所:

const f1 = async () => {
  // ...
};

これも使用できます:

const f2 = () => new Promise((resolve, reject) => {
});

asyncキーワードを使用して作成されていないため、instanceofまたは他の回答に投稿された他のメソッドと一致しません

特に、これを考慮してください:

const f1 = async (x) => {
  // ...
};

const f2 = () => f1(123);

f2f1はハードコーディングされた引数であり、asyncをここに追加することは、結果がf1あらゆる点で。

概要

したがって、関数がasyncキーワードを使用して作成されたかどうかを確認することは可能ですが、それをチェックするときに何か間違ったことをしている可能性が高いため、注意して使用してください。

2
rsp

最初はコールバックが約束されていると仮定できます:

export async function runSyncOrAsync(callback: Function) {

  let promisOrValue = callback()
  if (promisOrValue instanceof Promise) {
    promisOrValue = Promise.resolve(promisOrValue)
  }
  return promisOrValue;
}

あなたのコードでこれを行うことができます:

await runSyncOrAsync(callback)

これにより、コールバックタイプを知らないという問題が解決されます。

0

ヘイ、

以下は、David Walshが blogpost で提供しているアプローチです。

const isAsync = myFunction.constructor.name === "AsyncFunction";

乾杯!

0
theVoogie