JavaScript 中的函数大多数状况下都是由用户主动调用触发的,除非是函数自己的实现不合 理,不然咱们通常不会遇到跟性能相关的问题。但在一些少数状况下,函数的触发不是由用户直 接控制的。在这些场景下,函数有可能被很是频繁地调用,而形成大的性能问题。下面将列举一 些这样的场景
JavaScript 中的函数大多数状况下都是由用户主动调用触发的,除非是函数自己的实现不合 理,不然咱们通常不会遇到跟性能相关的问题。但在一些少数状况下,函数的触发不是由用户直 接控制的。在这些场景下,函数有可能被很是频繁地调用,而形成大的性能问题。下面将列举一 些这样的场景
(1). 函数被频繁调用的场景浏览器
window.onresize 事件。咱们给 window 对象绑定了 resize 事件,当浏览器窗口大小被拖动 而改变的时候,这个事件触发的频率很是之高。若是咱们在 window.onresize 事件函数里 有一些跟 DOM节点相关的操做,而跟 DOM节点相关的操做每每是很是消耗性能的,这 时候浏览器可能就会吃不消而形成卡顿现象app
mousemove 事件。一样,若是咱们给一个 div 节点绑定了拖曳事件(主要是 mousemove),当 div 节点被拖动的时候,也会频繁地触发该拖曳事件函数函数
上传进度。微云的上传功能使用了公司提供的一个浏览器插件。该浏览器插件在真正开 始上传文件以前,会对文件进行扫描并随时通知 JavaScript函数,以便在页面中显示当前 的扫描进度。但该插件通知的频率很是之高,大约一秒钟 10次,很显然咱们在页面中不 须要如此频繁地去提示用户性能
(2). 函数节流原理spa
咱们整理上面提到的三个场景,发现它们面临的共同问题是函数被触发的频率过高。 好比咱们在 window.onresize 事件中要打印当前的浏览器窗口大小,在咱们经过拖曳来改变 窗口大小的时候,打印窗口大小的工做 1秒钟进行了 10次。而咱们实际上只须要 2次或者 3次。 这就须要咱们按时间段来忽略掉一些事件请求,好比确保在 500ms内只打印一次。很显然,咱们 能够借助 setTimeout 来完成这件事情插件
var throttle = function(fn, duration) { var _self = fn, firstTime = true, timer; if (firstTime) { fn(); return firstTime = false; } if(timer){ return false } timer = setTimeout(() => { clearTimeout(timer) timer = null; fn() }, duration||500); }; window.onresize = throttle(function (params) { console.log(1) })
有时候是咱们主动须要大量的频繁调用某个函数,好比在页面中插入1000个div。在短期内往页面中大量添加 DOM节点显然也会让浏览器吃不消,咱们看到的结果每每就 是浏览器的卡顿甚至假死
(1). 解决原理code
咱们能够把函数让建立节点的工做分批进行,好比把 1秒钟建立 1000个节点,改成每隔 200毫秒建立 8个节点。对象
/** * @param {Array} ary - 必填--- 要建立的集合 * @param {Function} fn -必填--- 业务逻辑代码 * @param {Number} count - 可选---每批建立几个 */ var timeChunk = function(ary, fn, count) { var obj, timer; var start = function() { for (var i = 0; i < Math.min(count || 1, ary.length); i++) { obj = ary.shift() fn(obj) } } return function() { timer = setInterval(() => { if (ary.length === 0) { return clearInterval(timer) } start(); }, 500); } } var ary = []; for (var i = 1; i <= 10; i++) { ary.push(i); }; var renderFriendList = timeChunk(ary, function(n) { var div = document.createElement('div'); div.innerHTML = n; document.body.appendChild(div); }, 2); renderFriendList();