服务器的日志中经常会看到以下异常日志:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
Ignoring BEFORE_APP_SERIALIZED Exception: TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'children' -> object with constructor 'Array'
| index 0 -> object with constructor 'Object'
--- property 'parent' closes the circle
at JSON.stringify (<anonymous>)
at TransferState.toJson (/.../ifuyun.com/dist/server/main.js:1:4655830)
at /.../ifuyun.com/dist/server/main.js:1:5349426
at /...ifuyun.com/dist/server/main.js:1:5350617
at _ZoneDelegate2.invoke (/.../ifuyun.com/dist/server/main.js:1:2306479)
at Zone3.run (/.../ifuyun.com/dist/server/main.js:1:2298814)
at /.../ifuyun.com/dist/server/main.js:1:2326026
at _ZoneDelegate2.invokeTask (/.../ifuyun.com/dist/server/main.js:1:2307417)
at Zone3.runTask (/.../ifuyun.com/dist/server/main.js:1:2299899)
at drainMicroTaskQueue (/.../ifuyun.com/dist/server/main.js:1:2311188)
对于这样的日志,真是一头雾水,以至拖了一个多月……
今天,不想在日志中再看到此类信息,也隐隐觉得必然是代码中出现了什么问题,便想着必须要解决它……
然而,异常的发生却是间歇性、偶发的,更头疼的是,本地开发环境下,始终是正常的,而服务器SSR的日志并没有记录时间、User-Agent、URL等关键信息,甚至连异常发生的具体位置也无法定位,如以上信息所示,main.js是构建后的压缩文件,对问题的定位压根没有任何帮助。
无奈,只能在上述压缩混淆后的文件中手动加上console日志语句,等着异常再次发生……
似乎体会到了“守株待兔”的被动、无助的感觉……😒
所幸,一天之后,终于在日志文件中找到了蛛丝马迹。
根据日志的参数,定位到异常是在访问某篇文章时产生,再进行对比、排除法,可知是由评论列表导致的,如此,便可以定位到具体的代码块了。
然而,还是too young too simple了……
根据异常描述,大致是循环引用问题,因此,初步判断是递归所导致。一顿排查下来,然并卵……┓( ´∀` )┏
无奈,继续查找……在一个角落里,发现了下面这句:
- 1
item.children.forEach((child) => child.parent = item);
在不需要序列化的browser
端,自然是没问题的,然而,在server
端,数据是需要序列化之后进行缓存的,因此,便报错了……
知道了源头之后,解决就相对容易了……改成如下即可去除循环引用(注意:扩展运算符...
无效):
- 1
item.children.forEach((child) => child.parent = cloneDeep(item));
测试,完美!┓( ´∀` )┏