点击取消Promise时出现"undefined is not a function"错误求助
问题原因及解决办法
核心问题
你碰到的undefined is not a function错误,本质是在promiseReject被赋值前就调用了它——比如先点拒绝按钮,或者go函数还没执行到sleep逻辑时就触发拒绝操作。另外当前写法还存在多次调用go时,promiseReject会被覆盖的问题,可能导致旧的定时器无法被正确清理。
修复方案
1. 最小改动:增加调用前判断
不想大改代码的话,先给拒绝按钮加个判断,避免调用未定义的函数,同时在sleep执行完成或取消后重置变量:
let promiseReject const sleep = seconds => new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { resolve() promiseReject = undefined // 超时后重置 }, seconds * 1000) promiseReject = () => { clearTimeout(timeoutId) reject() promiseReject = undefined // 取消后重置 } }) const go = async () => { try { await sleep(10) // 超时完成后的逻辑 } catch (err) { // 被取消后的逻辑 console.log('睡眠已取消') } } // 触发睡眠的按钮 <TouchableOpacity onPress={() => { go() }} > </TouchableOpacity> // 取消睡眠的按钮 <TouchableOpacity onPress={() => { promiseReject?.() // 用可选链避免调用undefined }} > </TouchableOpacity>
2. 推荐方案:用类管理睡眠实例
全局变量容易出问题,用类封装每个睡眠实例的状态和操作,避免覆盖问题:
class SleepController { constructor() { this.rejectFn = null this.timeoutId = null } sleep(seconds) { return new Promise((resolve, reject) => { this.rejectFn = reject this.timeoutId = setTimeout(() => { resolve() this._reset() }, seconds * 1000) }) } cancel() { if (this.rejectFn && this.timeoutId) { clearTimeout(this.timeoutId) this.rejectFn() this._reset() } } _reset() { this.rejectFn = null this.timeoutId = null } } // 创建一个睡眠控制器实例 const sleepController = new SleepController() const go = async () => { try { await sleepController.sleep(10) console.log('超时完成') } catch (err) { console.log('睡眠被取消') } } <TouchableOpacity onPress={() => { go() }} > </TouchableOpacity> <TouchableOpacity onPress={() => { sleepController.cancel() }} > </TouchableOpacity>
关键提醒
一定要用try/catch包裹await sleep,这样reject时才能捕获到取消状态,避免出现未处理的Promise报错。
内容的提问来源于stack exchange,提问作者JackFrost
相关产品推荐
相关产品推荐

