关于javascript:网易前端面试题对一个事件循环内所有调用进行防抖

8次阅读

共计 1371 个字符,预计需要花费 4 分钟才能阅读完成。

写在后面:
自己没有这道题的标准答案,百度上也查不到相干的题解,以下思路都是自己集体想法,如有更好的答案,欢送提出!

网易前端校招的一道面试题,对一个事件循环内所有调用进行防抖。

大家对防抖应该都有所耳闻,但什么是对一个事件循环内的调用进行防抖?自己也从未据说过,看第一遍的时候也没有想法。

然而这道题总结下来,应该是要实现两个需要:

  1. 屡次同步调用 G,只执行第一次
  2. 别离应用 setTimeout 异步调用 G 和同步调用 G,各执行一次

既然是两个需要,那就一个一个来

先来实现第一个需要,这个比较简单,甚至也不必关怀事件循环。跟 once 函数的实现比拟相似,每次调用之前先判断一下是否曾经调用,如已调用就不再调用了。

function debounce(func) {
    let called = false;
    return function() {if(!called) {
            called = true;
            func();}
    }
}

尽管感觉哪里不对,然而第一个需要曾经实现了。各位同学必定也发现了,下面的代码存在一个问题,也就是同步调用 G 之后,没法通过 setTimeout 再次调用了,因为 called 曾经变成了 true

接下来实现第二个需要。为了让 setTimeout 能够再次调用,咱们须要通过一种伎俩,在所有同步代码执行结束之后,将 called 再次改为 false

既然要在同步代码执行结束之后批改 called,咱们能不能用 setTimeout 呢?依照这个思路,代码如下:

function debounce(func) {
    let called = false;
    return function() {if(!called) {
            called = true;
            func();
            setTimeout(() => {called = false;}, 0)
        }
    }
}

测试了一下发现,第一个需要没有问题,然而第二个需要还是只打印了一次。这是因为调用程序的问题,在第二个需要下,setTimeout(G, 0) 先进入工作队列,而后执行到下一行 G() 的时候,防抖函数中的 setTimeout 才进入工作队列。大家都晓得队列是先进先出,那么 setTimeout(G, 0) 会先于防抖函数中的 setTimeout 执行,当 setTimeout(G, 0) 执行的时候,called 还是 true,所以还是只打印一次。

要解决这个问题,就要找到一种机制,它的执行机会在同步代码之后,在 setTimeout 等异步工作执行之前。咱们晓得,JS 中的异步工作其实分为两种,宏工作 微工作

JS 在执行宏工作之前都会查看微工作队列,如果队列不为空,就先执行微工作,直到清空微工作队列,再执行宏工作

咱们晓得,setTimeoutsetInterval、回调函数、文件 I /O 等都属于宏工作,因而,为了实现题目中的需要,咱们能够应用微工作批改 called。常见的微工作包含 PromiseMutationOserverprocess.nextTick,咱们应用最常见的 Promise 来实现。

function debounce(func) {
    let called = false;
    return function() {if(!called) {
            called = true;
            func();
            Promise.resolve().then(() => {called = false;})
        }
    }
}

通过测试,完满实现题目中的两个需要。

正文完
 0