javascript 异步编程-setTimeout

javascript的执行引擎是单线程的,正常情况下是同步编程的模式,即是程序按照代码的顺序从上到下依次顺序执行。只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),那么在执行期间任何UI更新都会被阻塞,界面事件处理也会停止响应。导致整个页面卡在这个地方,其他任务无法执行。

特别是在for循环语句里,如果for循环的处理逻辑比较复杂,并且循环次数过多,超过1000次时,javascript的执行会阻塞浏览器处理起来会有明显的假死状态。原因就是浏览器在调用javascript的时候,主界面是停止响应的,因为cpu交给js执行了,没有时间去处理界面消息。

为了解决卡死的问题,很多人提出了异步编程的解决方案,这也是性能优化的其中一个方式,在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应。现在很火的nodejs就是异步编程,比如路由派发,IO操作,都是异步的。

在前端页面实现中,最常见的异步就是ajax操作,请求一个ajax无需等待ajax返回,则可继续操作页面。

其他的还有通过setTimeout,setInterval,image.onloadpostMessage,webwork等方式进行异步编程实现。

网上也有很多库实现了异步编程如:do.jsstep.jsasync.jsflow.js,就不详细阐述了,有兴趣的自行google了解。

setTimeOut

这里主要讲setTimeOut实现异步编程的方式。

先看一段代码,http://jsfiddle.net/jd_felix/mmrL66na/1/

<!DOCTYPE html>
<html>
<head>
    <title>DEMO</title>
</head>
<script src="http://codeorigin.jquery.com/jquery-1.10.2.min.js"></script>
<script>
    var updateSync = function() {
        for (var i = 0; i < 1000; i++) {
            $(‘#js_output‘).text(i);
        }
    }
    var updateAsync = function() {
        var i = 0;
        function updateLater() {
            $(‘#js_output‘).text(i++);
            if (i < 1000) {
                setTimeout(updateLater, 0);
            }
        }
        updateLater();
    }
</script>
<body>
<button onclick="updateSync()">同步DEMO</button>
<button onclick="updateAsync()">异步DEMO</button>
<div id="js_output"></div>
</body>
</html>

点击同步DEMO:你会感觉按钮按下去的时候卡了一下,然后看到一个最终结果99999,而没有中间过程,这就是因为在updateSync函数运行过程中UI更新被阻塞,只有当它结束退出后才会更新UI。

点击异步DEMO:你会看到UI界面上从0到999快速地更新过程,这就是异步执行的结果。 函数里先声明了一个局部变量i和嵌套函数updateLater,然后调用了updateLater,在这个函数中先是更新output结点的内容为i, 然后通过setTimeout让updateLater函数异步执行。这实际是一种递归调用。任何for循环都可以改造成递归调用的形式。

为什么用了setTimeOut(fn,0)后,还是能看到快速的更新呢?

这是因为虽然他的delay设置为0,几乎是即时触发,但还是被添加到了执行队列后面,但就是这个过程,渲染已经完成了,当他回调函数执行时,输出来的已经是更新后的值了。

以上结果很显然,异步操作不会阻塞UI,你可以继续执行浏览器其他操作。让UI操作更流畅,但异步编程也有坏处,如上面代码,使用setTimeout的异步方式,在代码整体执行效率来看,要比同步执行耗时更长时间。同时由于是异步执行,打断了原有代码的执行顺序,造成嵌套的函数调用,破坏了原有的简单逻辑,让代码难以读懂。

在判断是否执行完毕时,在同步编程中很方便实现,代码写在for循环后面就行了。而异步的话,则需要做一些判断。

还是以上的例子,如何在循环结束后执行回调?可以使用Jquery$.when,和$.Deferred方法,当然也可以自己写回调函数,但是看起来没那么优雅。

var wait = function(){
        var dtd = $.Deferred();
        var i = 0;
        function updateLater() {
            $(‘#js_output‘).text(i++);
            if (i < 1000) {
                setTimeout(updateLater, 0);
            }
            if(i == 1000){
                dtd.resolve(); // 改变Deferred对象的执行状态
            }
        }
        updateLater();
        return dtd.promise(); // 返回promise对象
    }
    var updateAsyncBack = function(){
        $.when(wait()).done(function(){
            alert(‘done!‘);
        })
    }

原文请看:http://faso.me/notes/20131123/javascript-synchronous-settimeout/

时间: 2024-11-15 08:52:52

javascript 异步编程-setTimeout的相关文章

JavaScript异步编程设计快速响应的网络应用

JavaScript已然成为了多媒体.多任务.多内核网络世界中的一种单线程语言.其利用事件模型处理异步触发任务的行为成就了JavaScript作为开发语言的利器.如何深入理解和掌握JavaScript异步编程变得尤为重要!!!<JavaScript异步编程设计快速响应的网络应用>提供了一些方法和灵感. 一.深入理解JavaScript事件 1. 事件的调度 JavaScript事件处理器在线程空闲之前不会运行(空闲时运行). var start = new Date(); setTimeout

JavaScript异步编程(一) 深入理解JavaScript事件

JavaScript异步编程 深入理解JavaScript事件 ?事件的调度 JavaScript事件处理器在线程空闲之前不会运行 线程的阻塞 var start = new Date(); // setTimeout和setInterval的计时精度比期望值差 setTimeout(function(){ var end = new Date(); console.log('Time elapsed', end - start, 'ms'); }, 500); while(new Date -

JavaScript异步编程(2)- 先驱者:jsDeferred

原文出处: linkFly   欢迎分享原创到伯乐头条 JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascript的异步编程,jsDeferred也是有必要探索的:因为Promise/A+规范的制定基本上是奠定在jsDeferred上,它是javascript异步编程中里程碑式的作品.jsDeferred自身的实现也是非常有意思的. 本文将探讨项目js

Javascript异步编程方法之------“事件监听”

Javascript异步编程方法之------“事件监听”另一种思路是采用事件驱动模式.任务的执行不取决于代码的顺序,而取决于某个事件是否发生.还是以f1和f2为例.首先,为f1绑定一个事件(这里采用的jQuery的写法).f1.on('done', f2);上面这行代码的意思是,当f1发生done事件,就执行f2.然后,对f1进行改写:function f1(){setTimeout(function () {// f1的任务代码f1.trigger('done');}, 1000);}f1.

Javascript异步编程方法之------“发布/订阅”

Javascript异步编程方法之------“发布/订阅”我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行.这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern).这个模式有多种实现

深入解析Javascript异步编程

这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程对其尤为重要. 拿nodejs来说,外壳是一层js语言,这是用户操作的层面,在这个层次上它是单线程运行的,也就是说我们不能像Java.Python这类语言在语言级别使用多线程能力.取而代之的是,nodejs编程中大量使用了异步编程技术,这是为了高效使用硬件,同时也可以不造成同步阻塞.不过nodejs

5分种让你了解javascript异步编程的前世今生,从onclick到await/async

javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为浏览器设计的GUI编程语言,GUI编程的特性之一是保证UI线程一定不能阻塞,否则体验不佳,甚至界面卡死. 一般安卓开发,会有一个界面线程,一个后台线程,保证界面的流畅.由于javascript是单线程,所以采用异步非阻塞的编程模式,javascript的绝大多数api都是异步api. 本文是本人的一个

JavaScript 异步编程

JavaScript 异步编程 第一章 深入理解JavaScript事件 1. javascirpt一般是单线程执行,setTimeout 和 setInterval 仅当cpu空闲时执行. var start = new Date; setTimeout(function(){ var end = new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000)

Javascript异步编程之二回调函数

上一节讲异步原理的时候基本上把回掉函数也捎带讲了一些,这节主要举几个例子来具体化一下.在开始之前,首先要明白一件事,在javascript里函数可以作为参数进行传递,这里涉及到高阶函数的概念,大家可以自行google一下. 传统的同步函数需要返回一个结果的话都是通过return语句实现,例如: function foo() { var a = 3, b = 2; return a+b; } var c = foo(); console.log(c); //5 就是说后面的代码console.lo