跳至主要內容

ajax

chanchaw大约 6 分钟javascript

概述

js 中使用 ajax 不需要引用什么依赖 - 直接使用,通过事件 onreadystatechange 展现一个请求执行的每个阶段,在该函数的回调函数中通过属性 readyState 区分不同的阶段: 0表示创建 XMLHttpRequest 对象,即:new XMLHttpRequest()
1表示为异步对象设置了请求的参数,即:ajaxObj.open("get","请求后端的地址",true);
2表示异步对象已经发送请求,即:xhr.send();
3表示异步对象已经接受到数据,还没有解析
4表示异步对象已经解析完数据,可以使用了
在 readyState 等于4 的情况下还要 xhr.status 等于200 (表示后端成功返回了数据),才可正常获取数据,完整使用案例看下面代码:

菜鸟教程 -- 学的不仅是技术,更是梦想!!!

菜鸟教程 -- 学的不仅是技术,更是梦想!!!

菜鸟教程 -- 学的不仅是技术,更是梦想!!!

<!doctype html>
<html lang="zh">
<head>
  <meta charset="utf-8">
  <title>最简单 ajax 案例</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
	<button onclick="printDate()">打印日期</button>
	<button onclick="req()">请求后端数据</button>

  <script type="text/javascript">
		var ajaxObj = null;
		window.onload = initCmpt;// 页面加载时初始化 ajax 对象
	
		// 点击上面的按钮发送请求
		function req(){
			ajaxObj.open("get","https://www.jzy.world/wxbe/wechat/test",true);
			ajaxObj.send();
		}
		
		// 初始化组件
		function initCmpt(){
			ajaxObj = new XMLHttpRequest();
			ajaxObj.onreadystatechange = printReqState;
		}
		
		// ajax 对象每次状态变化都打印到浏览器控制台
		function printReqState(){
			switch(ajaxObj.readyState){
				case 0: // 表示 new XMLHttpRequest()
					printLog("还没有初始化异步对象");
					break;
				case 1:// 表示为异步对象设置了参数:ajaxObj.open("get","请求后端的地址",true);  第三个参数默认 true 表示异步执行,相反则是同步执行
					printLog("初始化异步对象完毕");
					break;
				case 2:// 对应  ajaxObj.send();
					printLog("异步对象发送请求完毕");
					break;
				case 3:
					printLog("异步对象接受到数据还没有解析");
					break;
				case 4:
					printLog("异步对象解析数据完毕");
					// 正常接受到后端的数据的判断如下:
					// if( ajaxObj.readyState == 4 && ajaxObj.status == 200 ) {
					//    var data = ajaxObj.responseText; 获取后端响应的数据
					//}
					if( ajaxObj.status == 200 ){
						printLog("接收到的数据是:" + ajaxObj.responseText);
					}
					break;
				default:
					printLog("异步对象出现意料之外的状态");
			}
		}
		
		function printDate(){
			//const now = new Date().format2MilliSecond();
			//const now = new Date().format2Second();
			//const now = new Date().formatNoTime();
			const now = new Date(new Date().setDate(new Date().getDate()+1)).format2MilliSecond();
			console.log(now);
		}
		
		function printLog(content){
			console.log(new Date().format2MilliSecond() + " : " + content);
		}
		/*
		var ajaxObj = new XMLHtmlRequest();
		ajaxObj.onreadstatechange = function () {
			if( ajaxObj.readState == 1 ){
				const now = new Date().format("yyyy-MM-dd HH:mm:ss.S");
				console.log();
			}
		}
		*/
		
		
		/**
		/*对Date的扩展,将 Date 转化为指定格式的String
		/* 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
		/* 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
		/* 例子:
		/* (new Date()).Format("yyyy-MM-dd HH:mm:ss.S") ==> 2019-01-02 10:19:04.423
		/* (new Date()).Format("yyyy-M-d H:m:s.S")      ==> 2019-1-2 10:19:4.18
		/* yyyy-MM-dd HH:mm:ss  ==> 2021-07-04 21:38:36
		/* yyyy-MM-dd ==> 2021-07-04
		*/
		Date.prototype.format = function (fmt) {
			var o = {
				"M+": this.getMonth() + 1, //月份
				"d+": this.getDate(), //日
				"H+": this.getHours(), //小时
				"m+": this.getMinutes(), //分
				"s+": this.getSeconds(), //秒
				"q+": Math.floor((this.getMonth() + 3) / 3), //季度
				"S": this.getMilliseconds() //毫秒
			};
			if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
			for (var k in o)
			if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
			return fmt;
		}
		
		Date.prototype.format2MilliSecond = function () {
			const fmt = "yyyy-MM-dd HH:mm:ss.S";
			return this.format(fmt)
		}
		
		Date.prototype.format2Second = function () {
			const fmt = "yyyy-MM-dd HH:mm:ss";
			return this.format(fmt)
		}
		
		Date.prototype.formatNoTime = function () {
			const fmt = "yyyy-MM-dd";
			return this.format(fmt);
		}


// 调用方法
this.deliveryPlanDate = new Date().format("yyyyMMdd")
	</script>
</body>

jquery

json方式

通过 JSON.stringfy 将参数对象序列化,后端 java 通过 @requestBody 读取参数,案例代码:

function login(){
  $.ajax({
      async: true,
      //请求方式
      type : "POST",
      //请求的媒体类型
      contentType: "application/json;charset=UTF-8",
      // 这里后端使用了 springboot 中集成了 springsecurity做权限管理
      data: JSON.stringify({"username":"1001","password":"7758"}),
      //请求地址
      url : "https://www.jzy.world/white/login/in",
      //请求成功
      success : function(result) {
        console.log(result);
        alert('登录返回的code=' + result.code + ',data=' + result.data);
      },
      //请求失败,包含具体的错误信息
      error : function(e){
        console.log(e.status);
        console.log(e.responseText);
      },
      complete: function () {
        // 旭纸业项目中通过 progress 锁定前端页面
        // $.messager.progress({title: '提示', text: '请稍候...', interval: 5000});
        // $.messager.progress('close');
      }
  })
}

对象方式

不需要声明 contentType,data 属性直接传入参数对象即可,后端 java 直接通过模型类接受数据(API方法中参数为模型类,前面不需要 @requestBody

// 下面是前端代码
function login(){
  $.ajax({
      //请求方式
      type : "POST",
	  data: paramObj,
      //请求地址
      url : "https://www.jzy.world/white/login/in",
      //请求成功
      success : function(result) {
        console.log(result);
        alert('登录返回的code=' + result.code + ',data=' + result.data);
      },
      //请求失败,包含具体的错误信息
      error : function(e){
        console.log(e.status);
        console.log(e.responseText);
      },
      complete: function () {
        // 旭纸业项目中通过 progress 锁定前端页面
        // $.messager.progress({title: '提示', text: '请稍候...', interval: 5000});
        // $.messager.progress('close');
      }
  })
}

// 下面是后端 java 代码
@RequestMapping(value = "/query", method = {RequestMethod.GET, RequestMethod.POST})
public List<Craftcolor> query(Craftcolor craftcolor) throws Exception {
    List<Craftcolor> ret = service.query(craftcolor);
    return ret;
}

deferred

从 1.5.0 版本开始,jquery 开始引入 deferred 对象,有点类似 Promise 对象。使得 ajax 请求可以使用链式形式的请求

$.ajax("test.html")
  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

或者下面的形式

$.ajax("test.html").then(
  function(res){
    // 请求成功响应.res是响应来的数据
  },
  function(err){
    // 请求出现异常
  }
)

Deffered 改造为 Promise 对象

const req1 = {type:'GET',dataType:'json',contentType: 'application/json',url: 'billType/selectCPCK',};
const req2 = {type:'GET',dataType:'json',contentType: 'application/json',url: 'jcStore/listQuery',};

const getAjaxPromise = function(option){
    return new Promise(function(resolve,reject){
        $.ajax({
            type: option.type,
            dataType: option.dataType,
            contentType: option.contentType,
            url: option.url,
            data: option.data || '',
            success: function(data){
                resolve(data);
            },
            error: function(error){
                reject(error);
            }
        });
    })
}

const req1$ = getAjaxPromise(req1);
const req2$ = getAjaxPromise(req2);

req1$.then(
    function(res){
        console.log('req1$响应来的数据是:');
        console.log(res);

        return req2$;
    },
    function(err){
        console.log('req1$请求出现异常:');
        console.log(err);
    }
)
.then(
    function(res){
        console.log('req2$响应来的数据是:');
        console.log(res);
    },
    function(err){
        console.log('req2$请求出现异常:');
        console.log(err);
    }
)

Promise.all 获取 promise对象

let generate = $.ajax({
    url: 'productOrderBill/query/selectProductOrderPkByDtlPk',
    data: {id: selected},
    traditional: true,
    dataType: 'json',
    type: 'POST',
});
Promise.all([generate])
    .then(data => {
        if (data != undefined && data instanceof Array && data.length > 0) {
            let g = data[0];
            if (g.length <= 0 && m.length <= 0) {
                $.messager.alert('提示', '无法查询相关入库单据!', 'warning');
            }
            for (let i of g) {
                if (i) {
                    window.parent.addTab(`成品出库-${i}`, `cp_order_bill_picking?id=${i}`);
                }
            }
        } else {
            $.messager.alert('提示', '无法查询相关入库单据!', 'warning');
        }
    })
    .finally(() => {
    });

添加自定义header

$.ajax({
    headers: {
        "tradeuser":"o-huL5u73__97ihViycOniCmV_eI"
    },
    type: "POST",
    url: "../../tradebe/sampleMain/save",
    contentType: "application/json",
    data: formData,
    processData: false,
    contentType: false,
    async:false,
    success: function (r) {
        console.log('上传图片的响应结果:', r)
    }
});

$.when

多个 http 请求并发执行,要求同时成功,否则进入第二个回调函数。第一个回调函数表示多个请求都成功了,按照前后顺序,res1 表示 req1的响应数据,res2 表示 req2 的响应数据。 注意响应来的对象 res1 的模型是:[data,statusText,jqXHR] 所以后台返回的实际数据是 res1[0]

const req1 = $.ajax({type:'GET',dataType:'json',contentType: 'application/json',url: 'billType/selectCPCK',});
const req2 = $.ajax({type:'GET',dataType:'json',contentType: 'application/json',url: 'jcStore/listQuery',});
// 注意下面传入函数名称,后面不要带有括号
$.when(req1,req2).then(
    function(res1,res2){
        console.log('请求成功返回:');
        console.log(res1);
        console.log(res2);
    },
    function(err){
        console.log('请求出现异常:');
        console.log(err);
    }
)

超过2个以上的请求推荐使用下面方法

function getDataFun(){
    var reqlist = [];
    reqlist.push($.ajax({url: "/equip_rank",type:'GET',dataType:'jsonp'}));
    reqlist.push($.ajax({url: "/score_rank",type:'GET',dataType:'jsonp'}));
    reqlist.push($.ajax({url: "/billionaire_rank",type:'GET',dataType:'jsonp'}));
 
    $.when.apply($,reqlist).then(function(data1,data2,data3){
        //成功回调,所有请求正确返回时调用
        console.log(data1[0]);
        console.log(data2[1]);
        console.log(data3[2]);
    },function(){
        //失败回调,任意一个请求失败时返回
        console.log('fail!!');
    })
}