如何判断一个方法是不是异步的?
发布于 3 年前 作者 iori2882 7183 次浏览 来自 问答

请教一个困扰我好久的基础问题,如何判断一个方法是不是异步的? 比如,我自己写一个自定义函数 如果是下面这样的,肯定得用await包装一下才能顺序执行:

12.png

如果是下面这样的,那方法就不用加async了,直接写就能顺序执行:

13.png

上面例子举的有点极端,但是有的方法在调用的时候真的不知道是不是异步的?如何知道我 自己写的函数 到底用不用async封装一下?或者说如何知道一个方法是不是异步的呢?

17 回复

方法里面用了await的

其实最稳妥的方法就是,你要清楚这个函数的参数和返回值具体是什么,这样自然就知道它是不是异步的了。而如果确实不清楚具体的参数和返回值的含义,也可以通过一些通常都会遵循的代码风格来判断,例如:

  • 如果函数的声明是 async function xxx() 或者 async () 这样的;
  • 如果函数返回的是一个 Promise,如 return new Promise()
  • 如果函数最后一个参数是回调函数,如 xxx(a, b, callback)
  • 如果函数体内调用了一些已知的异步函数,比如 fs.readFile()

当然,说一千道一万还是抵挡不住各种风骚的代码写法,所以最可靠的还是要看文档,弄清楚这个函数的参数和返回值具体是什么。

看他返回的是不是Promise?

是否可以进行默认的约定,类似Nodejs。默认都是异步的函数,如果是同步的话,函数名上加上sync。

@theanarkh 赞同,配合使用 ts 完全不会有这个疑惑

“是不是”异步函数

本质上,只要你的代码,在函数 return 之后,还会执行,都算是异步函数,比如:

function f() {
  setTimeout(function() {
    console.log('是的')
  })
}

即使以前没有 async/await 关键字、没有 Promise,但当时,也有异步
不要去想“什么是异步函数?”,没意义

什么时候需要 async 关键字?

  • 如果你的函数里出现了 await 关键字,则必须使用 async
  • 否则,不需要使用 async

如何知道一个函数是不是异步的?

同第一个问题

建议

  • 如果刚入门前端,可以找个完整的教程,不要抱着“写着写着就会了”的心态

对普通方法也是可以await的

function foo() {
    console.log("foo()");
    return "haha";
}
(async function () {
    const r = await foo();
    console.log(r);
})()

如果你对一个函数不确定它是不是该await,那你直接await也没问题的 异步分两种:

  1. 有返回值的,但是它什么时候给你返回值是不确定的,最早是通过回调函数或者EventEmitter之类的东西来实现,原理都是一样的,就是告诉它你在什么地方等他的执行结果
  2. 没有返回值,就是6楼写的那种,准确的说这种是启动了一个异步的任务,你当前的程序并不需要关心它的运行结果,所以没有返回值。比如在后台运行一个机器人,你需要关心的是如何让它停下来

如果想简单地通过代码判断是否是 async function 的话可以:

(async () => {}) instanceof Object.getPrototypeOf(async function(){}).constructor

@yakczh 嗯 方法里用了await的肯定是同步的,但是我要确认的他是不是异步的 function f() { setTimeout(function() { console.log(‘是的’) }) } 比如上面的函数,如果我没实验过,我就不知道他是异步的

@leizongmin 我要确认的他是不是异步的,是不是同步的好确认~~~ function f() { setTimeout(function() { console.log(‘是的’) }) } 比如上面的函数,如果我没实验过,我就不知道他是异步的

@daGaiGuanYu 本质上,只要你的代码,在函数 return 之后,还会执行,都算是异步函数,比如: function f() { setTimeout(function() { console.log(‘是的’) }) }

现在疑惑的就是这个问题,同步的函数好确认,就是异步的函数我在用代码实验以前完全不知道他是不是异步的,比如上面的代码,我知道它是异步的,可能我用的时候就给他封装成同步的,但是有的函数我不知道他的执行到底是不是异步的,如果不是异步的就没必要二次封装了,我并不想为了保险起见,把所有的函数都给封装成同步的

@iori2882 这种就是你不需要它的运行结果的,只是启动了一个异步的任务,比如每隔一段时间去获取下数据、删除下文件什么的,如果是无关紧要的任务那也不需要关心它运行是否出错什么的,就是撒手不管了 如果是重要的任务那一定会通过一些信号量来控制它的运行

.constructor.name === ‘AsyncFunction’

@iori2882 异步函数不能封装成同步函数

说一千道一万还是抵挡不住各种风骚的代码写法,所以最可靠的还是要看文档,弄清楚这个函数的参数和返回值具体是什么。

不得不说,js的代码确实比其他语言更加风骚一点.

@iori2882 通过名称一般就可以判断出来这个函数是cpu敏感还是io敏感io敏感一般都是异步函数。io敏感的同步函数就那几个与文件操作相关的-Sync函数,主要是方便一些工具类脚本的编写,在服务环境是不建议使用的。

看官方文档吧,里面都会标注方法的返回是一个Promise<type>还是一个type, 如果是Promise配合await就很舒服

回到顶部