在前端页面开发的过程中,经常使用到Ajax请求,异步提交表单数据,或者异步刷新页面。

一般来说,使用Jquery中的$.ajax,$.post,$.getJSON,非常方便,但是有的时候,我们只因为需要ajax功能而引入Jquery比较不划算。

所以接下来便用原生JavaScrpit实现一个简单的Ajax请求,并说明ajax请求中的跨域访问问题,以及多个ajax请求的数据同步问题。

JavaScript实现Ajax异步请求

简单的ajax请求实现

Ajax请求的原理是创建一个XMLHttpRequest对象,使用这个对象来进行异步发送请求,具体实现参考下面代码:

  1. function ajax(option) {
  2. // 创建一个 XMLHttpRequest 对象
  3. var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"),
  4. requestData = option.data,
  5. requestUrl = option.url,
  6. requestMethod = option.method;
  7. // 如果是GET请求,需要将option中的参数拼接到URL后面
  8. if ('POST' != requestMethod && requestData) {
  9. var query_string = '';
  10. // 遍历option.data对象,构建GET查询参数
  11. for(var item in requestData) {
  12. query_string += item + '=' + requestData[item] + '&';
  13. }
  14. // 注意这儿拼接的时候,需要判断是否已经有 ?
  15. requestUrl.indexOf('?') > -1
  16. ? requestUrl = requestUrl + '&' + query_string
  17. : requestUrl = requestUrl + '?' + query_string;
  18. // GET 请求参数放在URL中,将requestData置为空
  19. requestData = null;
  20. }
  21. // ajax 请求成功之后的回调函数
  22. xhr.onreadystatechange = function () {
  23. // readyState=4表示接受响应完毕
  24. if (xhr.readyState == ("number" == typeof XMLHttpRequest.DONE ? XMLHttpRequest.DONE : 4)) {
  25. if (200 == xhr.status) { // 判断状态码
  26. var response = xhr.response || xhr.responseText || {}; // 获取返回值
  27. // if define success callback, call it, if response is string, convert it to json objcet
  28. console.log(response);
    option.success && option.success(response); // 调用成功的回调函数处理返回值
  29. // 可以判断返回数据类型,对数据进行JSON解析或者XML解析
  30. // option.success && option.success('string' == typeof response ? JSON.parse(response) : response);
  31. } else {
  32. // if define error callback, call it
  33. option.error && option.error(xhr, xhr.statusText);
  34. }
  35. }
  36. };
  37. // 发送ajax请求
  38. xhr.open(requestMethod, requestUrl, true);
  39. // 请求超时的回调
  40. xhr.ontimeout = function () {
  41. option.timeout && option.timeout(xhr, xhr.statusText);
  42. };
  43. // 定义超时时间
  44. xhr.timeout = option.timeout || 0;
  45. // 设置响应头部,这儿默认设置为json格式,可以定义为其他格式,修改头部即可
  46. xhr.setRequestHeader && xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
  47. xhr.withCredentials = (option.xhrFields || {}).withCredentials;
  48. // 这儿主要用于发送POST请求的数据
  49. xhr.send(requestData);
  50. }

上面的代码中有详细的注释,ajax的原理很简单,总的来说就是使用XMLHttpRequest对象来发送数据。这儿对这个对象进行补充说明。

代码中用了很多布尔表达式的短路特性代替条件语句的写法,善用布尔表达式的短路特性能让大量简单的条件语句简化。^_^

XMLHttpRequest对象的基本属性

readyState属性有五个状态值:

  1. 0:是uninitialized:未初始化。已经创建了XMLHttpRequest对象但是未初始化。
  2. 1:是loading:已经开始准备好要发送了。
  3. 2:是loaded,:已经发送,但是还没有收到响应。
  4. 3:是interactive:正在接受响应,但是还没接收完。
  5. 4:是completed:接受响应完毕。

responseText:服务器返回的响应文本。只有当readyState>=3的时候才有值。当readyState=3,返回的响应文本不完整,只有readyState=4,接收到完整的响应文本。 responseXML:响应信息是xml,可以解析为Dom对象。 status:服务器的Http状态码,若是200,则表示OK,404,表示为未找到。 statusText:服务器http状态码的文本。比如OK,Not Found。

XMLHttpRequest对象的基本方法

open(method,url,asyn):打开XMLHttpRequest对象。其中method方法有get,post,delete,put。url是请求资源的地址。第三个参数表示是否使用异步。默认情况是true,因为Ajax的特点就是异步传送。若使用同步则false。 send(body):发送请求Ajax。其中发送的内容可以是需要的参数,若是没有参数,直接send(null)

使用方法

直接调用上面定义的ajax函数,传送相应的选项和参数即可。

  1. ajax({
  2. url: '/post.php',
  3. data: {
  4. name: 'uusama',
  5. desc: 'smart'
  6. },
  7. method: 'GET',
  8. success: function(ret) {
  9. console.log(ret);
  10. }
  11. });

跨域请求问题

使用ajax请求的时候,一定要注意一个问题:跨域请求。 在没有使用特殊手段的情况下,跨域请求:请求其他域名和端口下的URL资源的时候,会报 Access-Control-Allow-Origin 相关的错误。其主要原因是浏览器的同源策略限制,浏览器规定不能跨域请求资源。

解决办法

下面简单的提一下一些解决方案。 在ajax头部添加允许跨域请求的header,这种方式还需要服务端配合添加允许跨域请求的头部才可以。下面是PHP添加允许POST请求跨域头部的PHP示例:

  1. // 指定允许其他域名访问
  2. header('Access-Control-Allow-Origin:*');
  3. // 响应类型
  4. header('Access-Control-Allow-Methods:POST');
  5. // 响应头设置
  6. header('Access-Control-Allow-Headers:x-requested-with,content-type');

使用动态scrpit标签,动态创建一个scrpit标签并指向请求的地址的方法,也就是JSONP方式,需要在URL后面拼接一个回调函数,标签加载成功以后会调用回调函数。

  1. var url = "http://uusama.com", callbaclName = 'jsonpCallback';
  2. script = document.createElement('script');
  3. script.type = 'text/javascript';
  4. script.src = url + (url.indexOf('?') > -1 ? '&' : '?') + 'callback=' + callbaclName;
  5. document.body.appendChild(script);

回调函数需要设置为全局函数:

  1. window['jsonpCallback'] = function jsonpCallback(ret) {}

多个ajax请求数据同步问题

单个ajax返回数据异步处理

多个ajax请求互不相关,它们在被调用以后发送各自请求,请求成功以后调用自己的回调方法,互不影响。 因为ajax请求异步的特性,所有一些依赖于请求完成之后的操作我们都需要放在回调函数内部,否则的话,你在回调函数外面读取到的值是空。看下面的例子:

  1. var result = null;
  2. ajax({
  3. url: '/get.php?id=1',
  4. method: 'GET',
  5. success: function(ret) {
  6. result = ret;
  7. }
  8. });
  9. console.log(result); // 输出 null

虽然我们在回调函数里面设置了result的值,但是在最后一行 console.log(result); 输出为空。 因为ajax请求是异步的,程序执行到最后一行的时候,请求并没有完成,值并没有来得及修改。 这儿我们应该把 console.log(result) 相关的处理,放在 success 回调函数中才可以。

多个ajax返回数据问题

如果有多个ajax请求,情况会变得有些复杂。 如果多个ajax请求是按照顺序执行的,其中一个完成之后,才能进行下一个,则可以把后面一个请求放在前一后请求的回调中。 比如有两个ajax请求,其中一个请求的数据依赖于另外一个,则可以在第一个请求的回调里面再进行ajax请求:

  1. // 首先请求第一个ajax
  2. ajax({
  3. url: '/get1.php?id=1',
  4. success: function(ret1) {
  5. // 第一个请求成功回调以后,再请求第二个
  6. if (ret1) {
  7. ajax({
  8. url: '/get2.php?id=4',
  9. success:function(ret2) {
  10. console.log(ret1);
  11. console.log(ret2)
  12. }
  13. })
  14. }
  15. }
  16. });
  17.  
  18. // 也可以写成下面的形式
  19. var ajax2 = function(ret1) {
  20. ajax({
  21. url: '/get2.php?id=4',
  22. success:function(ret2) {
  23. console.log(ret1);
  24. console.log(ret2)
  25. }
  26. });
  27. };
  28. ajax({
  29. url: '/get1.php?id=1',
  30. success: function(ret1) {
  31. if(ret1){
  32. ajax2(ret1);
  33. }
  34. }
  35. });

如果不关心不同的ajax请求的顺序,而只是关心所有请求都完成,才能进行下一步。 一种方法是可以在每个请求完成以后都调用同一个回调函数,只有次数减少到0才执行下一步。

  1. var count = 3, all_ret = []; // 调用3次
  2. ajax({
  3. url: '/get1.php?id=1',
  4. success:function(ret) {
  5. callback(ret);
  6. }
  7. });
  8. ajax({
  9. url: '/get2.php?id=1',
  10. success:function(ret) {
  11. callback(ret);
  12. }
  13. });
  14. ajax({
  15. url: '/get3.php?id=1',
  16. success:function(ret) {
  17. callback(ret);
  18. }
  19. });
  20. function callback(ret) {
  21. if (count > 0) {
  22. count--;
  23. // 可以在这儿保存 ret 到全局变量
  24. all_ret.push(ret);
  25. return;
  26. } else { // 调用三次以后
  27. // todo
  28. console.log(ret);
  29. }
  30. }

另一种方法是设置一个定时任务去轮训是否所有ajax请求都完成,需要在每个ajax的成功回调中去设置一个标志。 这儿可以用是否获得值来判断,也可以设置标签来判断,用值来判断时,要注意设置的值和初始相同的情况。

  1. var all_ret = {
  2. ret1: null, // 第一个ajax请求标识
  3. ret2: null, // 第二个ajax请求标识
  4. ret3: null, // 第三个ajax请求标识
  5. };
  6. ajax({
  7. url: '/get1.php?id=1',
  8. success:function(ret) {
  9. all_ret['ret1'] = ret; // 设置第一个ajax请求完成,把结果更新
  10. }
  11. });
  12. ajax({
  13. url: '/get2.php?id=1',
  14. success:function(ret) {
  15. all_ret['ret2'] = ret; // 设置第二个ajax请求完成,把结果更新
  16. }
  17. });
  18. ajax({
  19. url: '/get3.php?id=1',
  20. success:function(ret) {
  21. all_ret['ret3'] = ret; // 设置第三个ajax请求完成,把结果更新
  22. }
  23. });
  24. var repeat = setInterval(function(){
    // 循环检查是否所有设置的ajax请求结果的值是否都已被更改,都已被更改说明所有ajax请求都已完成
  25. for(var item in all_ret) {
  26. if (all_ret[item] === null){
  27. return;
  28. }
  29. }
  30. // todo, 到这儿所有ajax请求均已完成
  31. clearInterval(repeat);
  32. }, 50);

原文出自:http://uusama.com/377.html

JavaScrpit中异步请求Ajax实现的更多相关文章

  1. [js开源组件开发]network异步请求ajax的扩展

    network异步请求ajax的扩展 在日常的应用中,你可能直接调用$.ajax是会有些问题的,比如说用户的重复点击,比如说我只希望它成功提交一次后就不能再提交,比如说我希望有个正在提交的loadin ...

  2. 异步请求Ajax(取得json数据)

    异步请求Ajax 没有学习Ajax之前请求数据的时候都是整个页面全部刷新了一次,也就是每次请求都会重新请求所有的资源.但是在很多时候不需要页面全部刷新,仅仅是需要页面的局部数据刷新即可,此时需要发送异 ...

  3. 在内核中异步请求设备固件firmware的测试代码

    在内核中异步请求设备固件firmware的测试代码 static void ghost_load_firmware_callback(const struct firmware *fw, void * ...

  4. SpringBoot中异步请求和异步调用(看这一篇就够了)

    原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10661591.html,否则将追究法律责任!!! 一.SpringBoot中异步请求的使用 ...

  5. ASP.NET WebForm中异步请求防止XSRF攻击的方法

    在ASP.NET MVC中微软已经提供了如何防止跨域攻击的方法.对于传统Webfrom中使用Handler来接受ajax的Post请求数据,如何来防止XSRF攻击呢.这里给大家提供一个简单地方法,和M ...

  6. 异步请求Ajax

    AJAX:Asynchronous JS And XML,包括HTML.CSS.JS.DOM.XML.JSON等,客户端技术范畴.主要目标:发起异步请求/响应,实现页面内容的局部刷新,提高浏览体验:实 ...

  7. jQuery中异步请求

    1.load方法 使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: $(selector).load(URL,data,callback); ...

  8. 关于异步请求AJAX的具体解释

    1,异步请求的方法步骤: 1,推断当前用户支持的浏览器类型 XMLHttpRequest:推断是否支持非IE浏览器,相应的创建方法:xmlhttp = new XMLHttpRequest(); wi ...

  9. vue中异步请求渲染问题(swiper不轮播)(在开发过程中遇到过什么问题、踩过的坑)

    问题描述: 用vue封装一个swiper组件的时候,发现轮播图不能轮播了. 原因: 异步请求的时间远大于生命周期执行的时间,mounted初始化DOM时数据未返回,渲染数据是空数组,导致轮播图的容器层 ...

随机推荐

  1. angular directive自定义指令

    先来看一下自定义指令的写法 app.directive('', ['', function(){ // Runs during compile return { // name: '', // pri ...

  2. angularui 分页

    分页组件的使用 <!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> ...

  3. HDFS概述(4)————HDFS权限

    概述 Hadoop分布式文件系统(HDFS)的权限模型与POSIX模型的文件和目录权限模型一致.每个文件和目录与所有者和组相关联.该文件或目录将权限划分为所有者的权限,作为该组成员的其他用户的权限.以 ...

  4. Java常用异常整理

    填坑,整理下Java的常用异常.正确使用异常在实际编码中非常重要,但面试中的意义相对较小,因为对异常的理解和应用很难通过几句话或几行代码考查出来,不过我们至少应答出三点:异常类的继承关系.常用异常类. ...

  5. python GUI实战项目——tkinter库的简单实例

    一.项目说明: 本次通过实现一个小的功能模块对Python GUI进行实践学习.项目来源于软件制造工程的作业.记录在这里以复习下思路和总结编码过程.所有的源代码和文件放在这里: 链接: https:/ ...

  6. 使用SQLite做本地数据缓存的思考

    前言 在一个分布式缓存遍地都是的环境下,还讲本地缓存,感觉有点out了啊!可能大家看到标题,就没有想继续看下去的欲望了吧.但是,本地缓存的重要性也是有的! 本地缓存相比分布式缓存确实是比较out和比较 ...

  7. express简介

    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...

  8. javascript特效300例----抄书喽

    -javascript300例- #body_div { background-color: #202425; color: white; margin: 0 auto; border: 5px gr ...

  9. HDU1197 Specialized Four-Digit Numbers

    进制转化 hdu1197 #include<cstdio> #include<cstdlib> #include<iostream> #include<mem ...

  10. Java web 入门知识 及HTTP协议详解

     Java  web  入门知识 及HTTP协议详解 WEB入门 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资 ...