重新认识javascript的settimeout和异步

今晚看到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等语言的多线程),我感觉真正实现起来根本无法轻易得到保证。

本文分享自微信公众号 - 交互设计前端开发与后端程序设计(interaction_Designer)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-08-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码农分享

状态模式(State)

模式的组成 环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。 抽象状态类(State...

9720
来自专栏XAI

Highcharts AJAX JSON JQuery 实现动态数据交互显示图表 柱形图

这是第一篇实例的步骤与代码。还有整个项目的结构图。 http://my.oschina.net/xshuai/blog/345117 原创的博文。转载注明出处...

64060
来自专栏自由而无用的灵魂的碎碎念

多层次探秘Windows Vista的区域与语言选项和多语言版本问题

之前,一直想深入了解下Windows Vista Ultimate的英文版与中文版有什么详细的区别,因为Ultimate版支持多国语言。这便萌生了写这篇文章的想...

13330
来自专栏Golang语言社区

Go语言实战: 编写可维护Go语言代码建议

大家好, 我在接下来的两个会议中的目标是向大家提供有关编写Go代码最佳实践的建议。

26530
来自专栏用户2442861的专栏

Java Web 中使用ffmpeg实现视频转码、视频截图,javaffmpeg

http://www.cnblogs.com/dennisit/archive/2013/02/16/2913287.html#!comments

91410
来自专栏非著名程序员

常见面试第四题之requestLayout, invalidate和postInvalidate的异同

requestLayout, invalidate和postInvalidate的异同 ? 今天我们来讲讲在面试当中最常见的,最常常被问到的第四题,近期由于小...

28150
来自专栏雨过天晴

原 荐 C# FTP 坑了我两天的一个坑

1.5K70
来自专栏苦逼的码农

回车与换行的故事

以前在学汇编的时候,一直不知道老师在换行时,总会打一个换行符和回车符,原来他们还有这么一个故事….

17930
来自专栏趣谈编程

synchronized与Lock 擂台之战

面试官:说说synchronized和Lock(或ReentrantLock)的区别 Java 1.5之后,对共享变量访问的协调机制除了之前的synchron...

219100
来自专栏极客慕白的成长之路

信息安全实验室招新试题和完全解析

写个网页应该是很简单的,不管是静态网页还是带特效的网页。但是有几个问题,需要说明一下。

14930

扫码关注云+社区

领取腾讯云代金券