date | tags |
---|---|
2016-10-09 |
javascript |
从测试用例出发
如果项目中约定了编写测试用例,那么需要考虑它的测试用例是否完善,等测试用例完善了在review也不迟。
内存泄露
测试用例都能过了那么就没问题了吗?内存泄露在线下开发是很难复现的,因为测试用例没有负载量,在压测阶段或者灰度阶段发现还好,在线上阶段发现则以上所有相关人员case study。在压力测试的时候需要注意机器的内存情况。
在使用js对象去存一些长周期的东西时,需要严格的估算这个对象将承载的压力,在设计缓存的时候,也一定注意缓存的淘汰机制(比如lru,lfu)。下面也有其他原因造成内存泄露的例子。
变量逸出
在js中的,很有可能不小心将变量写到了全局环境,这时候此变量成了一个定时炸弹,当所有的代码都忽略了这个问题,那么逃逸的变量很有可能会引起非自主的变量共享问题。
一旦不小心逃逸成全局变量,此变量则不会随着作用域的结束而回收,此时如果写入key的量过多,就会导致内存泄露。
代码兜底
在获取任何资源的时候都需要预防获取失败的情况。例如在取变量对象时使用默认值。如let a = obj.b || {}
,或者使用es6的默认值语法。
再举个例子,在通过网络io获取配置的之后,需要硬编码一个默认配置,这也是代码兜底的一种策略。
来自npm社区的关怀
npm不仅有臭名昭著的left-padding事件,其托管的包也是鱼龙混杂。我们在后端使用了一个node的包,是一个服务的客户端,在每次重连的时候,它会把错误信息存在闭包的一个对象里,对象很合理的不被释放,在反复重连之后也很合理的内存泄露了。
如果实习生加入了一个库,如果他的经验不是很多,那么你可能需要帮助他做一次npm包的review。对于popularity的考察便是第一次的review,如果代码不多,花点时间看看源码也无妨。比如我发现有两个关于crontab的库,一个是用js的setTimeout实现的,一个则是系统调用,从多个角度分析也难说哪个更好。比如另一个库,它拓展了Array.prototype
从而影响了另一个库。
不必究其细节,可以着重了解它对操作系统的影响,别忘了node可以执行shell的,说不定你安装了一个危险的库,也有留后门的可能(偷偷的采集你的东西),这也是进程权限收敛的原因。
你的资源可能不支持并发
首先是,多进程的竞争,node实际上可以多进程,其次即使在单线程异步io模型中,node也可以在级短的时间派发一众io,实现了对于基础设施的并发操作。这就涉及到了对资源的并发操作,更多是从基础设施的角度解决这个问题,比如给mysql加锁。
时间复杂度和内存使用
典型的是indexOf,concat这两个方法,前者时间复杂度,后者内存使用。indexOf并不快,做值的check时首选用{}
或者es6中的map或者set。concat则是用两个数组生成了一个新的数组,我看见很多人在写类似数组拍平操作时使用concat收集item,此时不如用[].push.apply(arr, items)
。
考察代码的副作用
js中代码的副作用让人苦不堪言,这个对象它怎么就变了?是哪改的?对象的引用飘的到处都是,无尽的bug在等待。我在面试时有时候会问splice和slice的区别,除了参数,以及splice可以实现插入操作,我更希望的是候选人可以意识到代码的副作用(splice有副作用,slice没有)。
但是适当副作用是可以优化内存空间,所以有了immutable-js,可以用在纯函数中,也优化了内存。
分析潜在的死锁问题
多线程语言中(不是js该考虑的),线程死锁问题往往很难复现,只能通过阅读代码搞定(是这样吗?),例如类似哲学家就餐问题,最长的复现时间可能需要不停的运行代码一周。
英文拼写
专业性问题,比如data就是复数,单数是datum,不允许出现datas这种拼写,用select而不要用choose,choose更口语化,对应choice,select对应的是option。类似以上,没有很好的解决方法,只能多翻翻词典。
语法习惯
要是es6大家都别用var了,要是个传统项目还不带babel那也别用es6了, low点就low点。可以加eslint做语法习惯检查。