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/

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

  1. JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上

    众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...

  2. JavaScript异步编程原理

    众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...

  3. javascript异步编程的前世今生,从onclick到await/async

    javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...

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

    JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascri ...

  5. Promises与Javascript异步编程

    Promises与Javascript异步编程 转载:http://www.zawaliang.com/2013/08/399.html 在如今都追求用户体验的时代,Ajax应用真的是无所不在.加上这 ...

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

      javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...

  7. 转: Promises与Javascript异步编程

    在如今都追求用户体验的时代,Ajax应用真的是无所不在.加上这些年浏览器技术.HTML5以及CSS3等的发展,越来越多的富Web应用出现:在给与我们良好体验的同时,Web开发人员在背后需要处理越来越多 ...

  8. JavaScript异步编程

    前言 如果你有志于成为一个优秀的前端工程师,或是想要深入学习JavaScript,异步编程是必不可少的一个知识点,这也是区分初级,中级或高级前端的依据之一.如果你对异步编程没有太清晰的概念,那么我建议 ...

  9. 深入解析Javascript异步编程

    这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程 ...

随机推荐

  1. Discuz论坛搭建过程

    1.系统环境 操作系统版本:CentOS Linux  5.7 内核版本:2.6.18-274.el5 arch:x86_64 apache版本:Apache/2.4.6 (Unix) mysql版本 ...

  2. hdu1058丑数(优先队列、暴力打表)

    hdu1058 题意:当一个数只有2.3.5.7这四种质因数时(也可以一种都没有或只有其中几种),这个数就是丑数,输出第 n 个丑数是多少: 其实并没有发现hdu把这道题放在 dp 专题里的意图,我的 ...

  3. 英语语法最终珍藏版笔记- 21it 用法小结

    it 用法小结 it 在英语中的意思较多,用法较广,现总结如下. 一.it作句子的真正主语 1.it 指前面已经提到过的人或事物,有时指心目中的或成为问题的人或事物,作真正主语. 例如: What’s ...

  4. 【NOIP2008】双栈排序

    感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久--所以说我还是看题解了 原题: Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将 ...

  5. ps互补色

    色彩中的互补色有红色与绿色互补,蓝色与橙色互补,紫色与黄色互补.在光学中指两种色光以适当的比例混合而能产生白光时,则这两种颜色就称为“互为补色”. 互补色是相对的混合的白色 互补色:在色环中某种颜色的 ...

  6. Windows动态链接库DLL

    1.什么是DLLDLL,即动态链接库,是包含若干个函数的库文件,可供其他程序运行时调用. 2.DLL的优缺点优点:代码重用,可供多个程序同时调用 缺点:易发生版本冲突当新版本的动态链接库不兼容旧版本时 ...

  7. bugFree与zentao

    架构:b/s 开发语言:php 服务器端:lamp 客户端:浏览器 相关包:lamp BugFree是借鉴微软的研发流程和Bug管理理念,使用PHP+MySQL独立写出的一个Bug管理系统.简单实用. ...

  8. jmeter使用IP欺骗压力测试

    最近在使用jmeter进行压力测试时需要使用类似于loadrunner的IP欺骗功能,经问津度娘无果后决定再次耐心研究jmeter官方文 档,终于发现在jmeter2.5以上的版本有此功能的实现,由于 ...

  9. 【性能诊断】四、单功能场景的性能分析(RedGate,找到同一个客户端的并发请求被串行化问题)

    问题描述: 客户端js连续发起两个异步http请求,请求地址相同,但参数不同:POST http://*.*.*.*/*****/webservice/RESTFulWebService/RESTFu ...

  10. mysqldump: Got error: 1556: You can't use locks with log tables. when using LOCK TABLES

    mysqldump: Got error: 1556: You can't use locks with log tables. when using LOCK TABLES 我是把一些mysqldu ...