这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
最近在Sentry上看到某个项目偶尔会有零星的xxx is not a function
的错误上报,仔细查看发现,报错的是诸如JSONP_1628781407874
这样的方法名触发的。
详情
很明显,这是一个jsonp请求的回调函数,例如:
$.ajax({
url: 'https://foo.com/my/info',
dataType: 'jsonp',
jsonp: 'jsonpcb',
timeout: 5000,
success: function(data) {
console.log(data);
// some logic
},
error: function(e) {}
})
复制代码
然后,服务器返回内容:
JSONP_1628781407874({"code":0,"data":{"name":"Jack","age":22}})
复制代码
那为何会触发运行时错误呢,通过查看该接口的请求时长分布,发现有部分用户的时长会达到10s甚至更久。接着模拟类似情景会发现,超时之后console会报错Uncaught TypeError: JSONP_1628781407874 is not a function
。
显然,jsonp请求方法会在等待时间超过timeout之后,把声明在window
下的方法JSONP_1628781407874
给移除了。
解决方案
方案一
既然如此,最直接的处理方式就是,不让它删除掉回调函数。但是,这明显是会有问题的,如果一个页面有大量的jsonp请求的话,window
上就会挂在越来越多这些回调函数,而且这些回调函数本身就是一次性使用。
所以,这个方案不可行。
方案二
- 定义一个超时的通用处理函数(包含接口超时事件上报等逻辑)
- 在触发成功或者错误时才进行删除回调函数,超时的话则使用一个把回调函数的变量指向上面定义的超时通用处理函数,当超时的请求返回数据时,执行上报逻辑。
方案可行
方案三
不改动原有jsonp处理逻辑,但是要求服务器的jsonp接口返回时,外面多包裹一层try-catch代码,例如:
try { JSONP_1628781407874({"code":0,"data":{"name":"Jack","age":22}}) } catch(e) {}
复制代码
使得即使超时导致回调函数被删除,也不会触发运行时报错。
方案可行,但需要后端同事配合改造
结语
最后,我们顺便捋一下jsonp的工作原理
- 创建并插入script标签,声明要请求script静态资源的路径(也就是支持jsonp的接口路径)
- 在路径的参数上,按照与后端同事的约定,传递执行回调的函数名给服务器
- (如有)声明timeout的时长,设置定时器,到达指定时长执行错误处理
- {服务器}接收请求,获取结果后,用前面收到的函数名包裹数据返回到前端页面
- 接收到返回数据,执行回调函数
- 删除回调函数
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END