寫了個表單钱磅,其中有個這樣的設(shè)定:
輸入密碼,如果密碼長度低于6位似枕,則輸入框顏色變黃盖淡,且彈出提醒“密碼長度不低于6位”。
我把這部分的代碼拎出來菠净,如下:
<html>
<head>
<meta charset="utf-8">
<title>alert問題</title>
<style type="text/css">
.bg {
background-color: yellow;
}
</style>
</head>
<body>
<input type="text" id="pwd">
<input type="submit" id="btn" value="登錄">
<script type="text/javascript">
var btn = document.getElementById('btn');
btn.onclick = function(){
var pwd = document.getElementById('pwd');
if (pwd.value.length < 6) {
pwd.className = "bg";
alert("密碼長度不低于6位");
}
}
</script>
</body>
</html>
然而禁舷,在實際執(zhí)行的時候,卻發(fā)現(xiàn)一個現(xiàn)象:
先彈出alert對話框毅往,此時文本框并未變成黃色牵咙,點一下“確定”,文本框才變成黃色攀唯。
我們知道洁桌,JS是單線程的,alert()會阻塞JS繼續(xù)執(zhí)行侯嘀。
但是另凌,問題在于,“pwd.className = "bg";”在“alert("密碼長度不低于6位");”之前執(zhí)行戒幔,為什么還會被alert()阻塞呢吠谢?
有沒有可能是這樣:雖然pwd.className已經(jīng)被設(shè)置成了“bg”,但是CSS此時并沒有被加載诗茎,所以文本框仍然沒有變色工坊。JS繼續(xù)執(zhí)行,然后被alert()阻塞敢订。
為了驗證這個想法王污,我只需要在alert()前用console.log打印一下pwd,如果console里能出現(xiàn)pwd這個對象楚午,即便是文本框沒變色昭齐,仍然可以說明是按順序執(zhí)行的(這里我犯了一個錯,但是這個錯引出了有趣的東西)矾柜,于是循環(huán)體就變成:
pwd.className = "bg";
console.log(pwd);
alert("密碼長度不低于6位");
執(zhí)行一下試試阱驾,結(jié)果出乎意料,仍然是先彈出alert()對話框:
點完確定按鈕之后怪蔑,才同時出現(xiàn)pwd這個對象的內(nèi)容和黃色文本框啊易。
即便是不考慮CSS加載的問題,console.log(pwd);仍然沒有在alert()之前出結(jié)果饮睬。
很費解。篮奄。
猜想捆愁,由于alert()會阻塞js割去,給alert加個setTimeout試試:如果優(yōu)先執(zhí)行alert(),那么無論多少毫秒之后昼丑,都得alert()執(zhí)行完才能執(zhí)行console.log(pwd)呻逆。
pwd.className = "bg";
console.log(pwd);
setTimeout("alert('密碼長度不低于6位');", 100);
這段setTimeout代碼的意思是,100毫秒后執(zhí)行
"alert('密碼長度不低于6位');"
有趣的是菩帝,這次是console.log講pwd打印出來咖城,同時文本框變黃了,再彈出alert對話框呼奢。
也就是說宜雀,瀏覽器的確是按順序執(zhí)行的,并不是先運行alert()然后再去執(zhí)行前面的語句握础。
那為什么在之前的操作中辐董,出現(xiàn)了先alert()的情況呢?
答案可能就在setTimeout延后的時間里禀综。將這句代碼的時間改成1ms:
setTimeout("alert('密碼長度不低于6位');", 1);
果然又出現(xiàn)了先彈出alert()對話框并阻塞的情況简烘。我們可以推斷,其實此時瀏覽器已經(jīng)執(zhí)行過了修改className和打印pwd的操作定枷,僅僅過了1毫秒還沒有生效孤澎,js開始執(zhí)行alert(),然后就阻塞了欠窒。這也可以解釋設(shè)置成100毫秒就沒問題覆旭。
那瀏覽器多久可以設(shè)置好這兩項操作呢?
我試著在二分法在1-100ms之間找臨界點,發(fā)現(xiàn)我的瀏覽器在7毫秒的時候會先彈出alert再打印pwd窿给,而8毫米就可以先打印pwd再彈出alert组橄。
換句話說,瀏覽器需要8毫秒的時間茶敏,獲取到pwd對象,并將該對象轉(zhuǎn)化成字符串缚俏,在console里打印出來——其實也挺久的惊搏。
這里其實是我犯下的一個小錯誤,循環(huán)體里第一句“pwd.className = "bg";”忧换,其實后面更應(yīng)該用console.log()打印pwd.className而不是pwd本身恬惯。當然也正是因為這個疏忽,讓我發(fā)現(xiàn)了一些規(guī)律亚茬。
試一下:
pwd.className = "bg";
console.log(pwd.className);
setTimeout("alert('密碼長度不低于6位');", 1);
果然酪耳,瀏覽器花了1毫秒就獲取到了pwd的className。