当前位置:   article > 正文

chrome vue插件_一个element.__vue__引发的馒头

chrome插件使用elemen vue demo

最近出现了一个测试环境页面卡死的问题,打开页面一会之后就死掉了,如下图所示:

7665f052ec11201753d78c099b84b212.png

因为一打开页面就卡住了,控制台也卡得比较厉害,动不了,所以不太好调试,在卡死之际Chrome提示是内存超了:

d279674275daeda41cd48c8d1c8eefe1.png

怀疑是有个死循环造成的,通过Chrome提供的调用栈发现可能和加入的sentry上报错误插件有关(sentry是一个前端错误追踪上报的库),这个插件会监听Vue.config.errorHandler以上报错误:

ca0c66ddf37aa05dd8572f8369d7477c.png

猜测是这个插件引起的,注释掉之后果然好了。

把测试环境的数据mock到本地复现,经过一番debug,发现原因是这样的。

2d92605a7ecadaf4c52824cf7e1aeadf.png

sentry会把Vue组件的props取出来进行normalize格式化,如下代码所示:

  1. /**
  2. * normalize()
  3. *
  4. * - Creates a copy to prevent original input mutation
  5. * - Skip non-enumerablers
  6. * - Calls `toJSON` if implemented
  7. * - Removes circular references
  8. * - Translates non-serializeable values (undefined/NaN/Functions) to serializable format
  9. * - Translates known global objects/Classes to a string representations
  10. * - Takes care of Error objects serialization
  11. * - Optionally limit depth of final output
  12. */
  13. export function normalize(input, depth) {
  14. try {
  15. // tslint:disable-next-line:no-unsafe-any
  16. return JSON.parse(JSON.stringify(input, function (key, value) { return walk(key, value, depth); }));
  17. }
  18. catch (_oO) {
  19. return '**non-serializable**';
  20. }
  21. }

格式化的目的主要是为了上报,如下图所示:

8bb7aae22b899ac252ae2f142ecf1487.png

在这个格式化里面出了问题,它会递归遍历所有prop的属性,并且会访问有没有toJSON函数:

  1. // If value implements `toJSON` method, call it and return early
  2. // tslint:disable:no-unsafe-any
  3. if (value !== null && value !== undefined && typeof value.toJSON === 'function') {
  4. return value.toJSON();
  5. }

如果你把某一个组件的根DOM元素(this.$el)传给了另一个组件作为prop,这个时候这个元素就会被遍历到,包括这个元素的所有子属性都会被遍历到,由于Vue会给根元素添加一个__vue__属性指向当前组件,如下图所示:

0bbd1b76a6def0f8274e35b7ea04d733.png

导致当前组件的所有属性会被访问到,组件里面又有一个proxy,是vue用来处理template里访问到data里面没写的属性报一个警告:

8e09f5f3eac5e0fe84b936d00acdd57b.png

当访问它的toJSON属性时就会触发Vue错误:

38351cb89b629dd64160ad933dfcf03b.png

这个时候又触发了errorHandler,errorHandler里面又访问了toJSON,这样循环触发,就卡死了。

为啥Vue要在DOM节点放一个__vue__属性呢,根据尤大的说法是devtool会使用到:

To some extent yes - the official devtool relies on it too, so it's unlikely to change or break.

当然sentry的设计也有缺陷,应该避免这种循环上报。sentry另外一个循环上报的表现是如果它本身的ajax上报挂了,且在需要上报的域名里面没有滤掉它本身上报的域名,就会导致循环上报。

在新版的sentry(5.12,我当前使用的是5.1)里可以看到已经做了修改,加了一个递归深度为3:

7f138bdb2f467139317274ea7a185404.png

到了那个proxy的时候深度变成0了,就不会继续往下走访问到toJSON了:

  1. // If we reach the maximum depth, serialize whatever has left
  2. if (depth === 0) {
  3. return serializeValue(value);
  4. }
  5. // If value implements `toJSON` method, call it and return early
  6. // tslint:disable:no-unsafe-any
  7. if (value !== null && value !== undefined && typeof value.toJSON === 'function') {
  8. return value.toJSON();
  9. }

进而避免了这种情况。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/132638
推荐阅读
相关标签
  

闽ICP备14008679号