事件循环Event Loop

1.关于javascript

javascript是一门单线程语言,在最新的HTML5中提出了Web-Worker,但javascript是单线程这一核心仍未改变。所以一切javascript版的"多线程"都是用单线程模拟出来的,一切javascript多线程都是纸老虎!(不管是什么新框架新语法糖实现的所谓异步,其实都是用同步的方法去模拟的)

2.javascript事件循环

事件循环是js实现异步的一种方法,也是js的执行机制。

首先浏览器会把主任务队列中的同步任务挨个全部执行完,然后再去等待任务队列中看哪个任务可以执行了,

然后把该执行的任务放到主任务队列中去执行,等这个任务执行完,

再去等待任务中看谁可以执行了,再把这个任务放到主任务队列中执行... 如此循环。

这种循环叫做事件循环(Event Loop)

js是单线程,js任务也要一个一个顺序执行。如果一个任务耗时过长,那么后一个任务也必须等着。那么问题来了,假如我们想浏览新闻,但是新闻包含的超清图片加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?因此聪明的程序员将任务分为两类:1)同步任务 2)异步任务

一张图表示事件循环

#1.同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。#2.当指定的事情完成时,Event Table会将这个函数移入Event Queue。#3.主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。#4.上述过程会不断重复,也就是常说的Event Loop(事件循环)。主线程执行栈何时为空?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。~~~~

所以可以看做是这样的:

1.浏览器线程先执行同步任务,途中遇到异步任务就将其加入到等待任务队列中去,然后继续向下执行,

2.等同步任务全部执行完毕后,再去等待任务队列中去将所有可执行的微任务逐个执行,

3.执行完微任务后在拿取第一个先到达执行条件的宏任务来执行,

4.执行完后再去等待任务队列中清理执行完所有已到达执行条件的微任务,

5.然后再拿取下一个宏任务来执行,如果宏任务执行产生微任务或者微任务执行产生宏任务就一样加入到等待任务队列中,然后还是按照主线程每次到等待队列中先执行完所以的微任务再逐个执行宏任务的顺序来走

异步任务都是谁先到达条件谁先执行,但是谁先到达执行条件也有优先级的问题,这个优先级要看这个任务是宏任务还是微任务;微任务的优先级比宏任务的要高;

3.运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

*    执行一个宏任务(栈中没有就从事件队列中获取)*    执行过程中如果遇到微任务,就将它添加到微任务的任务队列中*    宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)*    当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染*    渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

一张图解释

宏任务:

(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,流程如下:(macro)task->渲染->(macro)task->...

微任务:

microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

宏任务(macrotask)微任务(microtask)

谁发起的宿主(Node、浏览器)JS引擎

具体事件1.script(同步代码), 2.setTimeout/setInterval, 3.UI rendering/UI事件, 4.postMessage,MessageChannel, 5.setImmediate,I/O(Node.js)1. Promise, 2.MutaionObserver, 3.Object.observe(已废弃;Proxy 对象替代), 4.process.nextTick(Node.js)

谁先运行后运行先运行

会触发新一轮tick吗会不会

代码块1

setTimeout(function(){console.log('1')});newPromise(function(resolve){console.log('2');  resolve();}).then(function(){console.log('3')});console.log('4');//2  4  3  1

分析:

(1)settimeout是宏任务,虽然先执行的他,但是他被放到了宏任务的eventqueue里面,(2)往下检查看有没有微任务,发现Promise回调函数内的代码是同步的(微任务)输出2

(3)then函数把他放入了微任务序列。

(4)主代码块(宏任务)输出4

(5)主线进程所有代码执行结束。先从微任务queue里拿回掉函数,输出3微任务全部完成

(6)再从宏任务的queue拿函数。输出1

代码块2

console.log('1');setTimeout(function(){console.log('2');    process.nextTick(function(){console.log('3');    })newPromise(function(resolve){console.log('4');        resolve();    }).then(function(){console.log('5')    })})process.nextTick(function(){console.log('6');})newPromise(function(resolve){console.log('7');    resolve();}).then(function(){console.log('8')})setTimeout(function(){console.log('9');    process.nextTick(function(){console.log('10');    })newPromise(function(resolve){console.log('11');        resolve();    }).then(function(){console.log('12')    })})

1.主代码块输出1

2.宏任务1setTimeout(2,3,4,5)

3.微任务1process(6)

4.promise立即执行,回调是同步输出7,then微任务2(8)

5.宏任务2setTimeout(9,10,11,12)

主代码全部执行完(余微任务1,2,宏任务1,2)

6.执行微任务1,输出6

7.执行微任务2,输出8

微任务全部执行完(余宏任务1, 2)

8.执行宏任务1,输出2,

增微任务process(3)

promise立即执行回调输出4,微任务(5),

9.执行微任务输出3,输出5

10.执行宏任务2,输出9,

增微任务process(10)

promise立即执行回调输出11,微任务(12),

11.执行微任务输出10,输出12

代码块3

asyncfunctionasync1(){console.log('async1 start');awaitasync2();console.log('async1 end');}asyncfunctionasync2(){console.log('async2');}console.log('script start');setTimeout(function(){console.log('setTimeout');},0)async1();newPromise(function(resolve){console.log('promise1');    resolve();}).then(function(){console.log('promise2');});console.log('script end');

1.输出“script start”

2.setTimeout宏任务

3.执行async1()输出async1 start,执行 async2(),输出 “async2”。

4.async2执行完毕,将await async2 后面的代码加入到 微任务队列async1 end');

5、继续执行,new Promise, 同步输出“promise1”。promise.then,加入到微任务队列,

6.输出script end

7.当前宏任务执行完毕,查看微任务队列输出async1 end “promise2”

8.微任务全部执行完,检查宏任务,输出setTimeout

改上面代码:

asyncfunctionasync1(){console.log('async1 start');letp =awaitasync2();console.log(p);console.log('async1 end');}asyncfunctionasync2(){console.log('async2');returnnewPromise(((resolve, reject) => {        resolve(10);    }))}console.log('script start');setTimeout(function() {console.log('setTimeout');}, 0)async1();newPromise(function(resolve) {console.log('promise1');    resolve();}).then(function() {console.log('promise2');});console.log('script end');scriptstartasync1startasync2promise1scriptendpromise210async1endsetTimeout

new promise的操作就跟你 new 一个普通函数没区别,所以这一句其实是宏任务,但后面的then是微任务

resolved后的promise对象会在这该级别事件队列结束之后才开始执行,及执行与该轮微任务队列中,始于下一级别宏任务之前

resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

如果出现两个这种微任务,则先出现的会先执行

async 函数中,遇到 await 会跳出当前函数,并让出线程,再将await后面的代码放到 微任务(microtask)队列中

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

推荐阅读更多精彩内容