让我们开始吧!注意,我们将在下面的示例中使用原生的 JavaScript,因为面试官通常希望了解你在没有 jQuery 等库的帮助下对JavaScript 和 DOM 的理解程度。...经过 3 秒后,执行该函数并打印出 i 的值,该值在循环结束时为 4,因为它循环经过0,1,2,3,4并且循环最终停止在 4。...,它是 “裁判” 决定是否停止比赛的依据,最后,等待比赛结果就对应到回调函数的执行。...直到“一段时间”到了,第一次触发的 scroll 事件对应的回调才会执行,而“一段时间内”触发的后续的 scroll 回调都会被节流阀无视掉。...对比 throttle 来理解 debounce: 在 throttle 的逻辑里, ‘裁判’ 说了算,当比赛时间到时,就执行回调函数。
/** * 函数节流 * 作用:一段时间内的多次操作,只按照第一次触发开始计算,并在计时结束时给予响应。...的回调函数,设置间隔时间为1s const better_scorll = throttle(() => { console.log("触发了滚动事件"); }, 1000); document.addEventListenner...并将id赋值给timer * 然后如果再次点击重复上面的操作,一直到delay时间内没点时,定时器执行 * 执行时:使用call调用传入的回调函数,并传入参数 * */ 使用:在 onScorll...* 函数内,拿到当前的时间戳 * 判断,是否小于间隔时间: * 小于:则清楚定时器,然后重新生成定时器。...定时器内直接赋值,然后call函数, * 大于:直接赋值,然后call函数, */ 使用:在 onScorll 中使用加强版 throttle // 用throttle来包装scroll的回调 const
生活化理解:英雄的技能条,技能条读完才能使用技能(R大招60s) 防抖的实现方式分两种 “立即执行” 和 “非立即执行”,区别在于第一次触发时,是否立即执行回调函数。...“立即执行防抖” 指事件触发后,回调函数会立即执行,之后要想触发执行回调函数,需等待 n 秒延迟 // e.g....,函数在时间段结束时执行。...:“时间戳”方式让函数在时间段开始时执行(第一次触发立即执行),“定时器”方式让函数在最后一次事件触发后(如4.2s)也能触发。...“防抖” 与 “节流” 的异同 相同:都是防止某一时间段内,函数被频繁调用执行,通过时间频率控制,减少回调函数执行次数,来实现相关性能优化。
调节器是浏览器中通过限制代码要处理的事件数量来提高性能的常用技术。当你想以受控的速率执行回调时,应该使用调节器,它允许你在每个固定的时间间隔内重复处理过渡状态。...相反,我们对其进行限制,仅每 100 毫秒检查一次滚动,这样每秒仅获得10个回调。用户仍然可以立即感觉到响应,但是计算效率更高。 调节器用于创建均匀间隔的函数调用。...想象一下,如果你在事件处理程序回调函数中执行大量计算或 API 请求。通过限制这些回调,可以防止应用冻结或对服务器发出不必要地请求。 JavaScript 中的调节器的实现 让我们立即进入调节器代码。...然后检查运行是否超时(即激活调节器)。如果调节器生效,那么 throttledEventHandler 已经完成了该执行并等待执行回调。如果调节器为非活动状态,则可以用回调函数立即处理该事件。...这时则会跳过回调的执行,这可以使我们免于执行 CPU 密集型任务或调用我们的 API。
它们将被传入推迟执行的函数(回调函数)。...最后那两个参数,将在1000毫秒之后回调函数执行时,作为回调函数的参数。...setTimeout注意点 setTimeout()中回调函数中的this 如果被setTimeout推迟执行的回调函数是某个对象的方法,那么该方法中的this关键字将指向全局环境,而不是定义时所在的那个对象...比如,网页开发中,某个事件先发生在子元素,然后冒泡到父元素,即子元素的事件回调函数,会早于父元素的事件回调函数触发。...在函数A中,setTimeout将函数B推迟到下一轮Loop执行,这样就起到了,先触发父元素的回调函数C的目的了。 用户自定义的回调函数,通常在浏览器的默认动作之前触发。
如果队列中有微任务,就一直执行微任务直到队列清空。 执行一个宏任务(如由 setTimeout() 或 setInterval() 设置的回调)。 宏任务执行完毕后,再次执行所有微任务。...JavaScript 是单线程的,如果事件队列中有其他任务在执行,定时器的回调可能会延迟执行。...setImmediate 是一个在 Node.js 环境中使用的函数,用于安排一个回调函数在当前事件循环结束后、下一次事件循环开始前被立即执行。...process.nextTick 是 Node.js 环境中的一个函数,它用于在 Node.js 的事件循环的当前阶段完成后、下一个事件循环阶段开始之前,安排一个回调函数尽快执行。...nextTick 允许你在 DOM 更新完成后立即运行回调函数,这对于 DOM 依赖的操作非常有用。
现实生活中计时器的另一个很好的例子是应用程序内的广告。当您打开任何应用程序时,它会在 2 到 3 分钟后开始显示广告,并在 1 到 2 分钟的间隔内更改广告。...let timeoutId = setTimeout(callback, delay); 在上面的语法中,回调函数也可以是要执行的箭头函数。 参数 回调 – 这是一个在延迟时间后执行的函数。..."; } 使用 setInterval() 函数在每个间隔后执行函数 setTimeOut() 函数只执行一次回调函数...setInterval(callback, interval) 参数 回调 – 它是一个在每个间隔后调用 setInterval() 函数的函数。...间隔 – 是在每个间隔后调用回调函数的时间(以毫秒为单位)。 返回值 setInterval() 函数还返回唯一 id,如 setTimeout() 函数,我们可以用来停止计时器。
异步编程方案有哪些 JavaScript 异步编程方案各有什么优缺点 回答关键点 阻塞 事件循环 回调函数 JavaScript 是一种同步的、阻塞的、单线程的语言,一次只能执行一个任务。...异步回调 异步回调函数作为参数传递给在后台执行的其他函数。当后台运行的代码结束,就调用回调函数,通知工作已经完成。...因为回调的控制权在第三方(如 Ajax),由第三方来调用回调函数,无法确定调用是否符合预期。 多层嵌套回调会产生回调地狱(callback hell)。 2....主要特征如下: setTimeout:经过任意时间后运行函数,递归 setTimeout 在 JavaScript 线程不阻塞情的况下可保证执行间隔相同。...setInterval:允许重复执行一个函数,并设置时间间隔,不能保证执行间隔相同。 requestAnimationFrame:以当前浏览器/系统的最佳帧速率重复且高效地运行函数的方法。
) 0秒延迟,此回调将会放到一个能立即执行的时段进行触发。...浏览器内核线程分析 初学JavaScript时出现过一个误区:JavaScript引擎是多线程的,定时器回调函数是异步执行的。...arguments.callee, 10); }, 10); setInterval(function(){ /* 代码块... */ }, 10); 两段代码看似效果相同,其实不然,第一段中回调函数内的...,理论时间间隔<=10ms 案例2 ajax异步请求是否真异步 XMLHttpRequest请求在连接后是异步的,请求是由浏览器新开一个线程,当请求状态变更时,若设置回调函数,异步线程产生状态变更事件放到...所以当第一次方法执行过后4ms,第二次方法也被执行了。从setInterval()第二次被触发开始,后面几次的执行都没有被阻塞,所以间隔时间都在11ms左右。
setTimeout可以保证函数在指定的时间间隔内不会执行,而setInterval无法保证(有可能出现接近连续执行的情况,后面会分析原因)。...但setInterval有一个原则:在向队列中添加回调函数时,如果队列中存在之前由其添加的回调函数,就放弃本次添加(不会影响之后的计时)。...那么函数的执行过程就会变成下图所示: 从图中可以看到,从上次函数执行完毕,到下次开始执行,之间只间隔了10毫秒,而不是我们所希望的每隔100毫秒执行一次(因为setInterval只关注任务添加...保证在指定的时间内不会执行的特点,我们可以在执行完上次的回调函数后,重置定时器,实现循环执行func的效果,并且从上次执行完毕到下次执行开始,至少会经过100毫秒。...总结 setTimeout与setInterval都是通过一个定时器控制回调函数的执行,但由于javascript单线程的特点,两者都不能准确控制函数的执行时间点,这点还请开发者注意。
事件循环应用:WebAPI 2.1 setTimeout 2.1.1 实现方式 消息队列中的任务是按顺序执行的,为了保证 setTimeout 回调函数能在指定时间内执行,不能将定时器的回调函数直接添加到消息队列中...嵌套调用最短时间间隔 4 毫秒 在定时器函数里面嵌套调用定时器,也会延长定时器的执行时间,系统会设置最短时间间隔为 4 毫秒。...执行环境,添加微任务并在 JavaScript 执行结束时取出执行,可以得到结论: 每个宏任务关联一个微任务队列 微任务的执行时长会影响当前宏任务的时长 在一个宏任务中分别创建一个用于回调的宏任务和微任务...4.2.1 Promise 解决嵌套回调 Promise 主要通过以下两步解决嵌套回调问题: Promise 实现了回调函数的延时绑定 产生嵌套回调的主要原因是在发起任务请求时会带上回调函数,所以当前任务结束后下个任务只能在回调函数中处理...rAF 函数的回调任务会在 每一帧的开始执行,与浏览器刷新频率同步;而 setTimeout 即使设置16.7ms延迟,也可能会因为当前任务的执行时间过长而延迟。
在浏览器中,因为所有的 JavaScript 代码都运行在单一线程之中,异步事件(如鼠标点击,定时器)只有在他们被触发的时候他们的回调才有机会得以执行。 我们可以用下图说明: ?... interval 回调函数无间隔的执行,直到该执行队列清空。...,尽管这意味着两个 interval 回调函数执行的时间间隔被牺牲。...这里第一个 interval 回调执行结束后,紧跟着第三个 interval 的回调马上得到执行,中间没有印象中应该有的 10ms 间隔。...需要注意到, setTimeout 的回调函数的执行总是保证了至少 10ms 的间隔(与上一个回调的执行相比,实际执行时,这个间隔可能变长,但是不可能更少),但是 setInterval 会尝试每隔 10ms
当指定的事情完成时,Event Table会将这个函数移入Event Queue。 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。...执行console.log('代码执行结束')。 ajax事件完成,回调函数success进入Event Queue。 主线程从Event Queue读取回调函数success并执行。...一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了。这句话请读者仔细品味。...ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。 结束。...(3)javascript的执行和运行 执行和运行有很大的区别,javascript在不同的环境下,比如node,浏览器,Ringo等等,执行方式是不同的。
执行console.log('代码执行结束')。 ajax事件完成,回调函数success进入Event Queue。 主线程从Event Queue读取回调函数success并执行。...一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了。这句话请读者仔细品味。...先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。...ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。 结束。...(3)javascript的执行和运行 执行和运行有很大的区别,javascript在不同的环境下,比如node,浏览器,Ringo等等,执行方式是不同的。
100ms 后将任务加入到"任务队列"中,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。...要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。...这个回调函数会在浏览器重绘之前调用。...函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。...的回调函数, ?
Throttle:第一个人说了算 throttle 的中心思想在于:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应。...它是“司机”决定发车的依据;最后“发车”这个动作,就对应到回调函数的执行。...直到“一段时间”到了,第一次触发的 scroll 事件对应的回调才会执行,而“一段时间内”触发的后续的 scroll 回调都会被节流阀无视掉。...我们对比 throttle 来理解 debounce:在throttle的逻辑里,“第一个人说了算”,它只为第一个乘客计时,时间到了就执行回调。...这个 throttle 与 debounce “合体”思路,已经被很多成熟的前端库应用到了它们的加强版 throttle 函数的实现中: // fn是我们需要包装的事件回调, delay是时间间隔的阈值
中低于4ms的时间间隔算为4ms iiiii: 异步http请求线程:浏览器有一个单独的线程用于处理AJAX请求,即用于异步http请求,当请求完成时,若有回调函数,通知事件触发线程。...详细描述下:在XMLHttpRequest连接后是通过浏览器新开一个线程请求,在检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中再由JavaScript引擎执行...一旦执行栈中的所有同步任务执行完毕(也就是JS引擎线程空闲了),系统就会读取任务队列,将可运行的异步任务(任务队列中的事件回调,只要任务队列中有事件回调,就说明可以执行)添加到执行栈中,开始执行。...setTimeout/setInterval和XHR/fetch代码,这些代码执行时,本身是同步任务,而其中的回调函数才是异步任务。...当代码执行到setTimeout/setInterval时,实际上是JS引擎线程通知定时触发线程,间隔一个时间后,会触发一个回调事件,而定时触发器线程在接收到这个消息后,会在等待的时间后,将回调事件放入到由事件触发线程所管理的事件队列中
作为开发者,您可以把挂起函数看作是普通函数,只不过它可能会在某些时刻挂起和恢复而已。 不同于回调,协程提供了一种简单的方式来实现线程间的切换以及对异常的处理。...Continuation 其实只是一个具有泛型参数和一些额外信息的回调接口,稍后我们会看到,它会实例化挂起函数所生成的状态机。...它会用于恢复那些执行了参数代码块后挂起的协程; 您可以在一个挂起函数上使用 startCoroutine 扩展函数,它会接收一个 Continuation 对象作为参数,并会在新的协程结束时调用它,无论其运行结果是成功还是异常...下面我们来看看编译器生成了什么: when 语句的参数是 LoginUserStateMachine 实例内的 label; 每一次处理新的状态时,为了防止函数被挂起时运行失败,都会进行一次检查; 在调用下一个挂起函数...而即将被调用的挂起函数也同样被编译器转换成一个相似的状态机,并且接收一个 continuation 对象作为参数。当被调用的挂起函数的状态机运行结束时,它将恢复当前状态机的执行。
两者的区别在于,宏任务在下一轮事件循环开始时执行,微任务在本轮事件循环结束时执行。这意味着微任务的优先级高于宏任务。...requestAnimationFrame 的执行时机是在下一次重绘之前,而不是立即执行。 requestAnimationFrame 的优点是由系统来决定回调函数的执行时机。...如果系统忙到一定程度,可能会两次“刷新”之间多次执行回调函数,这时就可以省略掉一些回调函数的执行。这种机制可以有效节省 CPU 开销,提高系统的性能。...回调地狱问题:回调地狱指的是多层嵌套的回调函数,导致代码难以维护和理解。Promise 可以通过链式调用的方式,解决回调地狱问题。...以上是关于 JavaScript 中异步编程、事件循环、任务队列、宏任务、微任务,以及requestAnimationFrame在事件循环的位置,Promise 的发展和如何解决回调地狱的详细介绍。
领取专属 10元无门槛券
手把手带您无忧上云