EventLoop事件循环

一、先了解javascript为什么是单线程

    |--javascript语言的特点:单线程。
    |--线程和进程
        |--进程:运行的程序就是一个进程,比如正在运行的浏览器就是一个进程。
        |--线程:程序中独立运行的代码段,一个进程由单个或多个线程组成,线程是负责执行代码的。
    |--JS为什么单线程?多线程效率多高啊?
        |--1.首先决定单线程的主要原因是js的用途:用户交互和操作DOM
        |--2.举个例子:两个线程,一个线程在DOM节点添加内容,另一个线程删除了这个节点。
        |--3.上述例子浏览器应该以哪个线程为准?
        |--综上:产生了问题。
    |--为了避免复杂性,单线程成为了javascript的核心特征。
    |--但是为了利用多核CPU的计算能力,HTML5提出了Web Worker标准,允许js创建多个线程,但是子线程    
        完全受主线程控制,且不得操作DOM,新标准并没有改变javascript单线程本质。

二、同步执行和异步执行

    |--同步执行:因为JS语言特点是单线程,即任务是串行的,后一个任务要等前一个任务执行完,才能执行,这样在主线程按照顺序,串行执行的任务称为同步执行任务。
    |--异步执行:由于类似于Ajax网络请求、setTimeout时间延迟、DOM事件的用户监护等,这些任务并不消耗CPU,是一种空等,资源浪费,因此出现了异步。通过将任务交给异步处理模块去处理,主线程的效率能大大的得到提升,可以并行的处理其他操作。当异步处理完成,主线程空闲时间,主线程读取相应的callback,进行后续操作,最大程度的利用CPU。因此异步执行就是CPU跳过等待,先处理后续任务(CPU和网络模块、timer模块等并行进行任务)。
    |--而为了协调主线程和异步模块之间性的工作,就产生了任务队列和事件循环

三、Event Loop事件循环机制

事件循环机制

    |--逐步分析事件循环机制:
        |--1.主线程运行js代码,产生了堆和执行栈。
            |--堆:对象被分配在堆中,即用来表示大部分非机构化的内存区域。
            |--执行栈:execution context stack,运行同步代码。执行栈中的代码(同步任务),总是在读取
            task queue(异步任务)之前。
        |--2.主线程遇到异步任务,指给对应的异步处理模块(异步进程)进行处理(web API)
        |--3.异步进程处理完毕(Ajax返回、DOM事件处理、Timer到时等),将相应的异步任务推入任务队列。
            |--任务队列:任务队列是一个事件队列,IO设备完成一项任务,就在task queue里添加一个事件,表示
            相关的异步任务可以进入“执行栈”了。主线程读取任务队列,就是读取里面的那些事件(数据结构是
            先进先出)。主线程的读取过程是自动的,只要执行栈一清空,任务队列中的第一个事件就会自动
            进入主线程。
            |--回调函数:任务队列也被称为callback queue(回调队列),即异步任务必须指定回调函数,当主线程
            开始执行异步任务时,就是执行对应的回到函数。
            |--异步进程包括:
                |--类似于onclick,由浏览器内核的DOM binding模块处理,事件触发时,回调函数添加到任务队列。
                |--setTimeout,由浏览器内核的Timer模块处理,事件到达,回调函数添加到任务队列。
                |--Ajax,由浏览器内核的Network模块处理,网络请求返回后,添加到任务队列。
        |--4.主线程循环的去查找、执行任务队列中的事件,就形成是事件循环(event loop)。

四、宏任务和微任务

    |--将任务进行更精细的定义,分为宏任务和微任务。
        |--宏任务队列(macrotask queue) 
            |--不唯一,存在一定的优先级(用户I/O部分优先级更高),异步执行,同一个事件循环中只执行一个,
            包括:整体代码script,setTimeout、setInterval、ajax、dom操作。
        |--微任务队列(microtask queue)
            |--整个事件循环当中仅存在一个,执行为同步,同一个事件循环中的microtask会按照队列顺序,
            串行执行。微任务指的是ES6中的Promise。
    |--宏任务和微任务区别:
        |--微任务中所有的callback处在同一个事件循环中,宏任务中的callback有自己的事件循环。
        |--利用微任务可以形成一个同步执行环境,但是如果微任务太长,将导致宏任务等待太久,长时间
        执行不了,最终导致用户的I/O无响应,所以慎用使用。
    |--加入宏任务和微任务概念的js运行机制:
        |--1.“执行栈”最先执行所有的同步代码(宏任务)。执行完毕。
        |--2.检查是否有微任务(microtask),如果有执行所有微任务。
        |--3.取出“任务队列”中的事件对应的回调函数(宏任务)进入执行栈。执行完毕。
        |--4.再检查是否有微任务,有的话执行多有微任务。
        |--5.主线程不断重复执行3,4形成事件循环。
    |--示例:

宏任务、微任务示例

    |--运行机制分析:
        |--同步环境:1 -> 2 -> 3
        |--事件循环(微任务):5
        |--事件循环(宏任务):4

五、宏任务之setTimeout和setInterval

    |--两个都是定时器,内部运行机制完全相同,区别在意setTimeout一次性执行,而setInterval反复执行。
    |--setTimeout和setInterval产生的任务都是异步任务,且是宏任务。
    |--两个定时器都是接受两个参数
        |--fn:callback 函数
        |--time:推迟执行的毫秒数、反复执行的毫秒数。
    |--注意:如果第二个参数为0,并不是立即执行,而是指定某个任务在主线程最早可得的空闲时间执行,
    也就是“尽早执行”。它在任务队列的“尾部”添加一个事件,因此要等同步任务和“任务队列”现有的事件处理完
    才能得到执行。
    |--setTimeout(function(){},3000)是异步任务,先被放入event table,3秒后才被推入到task queue,
    而task queue任务队列里的任务,只有主线程空闲时,才会执行。这样一来如果同步任务超出了
    推迟执行的事件3000s,那么这个3000秒就没有什么意义了,setTimeout(function(){},3000)就等同于
    setTimeout(function(){},0)。

六、微任务之Promise

    |--当new Promise(function(){... ...}).then(microTask),Promise里的function会立即执行,但是then方法里的
    函数是在执行栈后,任务队列之前执行的,即微任务。

七、nodeJs中的process.nextTick

    |--node.js中提供的和“任务队列”有关的方法,他产生的任务是放在执行栈的尾部,并不属于宏任务或
    微任务。因此它的任务总是发生在异步任务的前面。

八、nodeJs中的setImmediate

    |--他产生的任务在“任务队列”的尾部。

九、总结

    |--任务执行的优先级:
        |--1.同步代码(宏任务)
        |--2.process.nextTick(node.js中的方法)
        |--3.Promise(微任务)
        |--4.setTimeout(fn)、setInterval(fn)等(宏任务)
        |--5.setImmediate(nodejs)
        |--6.setTimeout(fn,time>0)、setInterval (fn,time>0)
    |--示例1:同步任务>异步任务 [优先级]

同步>异步

    |--示例2:证明任务队列中,先进先出。

先进先出

    |--示例3:在fn()之前增加一个微任务,Promise里的内容同步执行,先输出8,9后才是6。

Promise里的内容同步执行

    |--示例4:Promise形成了同步执行环境。但是then里的内容会在同步后,任务队列前执行。

then同步后,task queue前

十、扩展

    |--案例:for循环+setTimeout问题    

    |--如何让其输出0~4?
    |--解决办法1:var该为let

let解决

    |--解决办法2:通过闭包

闭包解决

    |--解决办法3:添加立即执行的函数

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

推荐阅读更多精彩内容