如何实现可迭代的类方法?解决「TypeError: Foo.my_method(...) is not a function or its return value is not async iterable」报错问题
如何实现可迭代的类方法?解决「TypeError: Foo.my_method(...) is not a function or its return value is not async iterable」报错问题
嘿,我来帮你揪出这个报错的根源,其实问题出在构造函数的返回值上!
你看,你的Foo构造函数里返回了一个异步函数的Promise:
constructor() { return (async () => { this.sleep(1000) })() }
这就导致new Foo()得到的不是Foo类的实例,而是一个Promise对象!后面你写的let foo = new Foo().then(...),这里的foo其实是then方法返回的Promise,不是真正的Foo实例——Promise对象当然没有my_method这个方法,所以才会抛出那个错误。
另外还有两个小细节要调整:一是构造函数里的this.sleep(1000)没加await,等于白执行;二是my_method里的while(true)会无限循环,最好加个终止条件(比如遍历完message的所有字符)。
下面给你两种可行的修正方案:
方案一:用静态异步工厂方法创建实例(推荐)
把异步初始化逻辑放到静态方法里,构造函数保持默认返回实例:
class Foo { constructor() { // 构造函数不做异步操作,返回默认的类实例 } // 静态工厂方法,负责异步初始化并返回实例 static async create() { const fooInstance = new Foo(); await fooInstance.sleep(1000); // 等待初始化的sleep完成 return fooInstance; } async *my_method(message) { let pos = 0; // 加终止条件,避免无限循环 while (pos < message.length) { yield message.charAt(pos); await this.sleep(100); pos += 1; } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // 使用方式 (async () => { const foo = await Foo.create(); const msgs = []; for await (let msg of foo.my_method("AAAA")) { msgs.push(msg); console.log(msg); // 会每隔100ms输出一个"A" } console.log(msgs); // 最终输出 ['A','A','A','A'] })();
方案二:用实例的init方法处理异步初始化
如果不想用静态方法,可以给实例加一个initializedPromise,确保异步初始化完成后再执行方法:
class Foo { constructor() { // 把异步初始化逻辑放到init方法,并用initialized保存Promise this.initialized = this.init(); } async init() { await this.sleep(1000); // 等待初始化完成 } async *my_method(message) { // 先等待初始化完成,再执行生成器逻辑 await this.initialized; let pos = 0; while (pos < message.length) { yield message.charAt(pos); await this.sleep(100); pos += 1; } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // 使用方式 (async () => { const foo = new Foo(); const msgs = []; for await (let msg of foo.my_method("AAAA")) { msgs.push(msg); console.log(msg); } console.log(msgs); })();
核心知识点总结
- 构造函数不要返回Promise(或其他非实例对象),否则
new Class()的结果就不是类实例了 - 你写的
async *my_method本身就是合法的异步生成器,只要调用它的是正确的Foo实例,就会是async iterable,符合for await...of的要求 - 类的异步初始化逻辑,尽量放到静态工厂方法或单独的init方法中,不要在构造函数里搞异步返回
备注:内容来源于stack exchange,提问作者rigiva
相关产品推荐
相关产品推荐

