一 关于事件的异步

事件是JavaScript中最重要的一个特征,nodejs就是利用js这一异步而设计出来的。所以这里讲一下事件机制。

在一个js文件中,如果要运行某一个函数,有2中手段,一个就是直接调用,比如foo(),第二就是利用事件来触发,这中函数也叫回调函数,比如传递给setTimeout函数和onready属性。

1.setTimeout函数中的事件异步

setTimeout本质上也是一种异步事件,当延迟时间到的时候触发该事件,但是有的有的时候(其实也是大部分时候)都不会按照给定的延迟时间执行,先看下面的代码

        var start = new Date();
setTimeout(function() {
console.log('settimeout1:',new Date()-start);
}, 500);
while (new Date() - start < 1000) {
console.log('in while');
}
document.getElementById('test').addEventListener('click', function(){
console.log('test:',new Date()-start);
}, false)
for(var i=0;i<10000;i++){
console.log('in for');
}
setTimeout(function(){
console.log('settimeout2: ',new Date()-start);
},1000);
/* 10214
in while
index.jsp (第 19 行)
10000
in for
index.jsp (第 25 行)
settimeout1: 2263
index.jsp (第 16 行)
settimeout2: 3239
index.jsp (第 28 行)
test: 10006
index.jsp (第 22 行)
test: 28175
index.jsp (第 22 行)
test: 28791
index.jsp (第 22 行)
test: 28966
index.jsp (第 22 行) */

如果按照正常的理解,延迟函数应该在500毫秒之后打断while循环,而事实上并没有,并且,我在while循环和for循环期间点击div时候并没有立即输出test,给出的解释就是:

a)事件队列。调用setTimeout函数的时候,会把传入它的回调函数加入到事件队列中去(事件已经初始化并且在内存了),然后继续执行后面的代码,直到再也没有代码可以运行(没有正常的运行流了,不包括事件函数等异步的内容),就会从事件队列里面pop出一个合适的事件来运行。

b)js是单线程的,事件处理器在线程空闲之前是不会运行的。

2 普通事件的异步和setTimeout类似

二 promise对象和deferred对象

1. promise

promise是一种解决ajax等异步编程回调函数嵌套太多导致代码晦涩难懂的解决方案,特别是在nodejs中,异步无处不在。不同的框架对promise的实现,一下是jquery中的promise的API。

这里不讲promise的实现原理,关于原理在另外的篇幅中介绍。

传统的ajax异步编程是这么写的(jquery1.5之前):

$.get('url', function(){
$.get('url1', function(){
$.get('url2', function(){ }, 'json');
}, 'json');
}, 'json');

这么写代码给开发和维护带来了极大的困难,好在jquery1.5以后引入了promise,就可以这么写了:

 $.ajax( "example.php" )
.done(function() { alert("success"); })
.fail(function() { alert("error"); })
.always(function() { alert("complete"); });

现在看上去就明显简单多了。

2.deferred对象

var nanowrimoing = $.Deferred();
var wordGoal = 5000;
nanowrimoing.progress(function(wordCount) {
var percentComplete = Math.floor(wordCount / wordGoal * 100);
$('#indicator').text(percentComplete + '% complete');
});
nanowrimoing.done(function(){
$('#indicator').text('Good job!');
});

三.worker对象和多线程

四.异步脚本加载

1.传统脚本在页面中的位置

脚本分为两大类:阻塞式和非阻塞式。这里的阻塞是指加载阻塞而不是运行阻塞。

<!DOCTYPE html>
<html>
<head>
<script src="headScript"></script>
<script defer src="deferredScript"></script>
</head>
<body>
<script async defer src="chatWidget"></script>
<script async defer src="asyncScript"></script>
</body>
</html>

上面这部分代码是比较标准的关于脚本在一个页面中的位置,1.其中传统的未加任何修饰的headScript是阻塞式的脚本,由于浏览器从上到下解释执行JavaScript,所以这部分脚本文件在一开始就会被执行,并且在执行完之前是DOM是不会渲染的,但是head标签里面的css会加载。2.有defer属性的脚本会在DOM渲染的同时进行加载,但是会在DOM渲染完毕之后才开始执行,不幸的是,不是所有的浏览器都支持defer属性,所以才会有了jquery(function)这个东西。3.同时带有async属性和defer属性时候,defer会覆盖async,但是单独有async的时候,脚本会在DOM渲染的时候加载并且运行。

2.可编程的脚本加载

如果不是一开始就在页面种引入js文件,而是通过用户交互来实现动态的加载js脚本,可以通过编程方式加入。

浏览器获取服务器脚本有2个方法,ajax获取并且通过eval函数执行,另外一个就是在DOM中插入<script>标签,一般用第二种方法,因为浏览器帮助我们生成HTTP请求以及eval会泄露作用域。

var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = '/js/feature.js';
head.appendChild(script);
script.onload = function() {
// 现在可以调用脚本里定义的函数了
}

不过,一些老版本的浏览器不支持onloa事件,所以可以使用一些脚本加载库来实现这一功能,如require.js。

JavaScript中异步编程的更多相关文章

  1. javascript的异步编程

    同步与异步 介绍异步之前,回顾一下,所谓同步编程,就是计算机一行一行按顺序依次执行代码,当前代码任务耗时执行会阻塞后续代码的执行. 同步编程,即是一种典型的请求-响应模型,当请求调用一个函数或方法后, ...

  2. Web worker 与JS中异步编程的对比

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...

  3. 说一说javascript的异步编程

    众所周知javascript是单线程的,它的设计之初是为浏览器设计的GUI编程语言,GUI编程的特性之一是保证UI线程一定不能阻塞,否则体验不佳,甚至界面卡死. 所谓的单线程就是一次只能完成一个任务, ...

  4. 谈谈c#中异步编程模型的变迁

    大家在编程过程中都会用到一些异步编程的情况.在c#的BCL中,很多api都提供了异步方法,初学者可能对各种不同异步方法的使用感到迷惑,本文主要为大家梳理一下异步方法的变迁以及如何使用异步方法. Beg ...

  5. javascript的异步编程方法

    一,callback 回调函数 即函数f1和函数f2的关系是f1(f2()); f2作为f1()的回调函数,在f1执行过程中就开始执行f2,先执行线程的主要逻辑,将比较耗时的任务放在后面执行. 回调函 ...

  6. Java网络编程中异步编程的理解

    目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...

  7. [JavaScript] 的异步编程之手写一个Gernerator的例子

    <html> <head> <meta charset="UTF-8"> <title>Generator Demo</tit ...

  8. c#中异步编程

    异步是现实生活中的很多现象的一种抽象.比如分工合作在很多时间段就是异步合作.异步中也一般要涉及委托方法.c#有3种模式的异步编程:异步模式,基于事件的异步模式,基于任务的异步模式(TAP). 一.   ...

  9. C#中异步编程异常的处理方式

    异步编程异常处理 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.但是对于异步编程来说,异常处理一直 ...

随机推荐

  1. Dynamic range compression

    这段时间终于把手头的东西都搞完了,还剩下一个AEC这个模块,这个模块跟整个系统机制有很大关系,单独的模块意义不大. 另外,刚写完一个分类器,希望能大幅提升音乐流派分类的准确率. 下周正式开搞AEC,把 ...

  2. C语言学习_include&lt;&gt;与include&quot;&quot;的区别

    经常会遇到两种include引用头文件的情况,其实区别很简单,如下: 一.#include< > #include< > 引用的是编译器的类库路径里面的头文件. 假如你编译器定 ...

  3. Java基础知识强化之集合框架笔记30:集合之泛型的引入

    1. 泛型的引入: (1)首先我们看看下面这一段代码,如下: package cn.itcast_01; import java.util.ArrayList; import java.util.It ...

  4. iOS中不透明度的查看

    模拟器工具条 Debug-->Color Blended Layers 即中文显示下 调试 -->颜色混合层 绿色代表不透明部分,红色代表透明部分,红色越多对性能影响越大

  5. Linux批量重命名文件

    五种方法实现Linux批量重命名文件 Linux批量重命名文件是指对某些特定的文件统一进行重新命名,以改变原来一批文件的名称,这里介绍五种方法来实现. Linux批量重命名文件会涉及到改变一个字母.改 ...

  6. NOIP2002 字符变换

    啊本来以为2002的题应该会比较友善于是很naive地像模拟一样用着stl乱玩结果死也过不了最后一个点qaq 心情很悲痛于是为了解放自我 #include<iostream> #inclu ...

  7. Object:所有类的超类

    Java中每个类都是由Object类扩展而来 1.equals方法 在Object类中,这个方法用于判断两个对象是否具有相同的引用,然而对于大多数类来说,经常需要检测两个对象状态的相等性. publi ...

  8. 【云盘资料】Sql注入从菜鸟到高手系列教程

    [云盘资料]Sql注入从菜鸟到高手系列教程 ps:Sql注入从菜鸟到高手系列教程 链接:阅读原文获取资料:http://bbs.ichunqiu.com/thread-6851-1-1.html 反馈 ...

  9. Laravel 5.2服务----用户验证Auth相关问题

    关于laravel的auth()用户认证这一块,面前我也是,有用到,有碰到什么问题我就记录下来. 手动认证用户 <?php namespace App\Http\Controllers; use ...

  10. fk输入地壳模型容易出错的地方

    结束的那一层地壳模型后面不再有空格,否则不会有波形.