LoginSignup
12
11

More than 5 years have passed since last update.

[JavaScript] ある関数がasyncか判定する

Last updated at Posted at 2018-02-22

問題

以下の関数isAsyncをどう実装すればよいか。

async function a() {
  return "a";
}
function b() {
  return "b";
}

function isAsync(func) {
  // もしfuncがasyncならtrueを返す
  // そうでないならfalseを返す
}

console.log(isAsync(a)); // => true
console.log(isAsync(b)); // => false

回答

function isAsync(func) {
  return func.constructor.name === "AsyncFunction";
}

詳細は言語仕様を参照。

上の実装では不安な人のために、より神経質な回答も用意してある。

function isAsync(func) {
  return Object.getPrototypeOf(func) === Object.getPrototypeOf(async function () {});
}

注意点

ある関数が非同期関数か判定するものではないことに注意してほしい。
あくまで、ある関数がasyncとして定義されたか判定するものである

例えばPromiseを返す関数は、実用的には、asyncとして定義された関数同様に非同期関数として見なされるものであるが、isAsyncに入れるとfalseが返ってくる。

function c() {
  return Promise.resolve("c")
}

console.log(isAsync(c)); // => false

より実用的には、ある関数がPromiseを返すか判定することができればよいのかもしれない。
しかし、それも以下のような関数をどう判定すればよいのかという問題が残る。

function wtf() {
  if (Math.floor(Math.random() * 2) === 0) {
    return Promise.resolve("I'm an asynchronous function!");
  } else {
    return "I'm a synchronous function!";
  }
}

ある関数が非同期関数かどうかというのは、多分に人間の主観が混ざってくる話で、もし何らかの客観的な基準を設けられたとしても、その基準を判定することは原理的に不可能か少なくとも簡単なコードでは不可能であることが多いだろう。
その中でも、「asyncとして定義されているかどうか」という基準は、実用的に微妙ではあるが、簡単なコードで判定が可能な例である。

ES2018に関する補足

ES2018に入ると目されているasync generator functionisAsynctrueが返ってくるようにしたいのであれば、isAsyncのコードを少し修正する必要がある。

async function* d() {
  return "d";
}

function isAsync(func) {
  return func.constructor.name === "AsyncFunction"
    || func.constructor.name === "AsyncGeneratorFunction";
}

console.log(isAsync(d)); // => true

詳細はDraftを参照。

参考リンク

Programmatically check if function is async · Issue #78 · tc39/ecmascript-asyncawait

12
11
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11