JavaScript事件如何处理?计时器使用0.0清明时分,忙碌后

事件处理过程

  • 浏览器检查事件队列头
  • 如果在队列头并没有事件则继续检查后面
  • 如果队列头有事件则去除并执行

为何要有事件队列?

因为浏览器处理事件是单线程的,这里历史原因在于单线程可以保证页面在同一时刻只被同一事件修改
又由于请求和数据的输入输出较慢,所以cpu空闲,所以提供这种事件循环机制使其进入任务队列,让排在后面的任务先执行,等数据到来后,进程空闲时按队列顺序处理之前的请求任务。

同步任务和异步任务与事件队列的关系

同步任务:主线程执行,任务按顺序一个一个执行
异步任务:不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)

(1)所有同步任务都在主线程上执行,形成一个执行栈。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。(回调函数、事件触发、计时器触发等)

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

主线程任务结束后执行任务队列里任务,迭代执行。
摘自阮一峰老师博客

定时器又是什么?与其有什么关系?

  • setTimeout():setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。对应的setTimeout取消定时器
  • setInterval():setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。对应的setInterval函数取消定时器
  • 这两个定时器均会返回一个值,将这个值传入对应取消函数中即可
var h = setTimeout(Fn,1000);
var h2 = setInterval(Fn,1000);

clearTimeout(h);
clearInterval(h2);

一些疑点

  1. 如何使用计时器将导致应用程序缓慢甚至不响应的长时间任务,分解为不会阻塞浏览器的小任务。
    使用setTimeout(Fn,0)将大任务切小为多个小任务执行, HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次 截取自阮一峰博客,长时间的任务会阻塞渲染,由此引发页面的假死,若将大任务切分后,可替换为多次页面更新。
function chunk (array,process,context){
  setTimeout(function() {
    var item = array.shift()
    process.call(context,item)
    
    if(array.length > 0){
      setTimeout(arguments.callee,100)
    }
  },100)
}
//摘自JavaScript高级程序设计
  1. 定时器也会在任务队列中,那么何时执行呢?是在设置的时间到了就执行吗?
    它所设置的时间指的就是在设定的时间到了后加入任务队列等待执行,如果此时队列中没有任务则会被执行,如果有则需要等待。这也是间隔计时器不会在预期执行的原因。因为你只能控制何时加入而不是何时执行。

  2. 那为何定时器的执行时间无法保证?
    无法保证是因为进入队列后,在执行它前的任务所需的事件是无法预期的。

  3. 如果setInterval 定时器每 3ms 执行一次,而事件处理程序需要运行16 ms,那么定时器的回调函数将被添加到微任务队列中多少次?
    一次,并不会重复添加,也就是不会创建两个相同的间隔计时器

这里有个问题,如果在事件运行到第15ms时增加的定时器会在18ms时执行,那么并没有起到事件结束后延时3ms运行的 效果,那么此时可以参考下面这个问题设计出信的解决方案。即对于setTimeout()的重复调用。
setTimeout(function() {
  setTimeout(arguments.callee , interval)
} , interval)

// arguments.callee 获取当前执行的函数的引用
拓展:arguments对象可以获取和设置函数的参数,通过arguments[0]这种形式获取、设置参数值,而 arguments.callee 则是指向当前执行的函数。arguments.length 指向传递给当前函数的参数数量。
  1. setTimeout() 和 setInterval()差异?
    重复调用setTimeout() 时 它的执行思路是这样的:假设setTimeout(Fn,Delay)这里的回调函数Fn执行时间是12ms,则Delay为10ms后任务加入队列,在无阻塞情况下执行,执行时间12ms,执行结束后,再等待10ms后任务再次加入队列,然后执行时间依然为12ms,重复以上。而setInterval(Fn,Delay) 则fn12ms执行时间,Delay为10ms,它会在第一个10ms后加入任务队列无阻塞情况下执行,当总时间为20ms时任务再次加入队列,而不是等待函数执行完毕后加入。

  2. setTimeout()如何设置防止资源未加载成功时多次发送请求?
    原理是第一次调用函数创建一个定时器,在指定时间间隔后执行代码,第二次调用时会清除上一次创建的定时器,并设置一个新的(即在设置这个新的计时器后再 在指定间隔后执行)。

  var timer
  function fn(){
      if(timer){
          clearTimeout(timer)
      }
        timer = setTimeout(function(){
             console.log('OK!')
        }, 1000)
  }

  fn()
  fn()
  fn()

在第一次执行fn后,1000ms内执行了第二次fn,此时由于代码需要在1000ms后加入队列执行,所以没有输出的情况下被清除了(clearTimeout(timer)),也就是不会重复执行此函数,如果这里面是ajax请求也同样不会多次发送请求。


Event Loop

image

在这里stack里的代码总是会先执行,在结束后执行任务队列。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容