前言

javascript的中的异步是很重要的概念,特别是ajax的提出,给整个web带来了很大的影响,今天就介绍下javascript的异步编程。

同步与异步

何为同步?何为异步呢?

同步:说白了就是程序一步一步从下向下执行,没有什么别的代码的跳动,就是按序执行,和在景区里女生上厕所是排队是一样的(每次女厕都是有好多人在排队)。可以看成是一个单线程问题。

异步:异步就是程序可以跳着执行,开始执行一段程序之后不用等返回结果就执行其他的代码,等结果返回之后在对结果进行处理,也就是可以在有限的时间内办好几件事情,提高效率,异步一般情况是多个线程问题。举个例子,还是上厕所的例子,A说需要5分钟搞定,B就可以5分钟之后过来,B可以在这5分钟干点别的事情。

所以说异步可以提高程序的执行效率,所以异步编程具有一定的好处,但是编写异步程序却不是那么容易的。

上面是我的理解,下面是摘自别人的文章:

"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

浏览器机制

我们都知道了,浏览器是单线程解析javascript的,也就是说,我们的浏览器原理是是不能搞成异步的,因为就一个线程嘛,如何搞成异步的呢?这就需要模拟异步来实现了,主要需要setTimeout函数。

setTimeout和setInterval

setTImeout是指延迟指定的毫秒数后调用函数或计算表达式。看个例子

setTimeout(function(){alert("延迟一秒弹出")},1000);

setInterval方法可按照指定的周期(以毫秒计)来调用函数或计算表达式,就是一定时间之后重新执行一次,例子

setInterval(function(){alert("一秒弹一次")},1000);

对应的取消方法是clearTimeout和clearInterval,用法很简单。

用上面的两个方法模拟所谓的“异步调用”事实上是通过将代码段插入到代码的执行队列中实现的,因为javascript是单线程执行的,程序按序执行下来时,等浏览器有时间了就等一定的时间将setTimeout中的代码添加到执行队列中,通过例子说明吧

 setTimeout(function(){console.log("延迟一秒打印我")},1000);
console.log("打印出我");

当执行1行代码时,浏览器将里面的function(){console.log("延迟一秒打印我")}代码添加到了执行队列,并且延迟1秒之后执行,之后就到了第2行代码,打印了结果"打印出我",过了一秒之后打印出"延迟一秒打印我"。可以看出第1行代码执行了之后,并没有执行完,而是执行了第2行代码,1秒之后再执行setTimeout中的函数,就这样模拟异步函数调用,其实说白了并不是真正的异步函数调用,事实上所谓的异步只是一个假象,同样是运行在一个线程上。

假如现在在执行异步调用的时候,浏览器一直没有时间,那么就不用进行调用了,例子

 setTimeout(function(){console.log("延迟一秒打印我")},1000);
while(true){}//模拟一直很忙
console.log("打印出我");

上段代码啥都不会打印出来,因为代码function(){console.log("延迟一秒打印我")}插入之后,它要等1秒之后才能执行,但是浏览器一直都在忙,所以即使到了1秒钟之后,代码也不会被执行。

异步编程

一般来说,异步编程有四种方式,分别为回调函数方式,事件监听方式,发布-订阅方式和Promise方式,下面分别介绍这些方式。

回调函数

所谓回调函数,就是将函数作为参数传到需要回调的函数内部再执行,·例子,例如f1是很耗时的程序,f1执行完之后执行f2,如果是普通的这样

f1();
f2();

f2需要很长的时间才能执行,为了提高效率,我们使用回调函数的方式还模拟异步调用,这样f1(f2),怎样实现呢?其实就是利用setTimeout来实现

 function f1(func){
setTimeout(function(){
//f1代码
func();
},0);
}
function f2(){}
f1(f2);

自己弄个例子吧

function f1(func){
setTimeout(function(){
for(var i=0;i<10000;i++){
console.log(i);
}
func();
},0);
}
function f2(){
console.log("f2");
}
f1(f2);
console.log("程序末尾");

结果:程序末尾 1 2 ...10000 f2

程序f1执行结束之后执行f2,f1执行的时候不影响后面程序的执行,所以先显示“程序末尾”,然后是1.2.3.。。。。,最后是回调函数f2的结果。

ajax和nodejs主要就是通过回调函数这样方式实现的异步调用,简单介绍一下

ajax

 var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","url", true);
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4){
if(xmlhttp.status == 200){
console.log(xmlhttp.responseXML);
}
}
}
xmlhttp.send();

nodejs

 fs.readdir(".", function (err, filenames) {
var i;
for (i = 0; i < filenames.length; i++) {
console.log(filenames[i]);
}
});

事件监听

javascript的事件驱动模式是重要的概念,代码的执行和顺序没有关系,而是与事件的何时发生有关系。javascript原生的绑定事件就是这个概念,例如

dom.onclick = function(){
console.log("click");
}

jquery就是类似这样的,都是事件绑定,这是演示,

function f2(){}
f1.on("complete",f2);
f1.trigger("complete");

订阅-发布

简单说:两种角色,订阅者和发布者,订阅者可以订阅事件,发布者发布事件消息,发布者发布消息只能通知到订阅改消息的订阅者,未订阅的不同接收到消息。专业解释:存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

自己弄个订阅-发布模式,大家看看,勿喷啊

 (function(window,undefined){
var topics = {};
var queue = {
publish : function(topic,args){
if(!topics[topic]){
return;
}
var funcs = topics[topic],
len = funcs.length;
for(var i=0;i<len;i++){
funcs[i](args);
}
return this;
},
subscribe :function(topic,func){
if(!topics[topic]){
topics[topic] = [];
}
topics[topic].push(func);
}
}
window.AllenQueue = queue;
})(window);

用法:

AllenQueue.subscribe("done",function(){console.log("done")});
AllenQueue.publish("done")

其实我觉得时间监听就是订阅发布模式,这两个应该是一样的,事件机制就是订阅发布的实例。

Promise

promise对象是CommonJS工作组提供的一种规范,用于异步编程的统一接口。promise对象通常实现一种then的方法,用来在注册状态发生改变时作为对应的回调函数。promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS Promise/A 标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler, rejectedHandler)。resolvedHandler 回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。

Jquery在1.5的版本中引入了一个新的概念叫Deferred,就是CommonJS promise A标准的一种衍生。可以在jQuery中创建$.Deferref的对象。同时也对发送ajax请求以及数据类型有了新的修改,参考JQuery API。

例子如下

 function f1(){
    var dfd = $.Deferred();
    setTimeout(function () {
      // f1的任务代码
      dfd.resolve();
    }, 500);
    return dfd.promise;
}
f1().then(f2)

这个暂时就这样,以后我们会单独详细说说这个promise的。

小结

异步调用是javascript中一个重要的部分,我们还是要好好的掌握的。

【javascript 进阶】异步调用的更多相关文章

  1. ♫【异步】短小强悍的JavaScript异步调用库

    短小强悍的JavaScript异步调用库 var queue = function(funcs, scope) { (function next() { if(funcs.length > 0) ...

  2. 用Html5/CSS3做Winform,一步一步教你搭建CefSharp开发环境(附JavaScript异步调用C#例子,及全部源代码)上

    本文为鸡毛巾原创,原文地址:http://www.cnblogs.com/jimaojin/p/7077131.html,转载请注明 CefSharp说白了就是Chromium浏览器的嵌入式核心,我们 ...

  3. JavaScript进阶之高阶函数篇

    JavaScript进阶之高阶函数篇 简介:欢迎大家来到woo爷说前端:今天给你们带来的是JavaScript进阶的知识,接下来的系列都是围绕着JavaScript进阶进行阐述:首先我们第一篇讲的是高 ...

  4. JavaScript进阶内容——BOM详解

    JavaScript进阶内容--BOM详解 在上一篇文章中我们学习了DOM,接下来让我们先通过和DOM的对比来简单了解一下BOM 首先我们先来复习一下DOM: 文档对象模型 DOM把文档当作一个对象来 ...

  5. JavaScript进阶之路——认识和使用Promise,重构你的Js代码

    一转眼,这2015年上半年就过去了,差不多一个月没有写博客了,"罪过罪过"啊~~.进入了七月份,也就意味着我们上半年苦逼的单身生活结束了,从此刻起,我们要打起十二分的精神,开始下半 ...

  6. jquery ajax异步调用

    写程序的第一步都要知其然,至于知其所以然就要看个人的爱好了.下面说一下web开发中经常用的ajax. 这里是用的jquery框架实现的ajax异步调用.废话少说先上代码.(asp.net开发) var ...

  7. [置顶] Ajax程序:处理异步调用中的异常(使用Asp.Net Ajax内建的异常处理方法)

    无论在Window应用程序,还是Web应用程序以对用户友好的方式显示运行时的异常都是很有必要,尤其对于可能有很多不确定因素导致异常的Web应用程序;在传统的Web开发中,处理异常的方式——设计专门一个 ...

  8. JavaScript 进阶(一)JS的"多线程"

    这个系列的文章名为“JavaScript 进阶”,内容涉及JS中容易忽略但是很有用的,偏JS底层的,以及复杂项目中的JS的实践.主要来源于我几年的开发过程中遇到的问题.小弟第一次写博客,写的不好的地方 ...

  9. 漫话JavaScript与异步·第二话——Promise:一诺千金

    一.难以掌控的回调 我在第一话中介绍了异步的概念.事件循环.以及JS编程中可能的3种异步情况(用户交互.I/O.定时器).在编写异步操作代码时,最直接.也是每个JSer最先接触的写法一定是回调函数(c ...

随机推荐

  1. 本地计算机 上的 OracleOraDb11g_home1TNSListener 服务启动后停止

    今天玩oracle的时候突然遇到一个问题:本地计算机 上的 OracleOraDb11g_home1TNSListener 服务启动后停止.某些服务在未由其他服务或程序使用时将自动停止. 在网上找解决 ...

  2. 长平狐 Android-x86虚拟机安装配置全攻略

    Android-x86虚拟机安装配置网上有很多,但是全部说明白的确不多,希望这篇文章能把主要的配置介绍给您,帮助您少走一些弯路. 本文分别针对VMWare和Virtual Box两种虚拟机介绍安装配置 ...

  3. Unity3D–RectTransfrom 记录笔记

    一.基本要点 部分来源:http://www.2fz1.com/post/unity-ugui-recttransform/ RectTransform继承于Trasnfrom , 在Trasnfor ...

  4. ionic 跨页面传值的几种方法

    1.使用AngularJS自带的$cacheFactory服务 $cacheFactory 从字面直译即为缓存工厂,可以用它来生成缓存对象,缓存对象以key-value的方式进行数据的存储,在整个应用 ...

  5. 出现( linker command failed with exit code 1)错误总结 (转)

    这种问题,通常出现在添加第三方库文件或者多人开发时. 这种问题一般是找不到文件而导致的链接错误. 我们可以从如下几个方面着手排查. 1.以如下错误为例,如果是多人开发,你同步完成后发现出现如下的错误. ...

  6. jenkins 使用oclint 扫描 oc 代码

    jenkins 环境的搭建,在这里不在赘述,下面我们写一写,如何接入oclint. OCLint是一个强大的静态代码分析工具,可以用来提高代码质量,查找潜在的bug,主要针对c,c++和Objecti ...

  7. textarea关于空格和换行那点事

    textarea中空格连续输入多个的情况下,数据回显的时候页面只是显示一个:换行同样有问题,在textarea中有换行,在页面上却没有,今天终于看到个写的比较具体的文章,拿过来收藏下. 地址链接: h ...

  8. Poco C++ MySQl demo

    #include "Poco/Exception.h"#include "Poco/Data/Session.h"#include "Poco/Dat ...

  9. android中加载的html获取的宽高不正确

    wap页面使用 js库是zepto,按照惯例在$(function(){})中,来获取当前可视区的宽高,但得到的宽高却与预想的相差十万八千里. 原本android手机的浏览器设定的宽高基本是360*6 ...

  10. java 三个循环的优缺点

    package cc.knms.appservice.test; import java.text.ParseException; import java.util.ArrayList; import ...