新聞中心
一道JavaScript面試題(setTimeout)

下面的代碼,多久之后會(huì)彈出'end'? 為什么?
這是以前在想有沒辦法實(shí)現(xiàn)阻塞javascript線程的時(shí)候(即實(shí)
- var t = true;
- setTimeout(function(){ t = false; }, 1000);
- while(t){ }
- alert('end');
現(xiàn)sleep方法),想過的一種實(shí)現(xiàn)。
很簡(jiǎn)單,是吧?
是嗎?
重新認(rèn)識(shí)javascript的settimeout和異步
今晚看到QLeelulu的一道JavaScript面試題(setTimeout),稍微想了一下,好不容易連猜帶蒙,湊巧說對(duì)了答案。但是原因到底是什么呢?自己一時(shí)也說不太清楚,反正感覺就是一個(gè)死循環(huán)造成的。然后看了一下文章下面的評(píng)論,發(fā)現(xiàn)5樓(典型的死循環(huán)……js是單線程執(zhí)行的,while里面死掉的時(shí)候setTimeout里面的函數(shù)是沒機(jī)會(huì)執(zhí)行的。)和6樓(setTimeout 只是掛了個(gè)定時(shí)任務(wù),但是 JS 本身是單線程的,while 那里肯定死掉了。)的回答很有道理,主要意思就是說javascript引擎是單線程執(zhí)行的,while循環(huán)那里執(zhí)行的時(shí)候,settimeout里面的函數(shù)根本沒有執(zhí)行的機(jī)會(huì),這樣while那里永遠(yuǎn)為真,造成死循環(huán)。但是單純看還是不怎么踏實(shí),最后發(fā)揮實(shí)踐精神,自己動(dòng)手做了兩個(gè)實(shí)驗(yàn):
1、簡(jiǎn)單的settimeout
- setTimeout(function () { while (true) { } }, 1000);
- setTimeout(function () { alert('end 2'); }, 2000);
- setTimeout(function () { alert('end 1'); }, 100);
- alert('end');
執(zhí)行的結(jié)果是彈出‘end’‘end 1’,然后瀏覽器假死,就是不彈出‘end 2’。也就是說第一個(gè)settimeout里執(zhí)行的時(shí)候是一個(gè)死循環(huán),這個(gè)直接導(dǎo)致了理論上比它晚一秒執(zhí)行的第二個(gè)settimeout里的函數(shù)被阻塞,這個(gè)和我們平時(shí)所理解的異步函數(shù)多線程互不干擾是不符的。
2、ajax請(qǐng)求回調(diào)
接著我們來測(cè)試一下通過xmlhttprequest實(shí)現(xiàn)ajax異步請(qǐng)求調(diào)用,主要代碼如下:
- var xmlReq = createXMLHTTP();//創(chuàng)建一個(gè)xmlhttprequest對(duì)象
- function testAsynRequest() {
- var url = "/AsyncHandler.ashx?action=ajax";
- xmlReq.open("post", url, true);
- xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- xmlReq.onreadystatechange = function () {
- if (xmlReq.readyState == 4) {
- if (xmlReq.status == 200) {
- var jsonData = eval('(' + xmlReq.responseText + ')');
- alert(jsonData.message);
- }
- else if (xmlReq.status == 404) {
- alert("Requested URL is not found.");
- } else if (xmlReq.status == 403) {
- alert("Access denied.");
- } else {
- alert("status is " + xmlReq.status);
- }
- }
- };
- xmlReq.send(null);
- }
- testAsynRequest();//1秒后調(diào)用回調(diào)函數(shù)
- while (true) {
- }
在服務(wù)端實(shí)現(xiàn)簡(jiǎn)單的輸出:
- private void ProcessAjaxRequest(HttpContext context)
- {
- string action = context.Request["ajax"];
- Thread.Sleep(1000);//等1秒
- string jsonObject = "{\"message\":\"" + action + "\"}";
- context.Response.Write(jsonObject);
- }
理論上,如果ajax異步請(qǐng)求,它的異步回調(diào)函數(shù)是在單獨(dú)一個(gè)線程中,那么回調(diào)函數(shù)必然不被其他線程”阻撓“而順利執(zhí)行,也就是1秒后,它回調(diào)執(zhí)行彈出‘a(chǎn)jax’,可是實(shí)際情況并非如此,回調(diào)函數(shù)無法執(zhí)行,因?yàn)闉g覽器再次因?yàn)樗姥h(huán)假死。
結(jié)論:根據(jù)實(shí)踐結(jié)果,可以得出,javascript引擎確實(shí)是單線程處理它的任務(wù)隊(duì)列(能理解成就是普通函數(shù)和回調(diào)函數(shù)構(gòu)成的隊(duì)列嗎?)的。在javascript里實(shí)現(xiàn)異步編程很大程度上就是一種障眼法,單線程的引擎實(shí)現(xiàn)多線程的編程,如果要實(shí)現(xiàn)一些資源同步互斥之類的操作(一如C#、Java等語言的多線程),我感覺真正實(shí)現(xiàn)起來根本無法輕易得到保證。
補(bǔ)充:如何實(shí)現(xiàn)javascript的sleep呢?在stackoverflow上找到一篇javascript sleep,試了一下,效果是有了,但是執(zhí)行的時(shí)候cpu很高,真還不如直接settimeout呢。
網(wǎng)站標(biāo)題:一道面試題引發(fā)的面壁:認(rèn)識(shí)JavaScript的settimeout和異步
URL地址:http://m.fisionsoft.com.cn/article/cdsdghs.html


咨詢
建站咨詢
