一道面试题引发的面壁:认识JavaScript的settimeout和异步

开发 前端
今晚看到QLeelulu的一道JavaScript面试题(setTimeout),稍微想了一下,好不容易连猜带蒙,凑巧说对了答案。但是原因到底是什么呢?自己一时也说不太清楚,反正感觉就是一个死循环造成的。那么我们就回到原点重新认识javascript的settimeout和异步吧!

一道JavaScript面试题(setTimeout)

下面的代码,多久之后会弹出'end'? 为什么?

这是以前在想有没办法实现阻塞javascript线程的时候(即实

  1. var t = true;  
  2.  
  3. setTimeout(function(){ t = false; }, 1000);  
  4.  
  5. while(t){ }  
  6.  
  7. alert('end'); 

现sleep方法),想过的一种实现。

很简单,是吧?

是吗?

重新认识javascript的settimeout和异步

今晚看到QLeelulu的一道JavaScript面试题(setTimeout),稍微想了一下,好不容易连猜带蒙,凑巧说对了答案。但是原因到底是什么呢?自己一时也说不太清楚,反正感觉就是一个死循环造成的。然后看了一下文章下面的评论,发现5楼(典型的死循环……js是单线程执行的,while里面死掉的时候setTimeout里面的函数是没机会执行的。)和6楼(setTimeout 只是挂了个定时任务,但是 JS 本身是单线程的,while 那里肯定死掉了。)的回答很有道理,主要意思就是说javascript引擎是单线程执行的,while循环那里执行的时候,settimeout里面的函数根本没有执行的机会,这样while那里永远为真,造成死循环。但是单纯看还是不怎么踏实,最后发挥实践精神,自己动手做了两个实验:

1、简单的settimeout

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

执行的结果是弹出‘end’‘end 1’,然后浏览器假死,就是不弹出‘end 2’。也就是说第一个settimeout里执行的时候是一个死循环,这个直接导致了理论上比它晚一秒执行的第二个settimeout里的函数被阻塞,这个和我们平时所理解的异步函数多线程互不干扰是不符的。

2、ajax请求回调

接着我们来测试一下通过xmlhttprequest实现ajax异步请求调用,主要代码如下:

  1. var xmlReq = createXMLHTTP();//创建一个xmlhttprequest对象  
  2.        function testAsynRequest() {  
  3.            var url = "/AsyncHandler.ashx?action=ajax";  
  4.            xmlReq.open("post", url, true);  
  5.            xmlReq.setRequestHeader("Content-Type""application/x-www-form-urlencoded");  
  6.            xmlReq.onreadystatechange = function () {  
  7.                if (xmlReq.readyState == 4) {  
  8.                    if (xmlReq.status == 200) {  
  9.                        var jsonData = eval('(' + xmlReq.responseText + ')');  
  10.                        alert(jsonData.message);  
  11.                    }  
  12.                    else if (xmlReq.status == 404) {  
  13.                        alert("Requested URL is not found.");  
  14.                    } else if (xmlReq.status == 403) {  
  15.                        alert("Access denied.");  
  16.                    } else {  
  17.                        alert("status is " + xmlReq.status);  
  18.                    }  
  19.                }  
  20.            };  
  21.            xmlReq.send(null);  
  22.        }  
  23.        testAsynRequest();//1秒后调用回调函数  
  24.          
  25.        while (true) {  
  26.  
  27.        } 

在服务端实现简单的输出:

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

理论上,如果ajax异步请求,它的异步回调函数是在单独一个线程中,那么回调函数必然不被其他线程”阻挠“而顺利执行,也就是1秒后,它回调执行弹出‘ajax’,可是实际情况并非如此,回调函数无法执行,因为浏览器再次因为死循环假死。

结论:根据实践结果,可以得出,javascript引擎确实是单线程处理它的任务队列(能理解成就是普通函数和回调函数构成的队列吗?)的。在javascript里实现异步编程很大程度上就是一种障眼法,单线程的引擎实现多线程的编程,如果要实现一些资源同步互斥之类的操作(一如C#、Java等语言的多线程),我感觉真正实现起来根本无法轻易得到保证。

补充:如何实现javascript的sleep呢?在stackoverflow上找到一篇javascript sleep,试了一下,效果是有了,但是执行的时候cpu很高,真还不如直接settimeout呢。

原文链接:http://www.cnblogs.com/jeffwongishandsome/archive/2011/06/13/2080145.html

【编辑推荐】

  1. JavaScript重构深入剖析
  2. 19个很有用的JavaScript库强烈推荐
  3. 惊动大神的JavaScript:在Web上运行Linux
  4. 15款超棒的JavaScript开发工具推荐
  5. 从零开始学习jQuery之你必须知道的JavaScript
责任编辑:陈贻新 来源: Jeff Wong的博客
相关推荐

2017-03-10 09:33:16

JavaScript类型

2021-03-16 05:44:26

JVM面试题运行时数据

2015-09-02 14:09:19

面试题程序设计

2011-05-23 11:27:32

面试题面试java

2021-05-31 07:55:44

smartRepeatJavaScript函数

2018-03-06 15:30:47

Java面试题

2009-08-11 10:12:07

C#算法

2023-02-04 18:24:10

SeataJava业务

2017-11-21 12:15:27

数据库面试题SQL

2009-08-11 15:09:44

一道面试题C#算法

2022-04-08 07:52:17

CSS面试题HTML

2009-08-11 14:59:57

一道面试题C#算法

2021-10-28 11:40:58

回文链表面试题数据结构

2011-03-02 10:58:16

SQL server入门面试题

2023-08-01 08:10:46

内存缓存

2017-09-13 07:15:10

Python读写文件函数

2021-03-27 10:59:45

JavaScript开发代码

2022-02-08 18:09:20

JS引擎解析器

2017-11-06 13:02:37

前端setTimeout循环闭包

2018-02-01 16:26:44

面试题static变量
点赞
收藏

51CTO技术栈公众号