另一个流行的前端面试问题。它测试受访者对 JS、性能和 FE 系统设计的知识。
这是前端面试问题系列的第二个问题。如果您希望提高准备水平或保持最新状态,请考虑注册 FrontendCamp。
去抖和节流的工作原理相同 - 延迟东西 - 但仍然有非常不同的方法和用例。
这两个概念对于开发高性能应用程序都很有用。 您每天访问的几乎所有网站都以某种方式使用去抖和节流。
去抖动的一个众所周知的用例是预先输入(或自动完成)。
假设您正在为一个拥有数千种产品的电子商务网站构建搜索功能。当用户尝试搜索某些内容时,您的应用将进行 API 调用来获取与用户的查询字符串匹配的所有产品。
const handleKeyDown = async (e) => { const { value } = e.target; const result = await search(value); // set the result to a state and then render on UI } <Input onKeyDown={handleKeyDown} />
这种方法看起来不错,但有一些问题:
解决这些问题的方法是去抖动。
基本思想是等到用户停止输入。我们将延迟 API 调用。
const debounce = (fn, delay) => { let timerId; return function(...args) { const context = this; if (timerId) { clearTimeout(timerId); }; timerId = setTimeout(() => fn.call(context, ...args), delay); } } const handleKeyDown = async (e) => { const { value } = e.target; const result = await search(value); // set the result to a state and then render on UI } <Input onKeyDown={debounce(handleKeyDown, 500)} />
我们扩展了现有代码以利用去抖动。
去抖动函数是通用实用函数,它接受两个参数:
在函数内部,我们使用 setTimeout 来延迟实际的函数(fn)调用。如果在计时器耗尽之前再次调用 fn,计时器将重置。
通过我们更新的实现,即使用户输入 15 个字符,我们也只会进行 1 次 API 调用(假设每次按键的时间少于 500 毫秒)。这解决了我们开始构建此功能时遇到的所有问题。
在生产代码库中,您不必编写自己的去抖动实用函数。您的公司很可能已经使用了像 lodash 这样具有这些方法的 JS 实用程序库。
嗯,去抖对于性能来说非常有用,但在某些情况下,我们不想在收到更改通知之前等待 x 秒。
想象一下您正在构建一个协作工作空间,例如 Google Docs 或 Figma。关键功能之一是用户应该实时了解其他用户所做的更改。
到目前为止我们只知道两种方法:
这就是节流的用武之地。它位于上述两种方法的中间。基本思想是 - 定期通知 - 不是在最后也不是在每次按键时通知,而是定期通知。
const throttle = (fn, time) => { let lastCalledAt = 0; return function(...args) { const context = this; const now = Date.now(); const remainingTime = time - (now - lastCalledAt); if (remainingTime <= 0) { fn.call(context, ...args); lastCalledAt = now; } } } const handleKeyDown = async (e) => { const { value } = e.target; // save it DB and also notify other peers await save(value); } <Editor onKeyDown={throttle(handleKeyDown, 1000)} />
我们修改了现有代码以利用节流功能。它需要两个参数:
实施非常简单。我们将函数上次调用的时间存储在lastCalledAt中。下次,当进行函数调用时,我们检查时间是否已经过去,然后才执行 fn。
我们已经快到了,但是这个实现有一个错误。如果最后一次使用某些数据的函数调用是在时间间隔内进行的,并且此后没有进行任何调用,该怎么办?根据我们当前的实现,我们将丢失一些数据。
为了解决这个问题,我们将参数存储在另一个变量中,并启动一个超时,以便在没有收到事件时稍后调用。
const throttle = (fn, time) => { let lastCalledAt = 0; let lastArgs = null; let timeoutId = null; return function(...args) { const context = this; const now = Date.now(); const remainingTime = time - (now - lastCalledAt); if (remainingTime <= 0) { // call immediately fn.call(context, ...args); lastCalledAt = now; if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } } else { // call later if no event is received lastArgs = args; if (!timeoutId) { timeoutId = setTimeout(() => { fn.call(context, ...lastArgs); lastCalledAt = Date.now(); lastArgs = null; timeoutId = null; }, remainingTime); } } } }
此更新的实现可确保我们不会错过任何数据。
Lodash 还提供了节流实用功能。
前端营
洛达什
以上是去抖和节流的详细内容。更多信息请关注PHP中文网其他相关文章!