JavaScrpit中异步请求Ajax实现
在前端页面开发的过程中,经常使用到Ajax请求,异步提交表单数据,或者异步刷新页面。
一般来说,使用Jquery中的$.ajax,$.post,$.getJSON,非常方便,但是有的时候,我们只因为需要ajax功能而引入Jquery比较不划算。
所以接下来便用原生JavaScrpit实现一个简单的Ajax请求,并说明ajax请求中的跨域访问问题,以及多个ajax请求的数据同步问题。
JavaScript实现Ajax异步请求
简单的ajax请求实现
Ajax请求的原理是创建一个XMLHttpRequest对象,使用这个对象来进行异步发送请求,具体实现参考下面代码:
- function ajax(option) {
- // 创建一个 XMLHttpRequest 对象
- var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"),
- requestData = option.data,
- requestUrl = option.url,
- requestMethod = option.method;
- // 如果是GET请求,需要将option中的参数拼接到URL后面
- if ('POST' != requestMethod && requestData) {
- var query_string = '';
- // 遍历option.data对象,构建GET查询参数
- for(var item in requestData) {
- query_string += item + '=' + requestData[item] + '&';
- }
- // 注意这儿拼接的时候,需要判断是否已经有 ?
- requestUrl.indexOf('?') > -1
- ? requestUrl = requestUrl + '&' + query_string
- : requestUrl = requestUrl + '?' + query_string;
- // GET 请求参数放在URL中,将requestData置为空
- requestData = null;
- }
- // ajax 请求成功之后的回调函数
- xhr.onreadystatechange = function () {
- // readyState=4表示接受响应完毕
- if (xhr.readyState == ("number" == typeof XMLHttpRequest.DONE ? XMLHttpRequest.DONE : 4)) {
- if (200 == xhr.status) { // 判断状态码
- var response = xhr.response || xhr.responseText || {}; // 获取返回值
- // if define success callback, call it, if response is string, convert it to json objcet
- console.log(response);
option.success && option.success(response); // 调用成功的回调函数处理返回值- // 可以判断返回数据类型,对数据进行JSON解析或者XML解析
- // option.success && option.success('string' == typeof response ? JSON.parse(response) : response);
- } else {
- // if define error callback, call it
- option.error && option.error(xhr, xhr.statusText);
- }
- }
- };
- // 发送ajax请求
- xhr.open(requestMethod, requestUrl, true);
- // 请求超时的回调
- xhr.ontimeout = function () {
- option.timeout && option.timeout(xhr, xhr.statusText);
- };
- // 定义超时时间
- xhr.timeout = option.timeout || 0;
- // 设置响应头部,这儿默认设置为json格式,可以定义为其他格式,修改头部即可
- xhr.setRequestHeader && xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
- xhr.withCredentials = (option.xhrFields || {}).withCredentials;
- // 这儿主要用于发送POST请求的数据
- xhr.send(requestData);
- }
上面的代码中有详细的注释,ajax的原理很简单,总的来说就是使用XMLHttpRequest对象来发送数据。这儿对这个对象进行补充说明。
代码中用了很多布尔表达式的短路特性代替条件语句的写法,善用布尔表达式的短路特性能让大量简单的条件语句简化。^_^
XMLHttpRequest对象的基本属性
readyState属性有五个状态值:
- 0:是uninitialized:未初始化。已经创建了XMLHttpRequest对象但是未初始化。
- 1:是loading:已经开始准备好要发送了。
- 2:是loaded,:已经发送,但是还没有收到响应。
- 3:是interactive:正在接受响应,但是还没接收完。
- 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函数,传送相应的选项和参数即可。
- ajax({
- url: '/post.php',
- data: {
- name: 'uusama',
- desc: 'smart'
- },
- method: 'GET',
- success: function(ret) {
- console.log(ret);
- }
- });
跨域请求问题
使用ajax请求的时候,一定要注意一个问题:跨域请求。 在没有使用特殊手段的情况下,跨域请求:请求其他域名和端口下的URL资源的时候,会报 Access-Control-Allow-Origin 相关的错误。其主要原因是浏览器的同源策略限制,浏览器规定不能跨域请求资源。
解决办法
下面简单的提一下一些解决方案。 在ajax头部添加允许跨域请求的header,这种方式还需要服务端配合添加允许跨域请求的头部才可以。下面是PHP添加允许POST请求跨域头部的PHP示例:
- // 指定允许其他域名访问
- header('Access-Control-Allow-Origin:*');
- // 响应类型
- header('Access-Control-Allow-Methods:POST');
- // 响应头设置
- header('Access-Control-Allow-Headers:x-requested-with,content-type');
使用动态scrpit标签,动态创建一个scrpit标签并指向请求的地址的方法,也就是JSONP方式,需要在URL后面拼接一个回调函数,标签加载成功以后会调用回调函数。
- var url = "http://uusama.com", callbaclName = 'jsonpCallback';
- script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = url + (url.indexOf('?') > -1 ? '&' : '?') + 'callback=' + callbaclName;
- document.body.appendChild(script);
回调函数需要设置为全局函数:
- window['jsonpCallback'] = function jsonpCallback(ret) {}
多个ajax请求数据同步问题
单个ajax返回数据异步处理
多个ajax请求互不相关,它们在被调用以后发送各自请求,请求成功以后调用自己的回调方法,互不影响。 因为ajax请求异步的特性,所有一些依赖于请求完成之后的操作我们都需要放在回调函数内部,否则的话,你在回调函数外面读取到的值是空。看下面的例子:
- var result = null;
- ajax({
- url: '/get.php?id=1',
- method: 'GET',
- success: function(ret) {
- result = ret;
- }
- });
- console.log(result); // 输出 null
虽然我们在回调函数里面设置了result的值,但是在最后一行 console.log(result); 输出为空。 因为ajax请求是异步的,程序执行到最后一行的时候,请求并没有完成,值并没有来得及修改。 这儿我们应该把 console.log(result) 相关的处理,放在 success 回调函数中才可以。
多个ajax返回数据问题
如果有多个ajax请求,情况会变得有些复杂。 如果多个ajax请求是按照顺序执行的,其中一个完成之后,才能进行下一个,则可以把后面一个请求放在前一后请求的回调中。 比如有两个ajax请求,其中一个请求的数据依赖于另外一个,则可以在第一个请求的回调里面再进行ajax请求:
- // 首先请求第一个ajax
- ajax({
- url: '/get1.php?id=1',
- success: function(ret1) {
- // 第一个请求成功回调以后,再请求第二个
- if (ret1) {
- ajax({
- url: '/get2.php?id=4',
- success:function(ret2) {
- console.log(ret1);
- console.log(ret2)
- }
- })
- }
- }
- });
- // 也可以写成下面的形式
- var ajax2 = function(ret1) {
- ajax({
- url: '/get2.php?id=4',
- success:function(ret2) {
- console.log(ret1);
- console.log(ret2)
- }
- });
- };
- ajax({
- url: '/get1.php?id=1',
- success: function(ret1) {
- if(ret1){
- ajax2(ret1);
- }
- }
- });
如果不关心不同的ajax请求的顺序,而只是关心所有请求都完成,才能进行下一步。 一种方法是可以在每个请求完成以后都调用同一个回调函数,只有次数减少到0才执行下一步。
- var count = 3, all_ret = []; // 调用3次
- ajax({
- url: '/get1.php?id=1',
- success:function(ret) {
- callback(ret);
- }
- });
- ajax({
- url: '/get2.php?id=1',
- success:function(ret) {
- callback(ret);
- }
- });
- ajax({
- url: '/get3.php?id=1',
- success:function(ret) {
- callback(ret);
- }
- });
- function callback(ret) {
- if (count > 0) {
- count--;
- // 可以在这儿保存 ret 到全局变量
- all_ret.push(ret);
- return;
- } else { // 调用三次以后
- // todo
- console.log(ret);
- }
- }
另一种方法是设置一个定时任务去轮训是否所有ajax请求都完成,需要在每个ajax的成功回调中去设置一个标志。 这儿可以用是否获得值来判断,也可以设置标签来判断,用值来判断时,要注意设置的值和初始相同的情况。
- var all_ret = {
- ret1: null, // 第一个ajax请求标识
- ret2: null, // 第二个ajax请求标识
- ret3: null, // 第三个ajax请求标识
- };
- ajax({
- url: '/get1.php?id=1',
- success:function(ret) {
- all_ret['ret1'] = ret; // 设置第一个ajax请求完成,把结果更新
- }
- });
- ajax({
- url: '/get2.php?id=1',
- success:function(ret) {
- all_ret['ret2'] = ret; // 设置第二个ajax请求完成,把结果更新
- }
- });
- ajax({
- url: '/get3.php?id=1',
- success:function(ret) {
- all_ret['ret3'] = ret; // 设置第三个ajax请求完成,把结果更新
- }
- });
- var repeat = setInterval(function(){
// 循环检查是否所有设置的ajax请求结果的值是否都已被更改,都已被更改说明所有ajax请求都已完成- for(var item in all_ret) {
- if (all_ret[item] === null){
- return;
- }
- }
- // todo, 到这儿所有ajax请求均已完成
- clearInterval(repeat);
- }, 50);
原文出自:http://uusama.com/377.html
JavaScrpit中异步请求Ajax实现的更多相关文章
- [js开源组件开发]network异步请求ajax的扩展
network异步请求ajax的扩展 在日常的应用中,你可能直接调用$.ajax是会有些问题的,比如说用户的重复点击,比如说我只希望它成功提交一次后就不能再提交,比如说我希望有个正在提交的loadin ...
- 异步请求Ajax(取得json数据)
异步请求Ajax 没有学习Ajax之前请求数据的时候都是整个页面全部刷新了一次,也就是每次请求都会重新请求所有的资源.但是在很多时候不需要页面全部刷新,仅仅是需要页面的局部数据刷新即可,此时需要发送异 ...
- 在内核中异步请求设备固件firmware的测试代码
在内核中异步请求设备固件firmware的测试代码 static void ghost_load_firmware_callback(const struct firmware *fw, void * ...
- SpringBoot中异步请求和异步调用(看这一篇就够了)
原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10661591.html,否则将追究法律责任!!! 一.SpringBoot中异步请求的使用 ...
- ASP.NET WebForm中异步请求防止XSRF攻击的方法
在ASP.NET MVC中微软已经提供了如何防止跨域攻击的方法.对于传统Webfrom中使用Handler来接受ajax的Post请求数据,如何来防止XSRF攻击呢.这里给大家提供一个简单地方法,和M ...
- 异步请求Ajax
AJAX:Asynchronous JS And XML,包括HTML.CSS.JS.DOM.XML.JSON等,客户端技术范畴.主要目标:发起异步请求/响应,实现页面内容的局部刷新,提高浏览体验:实 ...
- jQuery中异步请求
1.load方法 使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: $(selector).load(URL,data,callback); ...
- 关于异步请求AJAX的具体解释
1,异步请求的方法步骤: 1,推断当前用户支持的浏览器类型 XMLHttpRequest:推断是否支持非IE浏览器,相应的创建方法:xmlhttp = new XMLHttpRequest(); wi ...
- vue中异步请求渲染问题(swiper不轮播)(在开发过程中遇到过什么问题、踩过的坑)
问题描述: 用vue封装一个swiper组件的时候,发现轮播图不能轮播了. 原因: 异步请求的时间远大于生命周期执行的时间,mounted初始化DOM时数据未返回,渲染数据是空数组,导致轮播图的容器层 ...
随机推荐
- angular directive自定义指令
先来看一下自定义指令的写法 app.directive('', ['', function(){ // Runs during compile return { // name: '', // pri ...
- angularui 分页
分页组件的使用 <!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> ...
- HDFS概述(4)————HDFS权限
概述 Hadoop分布式文件系统(HDFS)的权限模型与POSIX模型的文件和目录权限模型一致.每个文件和目录与所有者和组相关联.该文件或目录将权限划分为所有者的权限,作为该组成员的其他用户的权限.以 ...
- Java常用异常整理
填坑,整理下Java的常用异常.正确使用异常在实际编码中非常重要,但面试中的意义相对较小,因为对异常的理解和应用很难通过几句话或几行代码考查出来,不过我们至少应答出三点:异常类的继承关系.常用异常类. ...
- python GUI实战项目——tkinter库的简单实例
一.项目说明: 本次通过实现一个小的功能模块对Python GUI进行实践学习.项目来源于软件制造工程的作业.记录在这里以复习下思路和总结编码过程.所有的源代码和文件放在这里: 链接: https:/ ...
- 使用SQLite做本地数据缓存的思考
前言 在一个分布式缓存遍地都是的环境下,还讲本地缓存,感觉有点out了啊!可能大家看到标题,就没有想继续看下去的欲望了吧.但是,本地缓存的重要性也是有的! 本地缓存相比分布式缓存确实是比较out和比较 ...
- express简介
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...
- javascript特效300例----抄书喽
-javascript300例- #body_div { background-color: #202425; color: white; margin: 0 auto; border: 5px gr ...
- HDU1197 Specialized Four-Digit Numbers
进制转化 hdu1197 #include<cstdio> #include<cstdlib> #include<iostream> #include<mem ...
- Java web 入门知识 及HTTP协议详解
Java web 入门知识 及HTTP协议详解 WEB入门 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资 ...