鍍金池/ 問答/HTML/ events loop

events loop

html中代碼

<div class="po">32wewe</div>

JavaScript代碼

var po = document.querySelector('.po')
var op = 0
for (var k = 0; k < 3; k++) {
    setTimeout(function () {
        console.log(k)
    }, 0)
}

var p;
for (var i = 0; i < 999999666; i++) {
    p = i
}
console.log(p)
po.addEventListener('click', function (e) {
    console.log(++op)
})
po.click()
console.log('主線程結(jié)束')

如果主線程在執(zhí)行的時(shí)候,我瘋狂點(diǎn)擊po元素,最后setTimeout永遠(yuǎn)都是最后顯示,即使在這里立即執(zhí)行click也是,看了別人寫的文章關(guān)于js的events loop,難道我沒理解到其中的深意?上面所說的情況都是在谷歌下測試的

回答
編輯回答
歆久

1.p.click是一個(gè)同步調(diào)用其效果相當(dāng)于使用p元素執(zhí)行dispatchEvent發(fā)送了一個(gè)模擬的鼠標(biāo)點(diǎn)擊動(dòng)作,而這個(gè)動(dòng)作是同步調(diào)用,也就是回去檢查是否有對(duì)應(yīng)的事件回調(diào)函數(shù)綁定到p上,如果有就同步調(diào)用
這個(gè)你可以通過如下代碼驗(yàn)證:

...
    po.addEventListener('click', function (e) {
        console.log(++op);
        console.log("click event listener invoked")
    });

...
po.click();
console.log("after po.click();");

輸出:
···
click event listener invoked
after po.click();
···

2.用戶操作的事件回調(diào)隊(duì)列執(zhí)行的優(yōu)先級(jí)要高于定時(shí)器事件隊(duì)列的執(zhí)行優(yōu)先級(jí)

2017年4月19日 08:37
編輯回答
賤人曾

js是一門“單線程”“非阻塞”語言

event loop:

  1. 執(zhí)行js代碼
  2. 遇到同步代碼,按照順序放入執(zhí)行棧
  3. 遇到異步代碼,不會(huì)阻塞后續(xù)的代碼執(zhí)行,等到異步請(qǐng)求成功直接將回調(diào)函數(shù)放入事件隊(duì)列
  4. 事件隊(duì)列內(nèi)部的回調(diào)函數(shù)并不是馬上執(zhí)行的,而是等到執(zhí)行棧中的同步代碼全部執(zhí)行完畢,才會(huì)從事件隊(duì)列中取出一個(gè)個(gè)回調(diào)函數(shù)放入執(zhí)行棧,執(zhí)行棧在繼續(xù)它的工作。

異步:通常是ajax請(qǐng)求、setTimeout、setInterval、i/o操作、onClick(用戶操作)等等

看到這里,應(yīng)該就可以理解了:為什么onClick的事件不能準(zhǔn)時(shí)執(zhí)行?因?yàn)榭赡茉谒迫氲绞录?duì)列時(shí),執(zhí)行棧還沒有為空,正在執(zhí)行其它同步代碼

這里就直接引用一張圖片來協(xié)助理解:
圖片描述

2017年12月20日 12:51
編輯回答
菊外人

并不知道你說的 events loop 是什么? 但是就我所知道的知識(shí)可以解釋你這個(gè)情況,

我瘋狂點(diǎn)擊po元素,最后setTimeout永遠(yuǎn)都是最后顯示

這里要說定時(shí)器的工作機(jī)制了;

除了主JavaScript 執(zhí)行進(jìn)程外,還有一個(gè)需要在進(jìn)程下一次空閑時(shí)執(zhí)行的代碼隊(duì)列;

定時(shí)器對(duì)隊(duì)列的工作方式是,當(dāng)特定時(shí)間過去后將代碼插入。注意,給隊(duì)列添加代碼并不意味著對(duì)它立刻執(zhí)行,而只能表示它會(huì)盡快執(zhí)行;

如果在這個(gè)時(shí)間點(diǎn)上,隊(duì)列中沒有其他東西,那么這段代碼就會(huì)被執(zhí)行;

在這里,我理解,如果 間隔 = 0 相當(dāng)于,就相當(dāng)于,在執(zhí)行順序上降低了優(yōu)先級(jí),因?yàn)?setTimeout 讓 他的回調(diào)等待隊(duì)列空閑再執(zhí)行,相當(dāng)于本來我先運(yùn)行,現(xiàn)在我等別人運(yùn)行完了我再運(yùn)行;不信可以測試下下面代碼:

setTimeout('alert(1)',0);
alert(2);
alert(3);

這里會(huì)把 alert(1) 放在最后執(zhí)行,間隔為0相當(dāng)于降低了執(zhí)行順序的優(yōu)先級(jí);

題主瘋狂點(diǎn)擊po元素,就是在不斷往下一次執(zhí)行的代碼隊(duì)列里不斷添加新的代碼,setTimeout 一直要等待空閑,那自然就是最后顯示了。紅框是 setTimeout

clipboard.png

詳情可以戳這里了解:innerHTML 延后執(zhí)行?

2018年6月30日 17:27
編輯回答
硬扛

正常情況下的輸出應(yīng)該是

999999665
1
主線程結(jié)束
3
3
3

setTimeout的時(shí)間參數(shù)默認(rèn)最小值是4ms,而且setTimeout的函數(shù)會(huì)被推入到事件隊(duì)列中,等待主線程執(zhí)行完畢后再加入到執(zhí)行棧執(zhí)行。
同樣的,click觸發(fā)的事件也是先加入事件隊(duì)列,等待主線程內(nèi)全部執(zhí)行完畢后再按次序加入執(zhí)行棧執(zhí)行。
具體的你還是看這篇文章吧,一句兩句講不清楚。

2017年6月10日 02:45