Cordova应用中async函数作为事件监听回调报错的原因咨询
让我来帮你拆解这两个问题的本质:
1. 事件监听器直接调用async函数存在什么问题?
你这里的问题根本不是async函数的锅,而是传参方式错了!看你的代码:
window.addEventListener("load", loadEdit(), false);
你写的loadEdit()是立即执行这个async函数,并把它的返回值(一个Promise对象)传给了addEventListener当事件处理器。
而addEventListener要求第二个参数必须是一个可调用的函数,或者是一个实现了handleEvent方法的对象。但Promise对象并没有handleEvent方法,所以当浏览器触发load事件、尝试调用这个“处理器”的时候,就会抛出TypeError: Property 'handleEvent' is not callable的错误。
哪怕你的函数不是async的,只要写成loadEdit()这种带括号的形式,都会出问题——比如普通函数执行后返回undefined,浏览器同样会因为找不到可调用的处理器报错,只是错误信息可能不同。
2. 为何第二种间接调用的方式不会触发该错误?
先纠正下你示例代码里可能的笔误:我猜你实际写的是window.addEventListener("load", loadPre, false);(不带括号),而不是loadPre()——如果是带括号的话,其实和第一种情况一样,传的是loadPre执行后的返回值(undefined),浏览器根本不会触发它。
回到问题本身:当你把普通函数loadPre(函数引用,不是执行结果)传给addEventListener时,它符合事件处理器的要求——是一个可调用的函数。当load事件触发时,浏览器会调用loadPre,然后在loadPre内部再调用loadEdit()。
这时候,loadEdit的返回值(Promise)只是作为普通函数调用的结果被忽略,不会被addEventListener当成处理器来调用,自然就不会触发类型不匹配的错误。
顺便提一句,如果你想直接用async函数当事件处理器,正确的写法应该是这样:
// 方式1:直接传函数引用(不加括号) window.addEventListener("load", loadEdit, false); // 方式2:用箭头函数包裹(如果需要给loadEdit传参数的话) window.addEventListener("load", () => loadEdit(), false);
这样就不会报错了,因为传给监听器的是一个可调用的函数,async函数的Promise返回值不会被监听器误判成处理器。
内容的提问来源于stack exchange,提问作者David E.

