重新認識javascript的settimeout和非同步

來源:互聯網
上載者:User

今晚看到QLeelulu的一道JavaScript面試題(setTimeout),稍微想了一下,好不容易連猜帶蒙,湊巧說對了答案。但是原因到底是什麼呢?自己一時也說不太清楚,反正感覺就是一個死迴圈造成的。然後看了一下文章下面的評論,發現5樓和6樓的回答很有道理,主要意思就是說javascript引擎是單線程執行的,while迴圈那裡執行的時候,settimeout裡面的函數根本沒有執行的機會,這樣while那裡永遠為真,造成死迴圈。但是單純看還是不怎麼踏實,最後發揮實踐精神,自己動手做了兩個實驗:

1、簡單的settimeout

        setTimeout(function () { while (true) { } }, 1000);        setTimeout(function () { alert('end 2'); }, 2000);        setTimeout(function () { alert('end 1'); }, 100);        alert('end');

執行的結果是彈出‘end’‘end 1’,然後瀏覽器假死,就是不彈出‘end 2’。也就是說第一個settimeout裡執行的時候是一個死迴圈,這個直接導致了理論上比它晚一秒執行的第二個settimeout裡的函數被阻塞,這個和我們平時所理解的非同步函數多線程互不干擾是不符的。

2、ajax請求回調

接著我們來測試一下通過xmlhttprequest實現ajax非同步請求調用,主要代碼如下:

        var xmlReq = createXMLHTTP();//建立一個xmlhttprequest對象        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秒後調用回呼函數                while (true) {        }

在服務端實現簡單的輸出:

        private void ProcessAjaxRequest(HttpContext context)        {            string action = context.Request["ajax"];            Thread.Sleep(1000);//等1秒            string jsonObject = "{\"message\":\"" + action + "\"}";            context.Response.Write(jsonObject);        }

理論上,如果ajax非同步請求,它的非同步回呼函數是在單獨一個線程中,那麼回呼函數必然不被其他線程”阻撓“而順利執行,也就是1秒後,它回調執行彈出‘ajax’,可是實際情況並非如此,回呼函數無法執行,因為瀏覽器再次因為死迴圈假死。

結論:根據實踐結果,可以得出,javascript引擎確實是單線程處理它的任務隊列(能理解成就是普通函數和回呼函數構成的隊列嗎?)的。在javascript裡實現非同步編程很大程度上就是一種障眼法,單線程的引擎實現多線程的編程,如果要實現一些資源同步互斥之類的操作(一如C#、Java等語言的多線程),我感覺真正實現起來根本無法輕易得到保證。

補充:如何?javascript的sleep呢?在stackoverflow上找到一篇javascript sleep,試了一下,效果是有了,但是執行的時候cpu很高,真還不如直接settimeout呢。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.