侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

简单介绍不用库(框架)自己写ajax

技术  /  管理员 发布于 8年前   248

平常会使用ajax来请求数据,加载一个库(框架),或许仅仅maybe就使用了它的ajax部分。

  写个ajax,一来可以经历一下处理问题的过程,提升技术能力,二来工作中有时真的用不着这么大的一个库(框架),用自己写的,何乐不为呢。

  先来看看流行的jQuery是怎样调用ajax的

$.ajax({  url:    'test.php',   //发送请求的URL字符串  type:    'GET',     //发送方式   dataType:  'json',     //预期服务器返回的数据类型 xml, html, text, json, jsonp, script  data:    'k=v&k=v',   //发送的数据   async:   true,      //异步请求   cache:   false,     //缓存   timeout:  5000,      //超时时间 毫秒  beforeSend: function(){},  //请求之前  error:   function(){},  //请求出错时  success:  function(){},  //请求成功时  complete:  function(){}  //请求完成之后(不论成功或失败)});

   这样的调用是不是很舒适、方便,如果感觉舒适那自己动手写也参照这种设计方式,不用太复杂,满足所需就好。

  先了解ajax的基础知识

  XMLHttpRequest 对象

  XMLHttpRequest对象是ajax的核心,通过XMLHttpRequest对象来向服务器发异步请求,从服务器获得数据,所有现代浏览器(IE7+、Firefox、Chrome、Safari、Opera)均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。  

  创建一个兼容的XMLHttpRequest对象

var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');

   向服务器发送请求

xhr.open(method,url,async);
    //method:请求的类型;GET 或 POST
    //url:请求的URL
    //async:true(异步)或 false(同步)
xhr.send(string);
    //将请求发送到服务器
    //string:仅用于 POST 请求
//GET 比 POST 请求方式更简单也更快,并且在大部分情况下都能用
//在以下情况中,请使用 POST 请求:
    //无法使用缓存文件(更新服务器上的文件或数据库)
    //向服务器发送大量数据(POST 没有数据量限制)
    //发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

  服务器响应

  使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性获得来自服务器的响应。

    如果来自服务器的响应是 XML,而且需要作为 XML 对象进行解析,请使用 responseXML 属性。

    如果来自服务器的响应并非 XML,请使用 responseText 属性,responseText 属性返回字符串形式的响应。

  onreadystatechange 事件

  当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState 属性存有 XMLHttpRequest 的状态信息。

   XMLHttpRequest 对象的三个重要的属性:

    onreadystatechange  //存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数

    readyState  //存有 XMLHttpRequest 的状态, 从 0 到 4 发生变化     

0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪

    status  //200: "OK", 404: 未找到页面

  在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务, 当 readyState等于4 且 status为200 时,表示响应已就绪。

xhr.onreadystatechange = function(){  if( xhr.readyState == 4 && xhr.status == 200 ){    //准备就绪 可以处理返回的 xhr.responseText 或者 xhr.responseXML   }};

   一个简单的ajax请求如下:

var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');xhr.onreadystatechange = function(){  if( xhr.readyState == 4 && xhr.status == 200 ){    //准备就绪 可以处理返回的 xhr.responseText 或者 xhr.responseXML   }};xhr.open(method,url,async);xhr.send(string);

   补充:1. 发送GET请求时可能得到的是缓存的结果,为了避免这种情况,可以向URL 添加一个唯一的 ID,时间戳。2. 如果需要像HTML表单那样 POST 数据,使用 setRequestHeader() 来添加 HTTP 头。然后在 send() 方法中发送数据。

url += (url.indexOf('?') < 0 ? '?' : '&') + '_='+ (+new Date());xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

  开始写自己的ajax

  先写一个基本的,定义好各种参数选项,供参考

var $ = (function(){  //辅助函数 序列化参数   function param(data){    //..    }   function ajax(opts){    var _opts = {      url    : '/',       //发送请求URL地址      type    : 'GET',      //发送请求的方式 GET(默认), POST      dataType  : '',        //预期服务器返回的数据类型 xml, html, text, json, jsonp, script      data    : null,       //发送的数据 'key=value&key=value', {key:value,key:value}        async   : true,       //异步请求 ture(默认异步), false      cache   : true,       //缓存 ture(默认缓存), false       timeout  : 5,        //超时时间 默认5秒      load    : function(){},   //请求加载中      error   : function(){},   //请求出错时      success  : function(){},   //请求成功时      complete  : function(){}   //请求完成之后(不论成功或失败)    }, aborted = false, key,    xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');    for(key in opts) _opts[key] = opts[key];                 /*    if(_opts.dataType.toLowerCase() === 'script'){      //..    }    if(_opts.dataType.toLowerCase() === 'jsonp'){      //..    }    */    if(_opts.type.toUpperCase() === 'GET'){      if(param(_opts.data) !== ''){        _opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + param(_opts.data);      }      !_opts.cache && ( _opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + '_='+(+new Date()) );    }     function checkTimeout(){      if(xhr.readyState !== 4){        aborted = true;        xhr.abort();      }    }    setTimeout(checkTimeout, _opts.timeout*1000);         xhr.onreadystatechange = function(){      if( xhr.readyState !== 4 ) _opts.load && _opts.load(xhr);      if( xhr.readyState === 4 ){        var s = xhr.status, xhrdata;        if( !aborted && ((s >= 200 && s < 300) || s === 304) ){          switch(_opts.dataType.toLowerCase()){            case 'xml':              xhrdata = xhr.responseXML;            break;            case 'json':              xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')');            break;            default:              xhrdata = xhr.responseText;          }          _opts.success && _opts.success(xhrdata,xhr);        }else{          _opts.error && _opts.error(xhr);        }        _opts.complete && _opts.complete(xhr);      }    };       xhr.open(_opts.type,_opts.url,_opts.async);    if(_opts.type.toUpperCase() === 'POST'){      xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');    }    xhr.send(_opts.type.toUpperCase() === 'GET' ? null : param(_opts.data));  }  return {    ajax: ajax  }})();

   定义好了参数选项,来分析一下。其中 dataType 是整个ajax的重点,代码的简单或者复杂都在它了。

  在这里dataType为预期服务器返回的数据类型:xml, html, text, json, jsonp, script

  1. 为xml时,来自服务器的响应是XML,使用 responseXML 属性获取返回的数据

  2. 为html、text、json时,使用 responseText 属性获取返回的数据

      a. 为html时,返回纯文本HTML信息,其中包含的script标签是否要在插入dom时执行 ( 代码复杂度+3 )

      b. 为json时,  返回JSON数据,要安全、要便捷、要兼容  ( 代码复杂度+2 )

  3. 为jsonp时,一般跨域才用它,不用原来的ajax请求了,用创建script法( 代码复杂度+2 )

  4. 为script时:  要跨域时,不用原来的ajax请求了,用创建script法( 代码复杂度+1 ); 不跨域,返回纯文本JavaScript代码, 使用 responseText 属性获取返回的数据 ( 代码复杂度+1 )

  其中,在html片段中的script标签、jsonp、script,都要用到创建script标签的方式。

  处理dataType为json

xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')');

  这是最简单的处理方式了,要JSON兼容,可以用json2.js。

  处理dataType为jsonp

  jsonp是要通过script标签来请求跨域的,先了解下流程:

  这上图中 a.html中请求了 http://www.b.com/b.php?callback=add  (在ajax程序中请求url就是这个链接),在b.php中读取了传过来的参数 callback=add  根据获取到的参数值(值为add),以JS语法生成了函数名,并把json数据作为参数传入了这个函数,返回以JS语法生成的文档给a.html,a.html解析并执行返回的JS文档,调用了定义好的add函数。

   在程序中一般采用更通用的方式去调用,比如下面这个广泛使用的loadJS函数:

function loadJS(url, callback) {  var doc = document, script = doc.createElement('script'), body = doc.getElementsByTagName('body')[0];  script.type = 'text/javascript';  if (script.readyState) {     script.onreadystatechange = function() {      if (script.readyState == 'loaded' || script.readyState == 'complete') {        script.onreadystatechange = null;        callback && callback();      }    };  } else {     script.onload = function() {      callback && callback();    };  }  script.src = url;  body.appendChild(script);}

  这样把请求的url,传入loadJS函数,得到一样的结果。

复制代码 代码如下:

loadJS('http://www.b.com/b.php?callback=add');

  因为是动态创建script,请求成功返回,JS代码就立即执行,如果请求失败是没有任何提示的。因此自定义的参数选项: _opts.success 能调用,_opts.error不能调用。

  ajax处理jsonp也有两种情况:

  1. 设置了请求URL后的参数 callback=add 特别是定义了函数名add,请求成功返回,JS代码就立即执行(这里就是调用 add({"a":8,"b":2})  )

  2. 在_opts.success中处理JSON数据,就是请求成功返回,JS代码不执行,并把函数中的参数挪出来,作为_opts.success的参数返回( 这里相当于处理字符串 'add({"a":8,"b":2})' ,去掉 'add(' 和 ‘)',得到 {"a":8,"b":2} )

  处理dataType为html

   如果不处理HTML片段中script标签,直接把responseText返回值插入DOM树就可以了。如果要处理script,就要把HTML片段中的script标签找出来,对买个script单独处理,并注意是script标签中包含的JS代码还是通过src请求的。

  处理dataType为script

  如果要跨域时,用创建script的方式,和处理jsonp类似; 不跨域,使用 responseText 属性获取返回的数据,可以用 eval 来让代码执行,也可以创建script来执行。

function addJS(text) {  var doc = document, script = doc.createElement('script'), head = doc.getElementsByTagName('body')[0];  script.type = 'text/javascript';  script.text = text;  body.appendChild(script);}

  到此ajax差不多分析完了,根据实际需要,添加各种功能,去思考每种功能是怎样实现的,并能找到解决方法。

以上内容就是小编跟大家分享的不用库(框架)自己写ajax,希望大家喜欢。


  • 上一条:
    JQuery中$.ajax()方法参数详解
    下一条:
    如何解决Ajax访问不断变化的session的值不一致以及HTTP协议中的GET、POST的区别
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 2024.07.09日OpenAI将终止对中国等国家和地区API服务(0个评论)
    • 2024/6/9最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(1个评论)
    • 国外服务器实现api.openai.com反代nginx配置(0个评论)
    • 2024/4/28最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(1个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2017-09
    • 2018-01
    • 2018-07
    • 2018-08
    • 2018-09
    • 2018-12
    • 2019-01
    • 2019-02
    • 2019-03
    • 2019-04
    • 2019-05
    • 2019-06
    • 2019-07
    • 2019-08
    • 2019-09
    • 2019-10
    • 2019-11
    • 2019-12
    • 2020-01
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-12
    • 2024-02
    • 2024-04
    • 2024-05
    • 2024-06
    • 2025-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客