hybrid-native开发或者reat-native开发时,不可避免涉及到js脚本编写。对于大前端来说,对于es6/es7的语法熟悉是必备素质。这里介绍一个前端常用的工具库lodash。
遇到的问题
今天在优化大搜索页面时碰到一个问题,feedback返回用户反馈搜索页面卡顿。先定位到原先的代码:是在 < TextInput > 的onchange回调中,请求suggest接口返回模糊搜索结果。但是在IOS设备上会有一个问题:键盘输入拼音时系统会把未输入完的结果录到input组建中,导致onchange回调多次调用,suggest接口频繁请求,hint内容不断刷新,造成页面卡顿的同时,也增加了接口的负担。
优化点
经过分析,我认为用户使用模糊搜索具备 幂等性 .即在一段时间内用户输入的key word应返回相同的suggest。不应频繁调用接口。
基于以上思想,很自然想到setTimeout()函数,用户输入停止后设置一个延时再请求网络,但是直接在回调里setTimeout这个做法十分hardcode。于是逛了一下万能的gayHub,发现了一个不错的解决方案:使用debounce函数去除抖动。
lodash介入
这里的debounce函数属于鼎鼎大名的lodash库(https://github.com/lodash/lodash)
debounce函数的官方文档
debounce 与 throttle
debounce(防抖):当调用函数n秒后,才会执行该动作,若在这n秒内又调用该函数则将取消前一次并重新计算执行时间,举个简单的例子,我们要根据用户输入做suggest,每当用户按下键盘的时候都可以取消前一次,并且只关心最后一次输入的时间就行了。
throttle(节流):将一个函数的调用频率限制在一定阈值内,例如 1s 内一个函数不能被调用两次。
这里拿出debounce的源码解析一下:
1 | function debounce(func, wait, options) { |
首次进入函数时因为 lastCallTime === undefined 并且 timerId === undefined,所以会执行 leadingEdge,如果此时 leading 为 true 的话,就会执行 func。同时,这里会设置一个定时器,在等待 wait(s) 后会执行 timerExpired,timerExpired 的主要作用就是触发 trailing。
如果在还未到 wait 的时候就再次调用了函数的话,会更新 lastCallTime,并且因为此时 isInvoking 不满足条件,所以这次什么也不会执行。
时间到达 wait 时,就会执行我们一开始设定的定时器timerExpired,此时因为time-lastCallTime < wait,所以不会执行 trailingEdge。
这时又会新增一个定时器,下一次执行的时间是 remainingWait,这里会根据是否有 maxwait 来作区分:
如果没有 maxwait,定时器的时间是 wait - timeSinceLastCall,保证下一次 trailing 的执行。
如果有 maxing,会比较出下一次 maxing 和下一次 trailing 的最小值,作为下一次函数要执行的时间。
最后,如果不再有函数调用,就会在定时器结束时执行 trailingEdge。
lodash其他常用函数:
遍历对象类型:
_.forEach(obj, (value, key) => { console.log(value) })
遍历和过滤的快捷方式:
从一组对象中摘取出某个属性的值:
1 | let arr = [{ n: 1 }, { n: 2 }] |
当对象类型的嵌套层级很多时,Lodash 的快捷方式就更实用了:
1 | let arr = [ |
可以看到,Lodash 的快捷方式还对 null 值做了容错处理。此外还有过滤快捷方式,以下是从 Lodash 官方文档中摘取的示例代码:
1 | let users = [ |
链式调用和惰性求值:
1 | et lines = ` |
解构赋值和箭头函数:
ES6 引入了解构赋值、箭头函数等新的语言特性,可以用来替换 Lodash:
1 | // Lodash |
一些参考信息:
10 Lodash Features You Can Replace with ES6
Does ES6 Mean The End Of Underscore / Lodash?