一、背景
在写项目的时候有时候在Ajax中请求了后端返回的数据,不想在success中处理或需要将结果带出Ajax(可能是业务需求),这时就需要处理了。一般解决方法是想办法将 Ajax 请求返回的结果同业务处理逻辑都放到 Ajax 中或者定义一个全局变量存数据,而定义一个全局变量,然后再在ajax中赋值可能就会出现这个问题,为什么我在这说可能出现这个问题呢?这个原因且听我慢慢道来。
二、Ajax中给全局变量赋值不上的原因
在Ajax中给全局变量赋值不上主要是因为Ajax默认是异步请求。为更清楚直观地知道这个原因,在这里我写了代码测试。
首先是我新建了一个叫Test2的项目,然后在后端写了这样的代码,大家都知道通过 Ajax 向后端请求这个 Servlet 会返回数据 Text 数据“后台返回的数据”。
package com.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class TestServlet
*/
@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("后台返回的数据");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
其次我写的 JS 代码如下,然后在控制台时刻打印出全局变量 _STR 的值,我给打印的内容标上了序号 12345 ,我们期望的打印顺序也是 12345 的依次打印在控制台。
注意:我这里用的是 Ajax 异步请求。
var _STR = "默认值";
function test() {
console.log("1.在ajax赋值前ajax外面 _STR 的值:" + _STR);
var url = "<%=request.getContextPath() %>/testServlet";
$.ajax({
url: url,
type:'post',
async: true,
dataType: 'text',
data: {
},
success: function(data) {
console.log("2.在ajax赋值前ajax里面 _STR 值:" + _STR);
console.log("3.data = " + data);
_STR = data; //给全局变量赋值
console.log("4.在ajax中赋值后ajax里面 _STR 的值:" + _STR);
}
});
console.log("5.在ajax赋值后ajax外面 _STR 的值:" + _STR);
}
然后,我在前端 JSP 写了下面这段的代码,为了能通过点击按钮能触发 JS 写的函数 test 。
<input type="button" onclick="test()" value="js全局变量ajax赋值">
现在我们就开始测试(Ajax 是异步请求),下图是测试结果:
控制台打印出来的顺序是 15234,和我们预期的结果 12345 不一样,产生这样的原因是因为什么我们先不说,暂留这个问题;然后我们在来看其中的 全局变量 _STR 的值 第1步打印的值是 “默认值”,在第5步打印的值和第一步一样,第2步和预期(_STR 的值是”默认值“)的一样,第3步是打印返回的值,作用是确定返回的值是后端返回的,第4步 _STR 的值和预期(_STR 的值是后端返回的值)一样。这里主要的问题是第5步比第234步执行的要快,所以在第234步没执行完第5步就拿到了没有赋值前的值,然后一直拿着这个原值执行下去,这就是为什么“赋值不上”。
紧接着我们将 JS 改动一部分:将第5步不直接打印,改为在 Ajax 请求完并赋值给全局变量后 打印 _STR 的值,我就给了它4秒后打印,这样4秒的时间 Ajax 请求应该能请求完并赋值给全局变量了吧。
var _STR = "默认值";
function test() {
console.log("1.在ajax赋值前ajax外面 _STR 的值:" + _STR);
var url = "<%=request.getContextPath() %>/testServlet";
$.ajax({
url: url,
type:'post',
async: true,
dataType: 'text',
data: {
},
success: function(data) {
console.log("2.在ajax赋值前ajax里面 _STR 值:" + _STR);
console.log("3.data = " + data);
_STR = data; //给全局变量赋值
console.log("4.在ajax中赋值后ajax里面 _STR 的值:" + _STR);
}
});
// 将这里改为4秒后打印 _STR 的值
setTimeout(function () {
console.log("5.在ajax赋值后ajax外面 _STR 的值:" + _STR);
}, 4000);
}
果不其然,4秒时间完全够 Ajax 请求完并赋值给全局变量了,见下图,当我们给这个 Ajax 足够的时间去请求后端拿到值,然后赋值给全局变量,再打印出结果。从这里我们可以看出其实是给全局变量附上值了的,只是后面的代码没有拿到赋值后的值。
然后我们将 Ajax 改为同步async: false,
接着测试,下图是测试结果
控制台打印出来的结果是 12345 ,和我们想要的结果一样。
综上所述,JS 设置全局变量在 Ajax 中赋值不上的原因是 Ajax 为异步请求。