Ajax的原理简单来说,实际上就是通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。
我们可以看出,XMLHttpRequest对象完全用来向服务器发出一个请求的,它的作用也局限于此,但它的作用是整个ajax实现的关键,我们可以把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,可以是Html,可以是Javascript代码,也可以只是一个字符串。这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,客户端在异步获取这个结果后,不是直接显示在页面,而是先由javascript来处理,然后再显示在页面。
同步与异步
以前经常被同步和异步的区别搞混,上网查的话,上面的答案五花八门,但是自己还算是总结了一下。
我们先介绍同步,何谓同步,抛开任何技术型相关的东西,同步就是步骤的一致性,这种步骤的一致性在不同的技术中又有不同的解释,我们一一介绍,在现有的B/S架构中,就是采用了同步的方式进行的,注意我们这里只说B/S架构采用同步方式而不是说HTTP协议采用同步方式,因为http本身是基于tcp连接的,而tcp连接又是同步协议,所以HTTP本身是同步的,没有异步的http协议。这种异步方式我们可以理解为时序,也就是当从浏览器发出一个http请求,浏览器就什么也不干,就等着接受返回来的http响应,这就是同步,但是,很明显这种同步方式不利于现在的B/S架构,于是出现了AJAX技术,ajax技术本身是一种异步通信,也就是说当浏览器发出请求信号后,就无需一直等待接受整个的http返回式页面,他可以发送完后去干别的事情。但是,我们应该知道这仅仅是表面上的异步,实际上,浏览器设置了一个监听线程在不断的等待即将到来的http响应,也就是说把原本由浏览器进程做的事情交给了浏览器的某个线程。
其实,同步还有一种意思,那就是一致性,例如在分布式数据库中,也存在同步性,这种同步就是一致的意思,例如,如果存在的冗余的数据,当一个数据库系统改变后,另外一个也必须改变,这也是同步的另外一种意思。在传输当中,分为同步传输和异步传输,所谓的同步传输就是在数据链路层,采用帧的方式进行通信,把数据打包成帧格式,以数据块为单位进行传输,在数据块中加入同步信息,也就是说能够让接受端知道一个具体数据块的开始和结束。异步传输其实是为每个bit加入同步信息。
从上面的各种解释,我们可以看出所谓的异步都是基于同步的,因为自然科学的任何领域没有同步性质存在就不可能发展,任何的异步性都是一种表面性质的东西,没有同步的支持,任何的纯异步性是不存在的。说的简单一些,异步性其实就是在原来同步的基础之上抽象出来的。例如,我们写信给朋友,邮寄出去以后,我们并不需要什么也不干,整天等着。这就是可以称为通信的异步性,但是,我们是否发现,我们必须有中东西再时时刻刻替我们在等待,例如信箱,电话。这种东西本身就代表着同步,这两种东西你不能让他们去忙别的,你不能把信息放到屋里乘垃圾,用完了再放回原来的位置,因为他必须相当于一个守候线程时刻在原位置进行守候,否则就无法接受信息。通过这个例子,我们就可以很好的理解异步的本质了。
所以从某种意义上讲,任何的协议都是同步的,协议的同步性应该包括两个方面,一个就是协议所规定的通信的同步性,也就是说一方发完信息后,采用什么方案等待,是留下一个线程等候,还是直接什么都不干。另外一个就是协议内部定义的标识符所代表的含义。所以我们是否可以这样认为,同步和协议是完全对等的,同步必须通过协议完成。
1.
举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
-----------------------------------------------------------------------------------
同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。
异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。
所以,要我请你吃饭就用同步的方法,要请我吃饭就用异步的方法,这样你可以省钱。
------------------------------------------------------------------------------------
举个例子 打电话时同步 发消息是异步
2.
经常看到介绍 ArrayList 和HashMap是异步,Vector和HashTable是同步,这里同步是线程安全的,异步不是线程安全的,举例说明:
当创建一个Vector对象时候,
Vector ve=new Vector();
ve.add("1");
当在多线程程序中,第一个线程调用修改对象ve的时候,就为其上了锁,其他线程只有等待。
当创建一个ArrayList对象时候,
ArrayList list=new ArrayList();
list.add("1");
当在多线程程序中,第一个线程调用修改对象list的时候,没有为其上锁,其他线程访问时就会报错。
eg:list.remove("1"),然后再由其他线程访问list对象的1时就会报错。
3.
如果数据将在线程间共享.例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取.
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率.
Java同步:
基本概念:
每个Object都会有1个锁.
同步就是串行使用一些资源.
(说明:以下有些例子为了突出重点,省略了不必要的代码.非凡是省掉了一些成员变量,就是需要同步的对象.)
1. 多线程中对共享、可变的数据进行同步.
对于函数中的局部变量没必要进行同步.
对于不可变数据,也没必要进行同步.
多线程中访问共享可变数据才有必要.
2. 单个线程中可以使用synchronized,而且可以嵌套,但无意义.
class Test {
public static void main(String[] args) {
Test t = new Test();
synchronized(t) {
synchronized(t) {
System.out.println("ok!");
}
}
}
}
3. 对象实例的锁
class Test{
public synchronized void f1(){
//do something here
}
public void f2(){
synchronized(this){
//do something here
}
}
}
上面的f1()和f2()效果一致, synchronized取得的锁都是Test某个实列(this)的锁.
比如: Test t = new Test();
线程A调用t.f2()时, 线程B无法进入t.f1(),直到t.f2()结束.
作用: 多线程中访问Test的同一个实例的同步方法时会进行同步.
4. class的锁
class Test{
final static Object o= new Object();
public static synchronized void f1(){
//do something here
}
public static void f2(){
synchronized(Test.class){
//do something here
}
}
public static void f3(){
try {
synchronized (Class.forName("Test")) {
//do something here
}
}
catch (ClassNotFoundException ex) {
}
}
public static void g(){
synchronized(o){
//do something here
}
}
}
上面f1(),f2(),f3(),g()效果一致
f1(),f2(),f3()中synchronized取得的锁都是Test.class的锁.
g()是自己产生一个对象o,利用o的锁做同步
作用: 多线程中访问此类或此类任一个实例的同步方法时都会同步. singleton模式lazily initializing属于此类.
5. static method
class Test{
private static int v = 0;
public static void f1(){
//do something, 但函数中没用用到v
}
public synchronized static void f2(){
//do something, 函数中对v进行了读/写.
}
}
多线程中使用Test的某个实列时,
(1) f1()是线程安全的,不需要同步
(2) f2()这个静态方法中使用了函数外静态变量,所以需要同步.
Java异步:
一. 它要能适应不同类型的请求:
本节用 makeString来说明要求有返回值的请求.用displayString来说明不需要返回值的请求.
二. 要能同时并发处理多个请求,并能按一定机制调度:
本节将用一个队列来存放请求,所以只能按FIFO机制调度,你可以改用LinkedList,就可以简单实现一个优先级(优先级高的addFirst,低的addLast).
三. 有能力将调用的边界从线程扩展到机器间(RMI)
四. 分离过度耦合,如分离调用句柄(取货凭证)和真实数据的实现.分离调用和执行的过程,可以尽快地将调返回.
现在看具体的实现:
public interface Axman {
Result resultTest(int count,char c);
void noResultTest(String str);
}
这个接口有两个方法要实现,就是有返回值的调用resultTest和不需要返回值的调用
noResultTest, 我们把这个接口用一个代理类来实现,目的是将方法调用转化为对象,这样就可以将多个请求(多个方法调)放到一个容器中缓存起来,然后统一处理,因为 Java不支持方法指针,所以把方法调用转换为对象,然后在这个对象上统一执行它们的方法,不仅可以做到异步处理,而且可以将代表方法调用的请求对象序列化后通过网络传递到另一个机器上执行(RMI).这也是Java回调机制最有力的实现.
一个简单的例子.
如果 1: 做A
如果 2: 做B
如果 3: 做C
如果有1000个情况,你不至于用1000个case吧?以后再增加呢?
所以如果C/C++程序员,会这样实现: (c和c++定义结构不同)
type define struct MyStruct{
int mark;
(*fn) ();
} MyList;
然后你可以声明这个结构数据:
{1,A,
2,B
3,C
}
做一个循环:
for(i=0;i<length;i++) {
if(数据组[i].mark == 传入的值) (数据组[i].*fn)();
}
简单说c/c++中将要被调用的涵数可以被保存起来,然后去访问,调用,而Java中,我们无法将一个方法保存,除了直接调用,所以将要调用的方法用子类来实现,然后把这些子类实例保存起来,然后在这些子类的实现上调用方法:
interface My{
void test();
}
class A implements My{
public void test(){
System.out.println("A"):
}
}
class B implements My{
public void test(){
System.out.println("B"):
}
}
class C implements My{
public void test(){
System.out.println("C"):
}
}
class MyStruct {
int mark;
My m;
public MyStruct(int mark,My m){this.mark = amrk;this.m = m}
}
数组:
{ new MyStruct(1,new A()),new MyStruct(2,new B()),new MyStruct(3,new C())}
for(xxxxxxxxx) if(参数 ==数组[i].mark) 数组[i].m.test();
这样把要调用的方法转换为对象的保程不仅仅是可以对要调用的方法进行调度,而且可以把对象序列化后在另一台机器上执行,这样就把调用边界从线程扩展到了机器.
回到我们的例子:
class Proxy implements Axman{
private final Scheduler scheduler;
private final Servant servant;
public Proxy(Scheduler scheduler,Servant servant){
this.scheduler = scheduler;
this.servant = servant;
}
public Result resultTest(int count,char c){
FutureResult futrue = new FutureResult();
this.scheduler.invoke(new ResultRequest(servant,futrue,count,c));
return futrue;
}
public void noResultTest(String str){
this.scheduler.invoke(new NoResultRequest(this.servant,str));
}
}
其中scheduler是管理对调用的调度, servant是真正的对方法的执行:
Servant就是去真实地实现方法:
class Servant implements Axman{
public Result resultTest(int count,char c){
char[] buf = new char[count];
for(int i = 0;i < count;i++){
buf[i] = c;
try{
Thread.sleep(100);
}catch(Throwable t){}
}
return new RealResult(new String(buf));
}
public void noResultTest(String str){
try{
System.out.println("displayString :" + str);
Thread.sleep(10);
}catch(Throwable t){}
}
}
在scheduler 将方法的调用(invkoe)和执行(execute)进行了分离,调用就是开始"注册"方法到要执行的容器中,这样就可以立即返回出来.真正执行多久就是execute的事了,就象一个人点燃爆竹的引信就跑了,至于那个爆竹什么时候爆炸就不是他能控制的了.
public class Scheduler extends Thread {
private final ActivationQueue queue;
public Scheduler(ActivationQueue queue){
this.queue = queue;
}
public void invoke(MethodRequest request){
this.queue.putRequest(request);
}
public void run(){
while(true){
//如果队列中有请求线程,测开始执行请求
MethodRequest request = this.queue.takeRequest();
request.execute();
}
}
}
在scheduler中只用一个队列来保存代表方法和请求对象,实行简单的FIFO调用,你要实更复杂的调度就要在这里重新实现:
class ActivationQueue{
private static final int MAX_METHOD_REQUEST = 100;
private final MethodRequest[] requestQueue;
private int tail;
private int head;
private int count;
public ActivationQueue(){
this.requestQueue = new MethodRequest[MAX_METHOD_REQUEST];
this.head = this.count = this.tail = 0;
}
public synchronized void putRequest(MethodRequest request){
while(this.count >= this.requestQueue.length){
try {
this.wait();
}
catch (Throwable t) {}
}
this.requestQueue[this.tail] = request;
tail = (tail + 1)%this.requestQueue.length;
count ++ ;
this.notifyAll();
}
public synchronized MethodRequest takeRequest(){
while(this.count <= 0){
try {
this.wait();
}
catch (Throwable t) {}
}
MethodRequest request = this.requestQueue[this.head];
this.head = (this.head + 1) % this.requestQueue.length;
count --;
this.notifyAll();
return request;
}
}
为了将方法调用转化为对象,我们通过实现MethodRequest对象的execute方法来方法具体方法转换成具体对象:
abstract class MethodRequest{
protected final Servant servant;
protected final FutureResult future;
protected MethodRequest(Servant servant,FutureResult future){
this.servant = servant;
this.future = future;
}
public abstract void execute();
}
class ResultRequest extends MethodRequest{
private final int count;
private final char c;
public ResultRequest(Servant servant,FutureResult future,int count,char c){
super(servant,future);
this.count = count;
this.c = c;
}
public void execute(){
Result result = servant.resultTest(this.count,this.c);
this.future.setResult(result);
}
}
class NoResultRequest extends MethodRequest{
private String str;
public NoResultRequest(Servant servant,String str){
super(servant,null);
this.str = str;
}
public void execute(){
this.servant.noResultTest(str);
}
}
而返回的数据我们也将真实数据的获取和取货凭证逻辑分离:
package com.axman.jasync;
public abstract class Result {
public abstract Object getResult();
}
class FutureResult extends Result{
private Result result;
private boolean completed;
public synchronized void setResult(Result result){
this.result = result;
this.completed = true;
this.notifyAll();
}
public synchronized Object getResult(){
while(!this.completed){
try{
this.wait();
}catch(Throwable t){}
}
return this.result.getResult();
}
}
class RealResult extends Result{
private final Object result;
public RealResult(Object result){
this.result = result;
}
public Object getResult(){
return this.result;
}
}
OK,现在这个异步消息处理器已经有了模型,这个异步处理器中有昭雪些对象参与呢?
Servant 忠心做真实的事务
ActivationQueue将请求缓存起来以便调度
Scheduler对容器中的请求根据一定原则进行调度执行
Proxy将特定方法请求转换为特定对象
所有这些都是这个异步处理器的核心部件,虽然是核心部件,我们就要进行封装而不能随便让调用者来修改,所以我们用工厂模式(我KAO,我实在不想提模式但有时找不到其它词来表述)来产生处理器Axman对象:
package com.axman.jasync;
public class AxmanFactory {
public static Axman createAxman() {
Servant s = new Servant();
ActivationQueue queue = new ActivationQueue();
Scheduler st = new Scheduler(queue);
Proxy p = new Proxy(st,s);
st.start();
return p;
}
}
好了,我们现在用两个请求的产生者不停产生请求:
ResultInvokeThreadv 发送有返回值的请求:
package com.axman.jasync;
public class ResultInvokeThread extends Thread{
private final Axman ao;
private final char c;
public ResultInvokeThread(String name,Axman ao){
this.ao = ao;
this.c = name.charAt(0);
}
public void run(){
try{
int i = 0;
while(true){
Result result = this.ao.resultTest(i++,c);
Thread.sleep(10);
String = (String)result.getResult();
System.out.println(Thread.currentThread().getName() + " = " + );
}
}
catch(Throwable t){}
}
}
NoResultInvokeThread发送无返回值的请求:
package com.axman.jasync;
public class NoResultInvokeThread extends Thread{
private final Axman ao;
public NoResultInvokeThread(String name,Axman ao){
super(name);
this.ao = ao;
}
public void run(){
try{
int i = 0;
while(true){
String s = Thread.currentThread().getName() + i++;
ao.noResultTest(s);
Thread.sleep(20);
}
}
catch(Throwable t){}
}
}
对了,我们还需要一个什么东西来产生一个演示:
package com.axman.jasync;
public class Program {
public static void main(String[] args) {
Axman ao = AxmanFactory.createAxman();
new ResultInvokeThread("Axman",ao).start();
new ResultInvokeThread("Sager",ao).start();
new NoResultInvokeThread("Macke",ao).start();
}
}
看看结果吧.你可以把不同类型的请求不断地向处理器发送,处理器会不断地接收请求,放到队列中,并同时不断从队列中提出请求进行处理.
*****************************************************************************
引言
时代在进步我们也要跟着往前跑啊,以前的文章大部分都是在论述C/S很重要,而且对于程序员来说C/S是基础,但是在如今信息革命时代,网络大行其道只懂C/S是远远不够的,还要精通B/S,接下来的文章就要开始论述B/S技术了。那就从AJAX开始吧。
一、B/S+AJAX
1.1 B/S综述
对于HTML、XML、CSS、Javascript应该都不陌生,它们都是B/S的编程语言,在开发浏览器应用程序时这几种语言必不可少,CSS的出现使得我们的网页布局独立于网页本身,能更方便的开发网页UI。对于Javascript它是一种动态的网页脚本语言,提供了更好的动态网页程序的开发,能够制作出很漂亮的网页效果,另外它的处理是在Browser端减少了Browser和服务器的交互,这也是它优于asp.net的地方。
Note:有关HTML和XML的内容请查看笔者的前篇博客。上面系统了解了B/S应用程序中的几种编程语言,但对于AJAX却没有说明。可能对于没有接触过AJAX的童鞋来说,它可能是一种很困难、很尖端的技术(至少对于以前的我来说是这样的),但通过了解后发现AJAX很简单,因为它基本上类似于JQuery是一种Web应用程序的技术。
1.2 AJAX概述
AJAX= 异步 JavaScript 及 XMLAJAX 全称是Asynchronous JavaScript And XML,它是指异步 JavaScript 及 XML,它不是一种新的编程语言,而是一种创建更好更快、交互性更强的Web技术。使用XMLHttpRequest对象来直接与服务器进行通信,使得JavaScript可在不重载页面的情况下与 Web 服务器交换数据。
表1 AJAX的应用情况
应 用 情 况 | 说 明 |
基于表单的简单用户交互 | 如用户注册验证、数据格式验证等。如果采取整页回发(PostBack)到服务器做法,不仅传输数据量大、服务器负担重、响应时间长,而且会导致用户体验很差。在验证结束后,由于某些数据错误返回注册页面时,先前输入的数据都已不存在了,必须重新填写。而采用Ajax技术后,这些任务在用户填写其他信息时,已有XMLHTTPRequest对象异步完成,极大地改善用户操作体验 |
时时更新的页面信息 | 如聊天室信息、在线统计、股票的涨跌等。这类系统都需要实时地反映数据的变化。采用Ajax技术能定时异步访问服务器,可以获得最新信息并将其显示给用户,而且可以避免整个页面的刷新 |
菜单导航 | 如多级联动菜单、树状导航等。可以采用Ajax技术来实现按需读取数据的功能,这可以避免每次变动都需要整页回发(PostBack)到服务器,从而节省带宽资源,提高响应速度,也减少显示所有数据时所要消耗的带宽资源 |
评论、选择投票 | 这几种情况传输的数据量非常小,因而没有必要将整个页面回发(PostBack)到服务器。采用Ajax技术,用户在执行完相关操作后,将异步与服务器进行自动交互,而用户同时可以继续执行其他操作 |
二、AJAX运行机制
图2 Ajax Web应用程序的模型
(1)用户在Web页面上执行了某个操作,如单击某个链接,或进行某项选择等。
(2)根据用户的操作,页面产生相应的DHTML事件。
(3)调用注册到该DHTML事件的客户端JavaScript事件处理函数。其中需要创建并初始化一个用以向服务器发送异步请求的XMLHttpRequest对象,同时指定一个回调函数。当服务器端的响应返回时,将自动调用该回调函数。
(4)服务器收到XMLHttpRequest对象的请求之后,根据请求进行一系列的处理。
(5)处理完毕,服务器端向客户端返回所需要的数据。
(6)数据到达客户端之后,执行JavaScript回调函数,并根据返回的数据对用户显示界面进行更新。
(7)用户获得自己操作所需的数据,即为看到显示界面的变化。
三、XMLHttpRequest对象
XMLHttpRequest 对象,使得web 开发者可以做到在页面已加载后从服务器更新页面!
XMLHttpRequest 对象,是AJAX的重点,它封装了DOM对象的基本操作方法和属性,另外不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的,对于IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 JavaScript 内建对象。所以在使用AJAX时首先必须要做的是判断浏览器的类型,代码如下:
- <html>
- <head>
- <title>AJAX的多浏览器支持示例</title>
- </head>
- <body>
- <script type="text/javascript">
- //验证浏览器的类型,根据浏览器的类型创建XMLHttpRequest对象
- function ajaxFunction(){
- var xmlHttp;
- //******************************************************************************
- //方法一:使用try-catch的方法判断是否支持AJAX
- try{
- xmlHttp=new XMLHttpRequest();
- }catch(e){
- try{
- xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
- }catch(e){
- try{
- xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
- }catch(e){
- alert("您的浏览器不支持AJAX!");
- return false;
- }
- }
- }
- //******************************************************************************
- //******************************************************************************
- //方法二:使用if-else的方法判断是否支持AJAX
- if(window.ActiveXObject){
- //IE浏览器
- }if (window.ActiveXObject) {
- //针对IE6,IE5.5,IE5
- //两个可以用于创建XMLHTTPRequest对象的控件名称,保存在一个js的数组中
- //排在前面的版本较新
- var activexName = ["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
- for (var i = 0; i < activexName.length; i++) {
- try{
- //取出一个控件名进行创建,如果创建成功就终止循环
- //如果创建失败,回抛出异常,然后可以继续循环,继续尝试创建
- xmlhttp = new ActiveXObject(activexName[i]);
- break;
- } catch(e){
- }
- }
- }
- //******************************************************************************
- }
- </script>
- </body>
- </html>
XMLHttpRequest使用的基本步骤:
(1)建立XMLHttpRequest对象(2)注册回调函数
(3)使用open方法设置和服务器端交互的基本信息
(4)设置发送的数据,开始和服务器端交互
(5)在回调函数中判断交互是否结束,相应是否正确,并根据需要获取服务器端返回的数据,更新页面代码。
- //用户名校验的方法
- //这个方法将使用XMLHTTPRequest对象来进行AJAX的异步数据交互
- var xmlhttp;
- function verify() {
- //0。使用dom的方式获取文本框中的值
- //document.getElementById("userName")是dom中获取元素节点的一种方法,一个元素节点对应HTML页面中的一个标签,如果<input>
- //。value可以获取一个元素节点的value属性值
- var userName = document.getElementById("userName").value;
- //1.创建XMLHttpRequest对象
- //这是XMLHttpReuquest对象五部使用中最复杂的一步
- //需要针对IE和其他类型的浏览器建立这个对象的不同方式写不同的代码
- if (window.XMLHttpRequest) {
- //针对FireFox,Mozillar,Opera,Safari,IE7,IE8
- xmlhttp = new XMLHttpRequest();
- //针对某些特定版本的mozillar浏览器的BUG进行修正
- if (xmlhttp.overrideMimeType) {
- xmlhttp.overrideMimeType("text/xml");
- }
- } else if (window.ActiveXObject) {
- //针对IE6,IE5.5,IE5
- //两个可以用于创建XMLHTTPRequest对象的控件名称,保存在一个js的数组中
- //排在前面的版本较新
- var activexName = ["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
- for (var i = 0; i < activexName.length; i++) {
- try{
- //取出一个控件名进行创建,如果创建成功就终止循环
- //如果创建失败,回抛出异常,然后可以继续循环,继续尝试创建
- xmlhttp = new ActiveXObject(activexName[i]);
- break;
- } catch(e){
- }
- }
- }
- //确认XMLHTtpRequest对象创建成功
- if (!xmlhttp) {
- alert("XMLHttpRequest对象创建失败!!");
- return;
- } else {
- alert(xmlhttp.readyState);
- }
- //2.注册回调函数
- //注册回调函数时,只需要函数名,不要加括号
- //我们需要将函数名注册,如果加上括号,就会把函数的返回值注册上,这是错误的
- xmlhttp.onreadystatechange = callback;
- //3。设置连接信息
- //第一个参数表示http的请求方式,支持所有http的请求方式,主要使用get和post
- //第二个参数表示请求的url地址,get方式请求的参数也在url中
- //第三个参数表示采用异步还是同步方式交互,true表示异步
- xmlhttp.open("GET",url,true);
- //POST方式请求的代码
- //xmlhttp.open("POST","AJAXServer",true);
- //POST方式需要自己设置http的请求头
- //xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
- //POST方式发送数据
- //xmlhttp.send("name=" + userName);
- //4.发送数据,开始和服务器端进行交互
- //同步方式下,send这句话会在服务器段数据回来后才执行完
- //异步方式下,send这句话会立即完成执行
- xmlhttp.send(null);
- }
- //回调函数
- function callback() {
- //alert(xmlhttp.readyState);
- //5。接收响应数据
- //判断对象的状态是交互完成
- if (xmlhttp.readyState == 4) {
- //判断http的交互是否成功
- if (xmlhttp.status == 200) {
- //获取服务漆器端返回的数据
- //获取服务器段输出的纯文本数据
- var responseText = xmlhttp.responseText;
- //将数据显示在页面上
- //通过dom的方式找到div标签所对应的元素节点
- var divNode = document.getElementById("result");
- //设置元素节点中的html内容
- divNode.innerHTML = responseText;
- } else {
- alert("出错了!!!");
- }
- }
- }
上面的代码示例演示类XMLHttpRequest在使用过程中需要执行的五个步骤,其中最困难的是XMLhttpRequest的创建,不同的浏览器在创建该对象时会有所差异,另外还有设置连接信息,有GET和POST两种方式,两种创建方式有很大的区别。有关XMLHttpRequest的API说明请下载:XMLHttpRequest方法和属性API。
三、Ajax示例
编写了一个注册的案例,使用的是Ajax进行用户信息的验证。该案例通过对会员昵称(用户名)进行验证,即根据该用户名是否已经被使用,在不进行页面刷新的情况下给出相应的提示信息。如下图为注册页面的UI界面:
完整的代码示例请下载:AJAX登陆示例。
会员注册页面:Default.aspx,使用的是基本的HTML控件,在昵称后面放置了一个<span>标签用来提示用户输入的信息是否合法,其中交互过程使用的是AJAX来实现。
- <form id="form1" runat="server">
- <script language="javascript" src="Scripts/tool.js"></script>
- <div>
- <h2>会员注册</h2>
- </div>
- <div>
- <asp:Panel ID="Panel1" runat="server">
- <div>
- 完成下面的注册,即可成为我们的会员
- </div>
- </asp:Panel>
- <div>
- 昵 称:<input id="iUserName" type="text" onblur="userCheck()" style=" height:20px; width:200px;"/>
- <span id="showmsgform"></span><br />
- 邮 箱:<input id="Text1" type="text" style=" height:20px; width:200px;"/>
- <br />
- 密 码:<input id="Text2" type="text" style=" height:20px; width:200px;"/>
- <br />
- <input id="btnSubmit" type="submit" value="确 定" />
- <input id="btnCancel" type="submit" value="取 消" />
- </div>
- </div>
- </form>
Tool.js,内部Ajax代码的执行过程。userCheck方法用来验证数据用户的用户名,如果不为空将调用AJAX代码向checkUserName.aspx页面传递用户名参数,并在checkUserName.aspx查询数据库中的用户名来验证输入的用户名是否正确。
- //检查用户是否存在
- function userCheck() {
- //获取用户输入的用户名
- var username = document.getElementById("iUserName").value;
- //判断用户名是否输入,如果用户名为空将显示提示语句
- if (username == "") {
- //显示提示语句
- document.getElementById("showmsgform").innerHTML = "<font color='Red'>会员昵称不能为空</font>";
- //用户名框重新获得焦点
- document.getElementById("iUserName").focus();
- return false;
- } else {
- send_request('checkUserName.aspx?username=' + username + '&r=' + Math.random());
- }
- }
- //向服务器发送请求函数
- var http_request = false;
- function send_request(url) {
- //初始化,指定处理函数,发送请求的函数
- http_request = false;
- //开始初始化XMLHttpRequest对象
- if (window.XMLHttpRequest) {
- //非IE浏览器
- http_request = new XMLHttpRequest();
- } else if (window.ActiveXObject) {
- //IE浏览器
- try{
- http_request=new ActiveXObject("Msxml2.XMLHTTP");
- } catch (e) {
- try
- {
- http_request = new ActiveXObject("Microsoft.XMLHTTP");
- }
- catch (e) {}
- }
- }
- //判断http_request是否创建成功
- if (!http_request) {
- alert("该浏览器不支持AJAX!");
- return false;
- }
- //注册回调函数
- http_request.onreadystatechange = processRequest;
- //设置连接信息
- //第一个参数表示http的请求方式,支持所有http的请求方式,主要使用get和post
- //第二个参数表示请求的url地址,get方式请求的参数也在url中
- //第三个参数表示采用异步还是同步方式交互,true表示异步
- http_request.open("GET", url, true);
- //发送数据,开始和服务器端进行交互
- http_request.send(null);
- }
- //处理返回信息的函数processRequest()
- function processRequest() {
- if (http_request.readyState==4) {
- // 判断对象状态
- if (http_request.status == 200) {
- // 信息已经成功返回,开始处理信息
- var str = http_request.responseText;
- showMsg(str);
- }
- else {
- //页面不正常
- alert("您所请求的页面有异常.");
- }
- }
- }
- //根据返回结果,显示信息
- function showMsg(str)
- {
- if(str == "1")
- {
- document.getElementById("showmsgform").innerHTML = " <font color='Red'>昵称可以使用!</font> ";
- }
- else if(str == "2")
- {
- document.getElementById("showmsgform").innerHTML = "<font color='Red'>会员昵称已存在!</font>";
- }
- else if(str == "3")
- {
- document.getElementById("showmsgform").innerHTML = "<font color='Red'>会员昵称不能为空!</font>";
- }
- }
结语
有关AJAX基础部分的内容已经讨论完成,从B/S到AJAX再到AJAX运行机制的解析,系统的了解了B/S架构的内容以及AJAX技术的便利性。其次对XMLHttpRequest对象进行了大致的应用解析,该对象是AJAX应用的基础,封装了页面的基本信息,最后通过示例来加深联系。说到这里有关AJAX的内容还没有完结,下篇博客让我们来看看AJAX是如何操作DOM对象的。