1、同步:执行完一件事再去执行另一件事情。缺点:一旦阻塞,后面的方法无法执行。
2、异步:请求一件事情的同时再去执行另外一件事情。缺点,请求的结果还没有返回来,就执行后面的代码。
在用JavaScript时,为了实现某些逻辑会用到函数嵌套,但嵌套过多会形成一个回调地狱,影响对代码的理解以及可读性。
Promise是异步编程的一种解决方案,比传统的解决方案(回调函数+事件)更合理,更强大,相当于是一个规范。
Promise主要是为了解决JS中多个异步回调难以维护和控制的问题。
Promise对象中有三种状态,进行中,已成功,已失败。
在ES6中Promise是一个构造函数,用来生成Promise实例。
Promise构造函数接收一个函数作为参数。
Promise的两个参数分别是resolve,reject(这个两个参数有js引擎提供,不需要自己部署)。
resolve函数的作用是将Promise对象的状态从未完成到成功,成功后将异步结果作为参数传递出去。
reject函数的作用是将Promise对象的状态从未完成到失败,失败后将异步结果作为参数传递出去。
Promise实例生成后可用then方法分别制定resolve和reject状态的回调函数。
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
从浏览器中创建 XMLHttpRequest。
支持 Promise API。
客户端支持防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
提供了一些并发请求的接口(重要,方便了很多的操作)。
从 node.js 创建 http 请求。
拦截请求和响应。
转换请求和响应数据。
取消请求。
自动转换JSON数据。
1、修改前的代码
mui.ajax({ type: "get", cache: false, dataType: "json", data: null, async: true, beforeSend: function(XHR) { //发送ajax请求之前向http的head里面加入验证信息 XHR.setRequestHeader('Authorization', 'BasicAuth' + loginTicket); XHR.setRequestHeader('mobile', '0'); }, xhrFields: { withCredentials: true }, url: WebApiUrl + apiInfo.loginTestApi + "?keypwds=" + encryptedN, contentType: 'application/json', success: function(data) { if (data != null) { if (data.Data.Flag == true) { /* ..代码省略.. */ /* 获取基础信息 嵌套 */ PostAjaxValidate(Rowguid_CID, WebApiUrl + "api/AppLogin/GetLoginEquipInfo", function(respEquip) { /* ..代码省略..*/ mui.ajax({ url: apiInfo.Project_UpdateCidAPi, type: 'POST', timeout: 5000, contentType: 'application/json', dataType: "json", data: JSON.stringify({ "cid": cid, "userId": UserGuid }), complete: function(xhr, data) {}, success: function(data, textStatus, request) { /* 嵌套3 */ GetAjaxValidate(Rowguid_CID, WebApiUrl + "api/GeTuiPush/SetRowGuidClientID", function(response) {}); }, error: function(error) { console.log("登录异常:" + error) } }); /* ..代码省略.. */ mui.hideLoading( function() { Common.initOpen('/pages/WorkOrders/home_new.html', '/pages/WorkOrders/home_new.html', {}) }) }); } } } });2、修改后的代码
封装request
...... axios.defaults.withCredentials = true //请求拦截器 axios.interceptors.request.use(function(config) { //在发送请求前 config.headers['Authorization'] = 'BasicAuth ' + window.localStorage.Ticket; config.headers['mobile'] = '0'; config.headers['UserName'] = "App" + window.localStorage.UserName; config.headers['Password'] = window.localStorage.Password; return config; }, function(error) { //请求错误 return Promise.reject(error) }); //响应拦截器 axios.interceptors.response.use(function(response) { return response; }, function(error) { return Promise.reject(error) }); const requestList = { /* 登录 */ login: function(data, url) { try { var encryptedN = CryptoJSInfo(data); return axios({ method: 'GET', url: url + "?keypwds=" + encryptedN, params: null }) } catch (e) { //TODO handle the exception } }, /* post请求 */ post: function(data, url) { try { var encryptedN = CryptoJSInfo(data); return axios({ method: 'POST', url: url, data: encryptedN }) } catch (e) { //TODO handle the exception } }, /* get请求 */ get: function(data, url) { try { var encryptedN = CryptoJSInfo(data); return axios({ method: 'GET', url: url + "?" + encryptedN }) } catch (e) { //TODO handle the exception } } ........ }调用requestjs中的方法
new Promise(function(resolve, reject) { /* 登录请求 */ requestList.login(selfInfo, WebApiUrl + apiInfo.loginTestApi).then(function(res) { if (res != null) {} }) }).then(function(Rowguid_CID) { /* 获取基础信息 */ return new Promise(function(resolve, reject) { PostAjaxValidate(Rowguid_CID, WebApiUrl + "api/AppLogin/GetLoginEquipInfo", function(respEquip) {}); resolve(Rowguid_CID) }) }).then(function(Rowguid_CID) { //将CID保存至服务器 return new Promise(function(resolve, reject) { GetAjaxValidate(Rowguid_CID, WebApiUrl +"api/GeTuiPush/SetRowGuidClientID",function(response) {}); resolve(Rowguid_CID) }) }).then(function(Rowguid_CID) { /* 修改消息中心的CID */ var param = { "cid": Rowguid_CID.RowGuid, "userId": Rowguid_CID.ClientID } PostAjaxNoValidate(JSON.stringify(param), apiInfo.Project_UpdateCidAPi, function(res) {}) })
备注:
使用axios代替所有的ajax请求,原因如下使用promise+axios解决请求多层嵌套的问题,使用promise+axios解决并行请求的问题。
代码简化,结构清晰,易维护。
为了不影响项目的调用方式,传参方式,方法名没有做变化,仅仅加了一个requestjs,用于存放axios的配置,参数加密,以及封装请求方法。baseservice.js做了简单的修改
修改前
//get方式提交,带验证 function GetAjaxValidate(data, url, FunName, asyncs) { var sendDate = new Date(); var mask = mui.createMask(); var loginTicket = window.localStorage.Ticket; if (asyncs == null) { asyncs = true; } var encryptedN = null; if (data != null) { encryptedN = com.Encrypt(JSON.stringify(data)); //加密 } mui.ajax({ type: "get", url: url, data: encryptedN, async: asyncs, timeout: 3000, beforeSend: function(XHR) { //发送ajax请求之前向http的head里面加入验证信息 XHR.setRequestHeader('Authorization', 'BasicAuth ' + loginTicket); //新增一个属性区分是否是移动端访问服务器 XHR.setRequestHeader('mobile', '0'); XHR.setRequestHeader('UserName', "App" + window.localStorage.UserName); XHR.setRequestHeader("Password", window.localStorage.Password); }, xhrFields: { withCredentials: true }, success: function(data, status) { if (status == "success") { var receiveDate = (new Date()).getTime(); var responseTimeMs = (receiveDate - sendDate) / 1000 FunName(data); } }, complete: function(XMLHttpRequest, status) { mui.hideLoading() var _dataInfo = {} try { if (status == "success") { _dataInfo.statecode = "200"; } else if (status == "error") { _dataInfo.statecode = "500"; } } catch (e) {} }, error: function(XMLHttpRequest, textStatus, errorThrown) { mui.hideLoading() if (XMLHttpRequest.responseText == "SessionError") { plus.runtime.restart(); Common.initToast("当前session失效!"); } else { //Common.initToast("数据请求失败!"); } } }); }修改后
function GetAjaxValidate(data, url, FunName, asyncs) { new Promise(function(resolve, reject) { requestList.get(data, url).then(function(data) { resolve(_dataInfo); FunName(data.data); }).catch(function(error) { resolve(_dataInfo); }); }).then(function(_dataInfo) { /* 调用前端日志方法入库 */ }) }