异步TypeScript运行时出现'callbackSuccess is not a function'错误的修复方案咨询
异步TypeScript运行时出现'callbackSuccess is not a function'错误的修复方案咨询
看起来你遇到的问题核心是:api.call的内部实现对回调函数的存在性有依赖,当用户没有显式传入回调时,它会尝试调用一个未定义的callbackSuccess函数,导致报错。我们可以通过修改eval包装的自执行函数,对api.call做一层透明的封装,自动处理回调缺失的情况,完全不用用户手动添加回调。
问题根源分析
从报错和你的测试结果来看,api.call的设计应该是双模式兼容:
- 如果最后一个参数是函数,就用回调模式执行,调用这个函数返回结果
- 如果没有传入回调,它可能期望用全局的
callbackSuccess/callbackError来处理结果,或者内部没有正确处理Promise的resolve逻辑,导致找不到回调函数报错
而你观察到的“部分请求成功、部分失败”的随机现象,大概率是api.call内部的同步/异步分支逻辑导致的:比如小数据量可能同步执行,刚好绕过了回调检查;大数据量异步执行时,就会触发未定义的callbackSuccess。
最优修复方案:包装api.call为Promise优先的方法
我们可以在eval的自执行函数里,先对api.call做一层代理包装,自动补全回调并转化为Promise,同时兼容原有的回调写法。这样用户既可以用现代的await语法直接获取结果,也可以保留原有的回调写法,完全不需要修改自己的脚本。
修改后的eval代码如下:
eval(`(async (api) => { // 保存原始的api.call方法 const originalCall = api.call; // 重写api.call,自动处理回调缺失的情况 api.call = function(...args) { // 检查用户是否传入了回调函数(最后一个参数是函数) const hasCallback = typeof args[args.length - 1] === 'function'; if (hasCallback) { // 如果有回调,直接调用原始方法,保持原有行为 return originalCall.apply(this, args); } else { // 如果没有回调,返回一个Promise,手动绑定success/error回调 return new Promise((resolve, reject) => { // 给参数列表添加我们自己的成功/失败回调 args.push( (data) => resolve(data), // 成功时resolve Promise (error) => reject(error) // 失败时reject Promise ); // 调用原始的api.call originalCall.apply(this, args); }); } }; try { // 执行用户的脚本,现在用户可以直接用await获取结果 await ${script}; } catch (error) { console.error('脚本执行错误:', error); } })(api);`);
方案说明
- 完全透明的封装:用户的脚本不需要做任何修改,原来的
api.call(...)写法可以直接用,加上await就能拿到结果:// 用户现在可以这么写,不用加回调 const result = await api.call("Get", { "typeName": "TYPENAME", "fromDate": "2025-06-11T04:00:00.000Z", "toDate": "2025-06-12T03:59:59.000Z" }); console.log(result); // 直接拿到数据 - 兼容原有回调写法:如果用户习惯用回调,原来的代码依然可以正常运行,不会有任何影响
- 解决随机报错问题:不管
api.call内部是同步还是异步执行,我们都手动传入了合法的回调函数,彻底避免callbackSuccess is not a function的报错
备选方案:注入全局的callbackSuccess函数
如果api.call的内部实现是硬编码依赖全局的callbackSuccess函数(而不是通过参数传递),我们可以在eval的上下文中临时注入这个函数,用完再清理:
eval(`(async (api) => { // 临时注入全局的回调函数 globalThis.callbackSuccess = (data) => { // 这里可以把数据赋值到你期望的地方,比如某个全局变量,或者直接打印 console.log('自动捕获的返回结果:', data); // 如果需要让用户的脚本能拿到数据,可以把data挂载到api对象上,比如api.lastResult = data }; globalThis.callbackError = (error) => { console.error('自动捕获的请求错误:', error); }; try { await ${script}; } catch (error) { console.error('脚本执行错误:', error); } finally { // 用完清理,避免污染全局环境 delete globalThis.callbackSuccess; delete globalThis.callbackError; } })(api);`);
注意:这个方案的局限性比较大,因为它只能捕获结果但无法让用户的脚本直接通过
const result = api.call(...)拿到数据,更适合临时调试,优先推荐第一种Promise包装方案。
为什么这个方案能解决你的问题?
通过包装api.call,我们强制所有调用都有合法的回调函数:
- 当用户没传回调时,我们自动添加了绑定到Promise的回调,从根源上避免了
callbackSuccess未定义的报错 - 同时把
api.call转化为支持await的Promise方法,符合现代JavaScript的开发习惯,用户的代码会更简洁
内容来源于stack exchange
相关产品推荐
相关产品推荐

