js中ajax异步问题
1、JS的执行顺序问题
浏览器是按照从上到下的顺序解析页面,因此正常情况下,JavaScript脚本的执行顺序也是从上到下的,即页面上先出现的代码或先被引入的代码总是被先执行,即使是允许并行下载JavaScript文件时也是如此。
Javascript语言的执行环境是"单线程"(single thread)。所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
2、JS的同步和异步概念
"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
概念讲到这里已经足矣,关键是真正要理解,我们可以打开某一个网站的请求为例,F12打开调试模式:
客户端向服务器发出了三个请求,这三个ajax请求在时间调度上可以看到是相互重叠的,意味着异步的现象的存在,并不是执行完第一个请求再顺序去执行第二第三个,而是在启动了头一个的请求之后紧接着马上就去请求第二个,第三个请求也紧随其后,而请求耗时都是在运行中,意味着回调函数还未得以执行,浏览器已经另开一个线程去走下面的方法了。
我在项目中并未深入理解这个异步现象中,以至于在调试下方代码的时候出现了问题,具体见案例:
var area;//area变量,执行Fn1()方法后才会有值
function Fn1(areaId){
debugger;
var url = 'admin/area/queryArea/'+areaId;
//自己封装的一个ajax异步请求
$my.Get(url,function(data){
debugger;
area= data;
});
}
//打印area信息
function Fn2(area){
console.log(area);
}
执行方式1:
Fn1();
Fn2();
console控制台会报错,而异常原因还是是Fn2()中的area为undefined,按照我们正常的理解如果是顺序执行,明明Fn1执行在前,为什么会得到这样的结果呢,如果理解了Ajax的异步请求机制就很好理解,Fn1()执行,而后遇到ajax请求了,于是浏览器开另一个线程往下去顺序执行Fn2()方法,Fn2()方法中的变量是依赖Fn1()中的回调赋值函数,但是此时请求还未完成,因此会报异常信息。
正确的写法是如下:
var area;//area变量,执行Fn1()方法后才会有值
function Fn1(areaId){
debugger;
var url = 'admin/area/queryArea/'+areaId;
//自己封装的一个ajax异步请求
$my.Get(url,function(data){
debugger;
area= data;
Fn2(area);
});
} //打印area信息
function Fn2(area){
console.log(area);
}
于是程序就能正常执行打印area信息了。实际上我们可以用调试模式来一步步跟代码:
方法运行到了第一个debugger处,一步步调试进入到$my.Get()方法,这里封装一个简单的ajax的Get请求,默认为异步调用,但是方法却并未进入到下一个debugger中而是直接跑到了别的方法里头去了,在别处运行了一会儿程序才开始执行到第二个debugger中。
从中我们可以总结:假如有两个ajax请求f1()和f2(),f1发起了请求去往服务器,而f1中的方法并不会马上得到执行而是另开一个线程去执行f2,如果这两个方法没有依赖关系,而f1内的方法需要等到服务器响应后才会执行回调函数。在实际开发中,我们可能会有这样的关系,即f2()的执行需要用到f1()回调的内容,如果仅仅携程f1();f2();是会出现页面报错的,正确的写法则是:f1(f2());
var username;
function fn1(){
ajax("user/getNname",function (data) {
//the callback function
username=data.username;
//fn2()顺序执行才能拿到变量值
fn2();
})
//此处写fn2()还是拿不到变量值,将为undefined
//fn2()
}
function fn2(){
console.log(username);
}
采用这种方式,我们把异步操作变成了同步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数,在js逻辑不是太复杂的情况下,采用这种方式是十分可行的。当然异步操作在面临复杂的业务场景还有更好的办法,这篇文章提炼总结的方法不错:js的四种异步编程方式。可以参考学习。
js中ajax异步问题的更多相关文章
- js中ajax异步导致的一些问题
问题1:ajax默认是异步,所以在ajax中对外面定义的变量赋值,不能正确赋值 $("form").submit( var flag; $.ajax({ type: 'GET', ...
- js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快、简单 post:安全,量大,不缓存)(服务器同步和异步区别:同步:等待服务器响应当中浏览器不能做别的事情)(ajax和jquery一起用的)
js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快.简单 post:安全,量大,不缓存)( ...
- JS中的异步以及事件轮询机制
一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...
- js中的异步与同步,解决由异步引起的问题
之前在项目中遇到过好多次因为异步引起的变量没有值,所以意识到了认识js中同步与异步机制的重要性 在单线程的js中,异步代码会被放入一个事件队列,等到所有其他代码执行后再执行,而不会阻塞线程. 下面是j ...
- JS中的异步
Hello,日常更新的我“浪”回来了!!! JS中有三座高山:异步和单线程.作用域和闭包.原型原型链 今天“浪”的主题是JS中的异步和单线程的问题. 主要从这三个方面入手 一.什么是异步(与同步作比较 ...
- prototype.js 和 jQuery.js中 ajax 的使用
这次还是prototype.js 和 jQuery.js冲突的问题,前面说到过解决办法http://www.cnblogs.com/Joanna-Yan/p/4836252.html,以及上网说的大部 ...
- js中ajax如何解决跨域请求
js中ajax如何解决跨域请求,在讲这个问题之前先解释几个名词 1.跨域请求 所有的浏览器都是同源策略,这个策略能保证页面脚本资源和cookie安全 ,浏览器隔离了来自不同源的请求,防上跨域不安全的操 ...
- JS中的异步与回调
问题的引出:在js中使用异步调用时,有可能会出现在异步的回调函数中设置调用之外的变量值,但在异步调用完成后去使用变量,却发现这些变量值并没有被成功设置的情况.如: google map中的地理编码,地 ...
- js中的异步[Important]
js作为前端最主流的语言,主要处理页面显示变化(mutation)和异步(asynchronicity), js语言的基本要素和使用惯例的演化大都围绕着这两大主题,两者均值得总结和思考的主题, 这里先 ...
随机推荐
- [转载]Docker 完全指南
Docker 完全指南 原作者地址: https://wdxtub.com/2017/05/01/docker-guide/ 发表于 2017-05-01 | 更新于 2017-08-03 | ...
- Oracle 标准版 企业版 个人版的区别 转帖
转帖来源: https://blog.csdn.net/flg_inwind/article/details/2628133 同事方总:http://www.oracle.com/us/corpora ...
- App phonegap
云端打包 https://build.phonegap.com/apps phonegap PC端下载 https://www.phonegap.com/getstarted/ 移动端下载 https ...
- java 前台使用枚举方法(一)
枚举值封装: http://blog.csdn.net/hanjun0612/article/details/72845960 一 基本类型 这里接着说前台调用枚举值. 首先,controller层 ...
- King's Quest POJ - 1904(强连通分量)
建图:王子u喜欢女孩v,则u到v连一条边.对于给出的初始完美匹配,王子u与女孩v匹配,则v到u连一条边.然后求SCC. 显然对于同一个SCC中王子数目和女孩数目是相等的,并且从某个王子出发能够到达所有 ...
- 使用highlight.js高亮静态页面的语言代码
显示静态的代码其实html的pre标签基本可以满足需求了,至少不会将换行的文本显示成一堆字符串. 不过能使静态的文本能高亮显示,倒更炫酷一点.其实很简单的,引入highlight.js包,可以使用cd ...
- 个推数据统计产品(个数)iOS集成实践
最近业务方给我们部门提了新的需求,希望能一站式统计APP的几项重要数据.这次我们尝试使用的是个推(之前专门做消息推送的)旗下新推出的产品“个数·应用统计”,根据官方的说法,个推的数据统计产品通过专业的 ...
- [Spring] 学习Spring Boot之二:整合MyBatis并使用@Trasactional管理事务
一.配置及准备工作 1.在 Maven 的 pom 文件中新增以下依赖: <dependency> <groupId>mysql</groupId> <art ...
- numpy中的arg系列函数
numpy中的arg系列函数 觉得有用的话,欢迎一起讨论相互学习~Follow Me 不定期更新,现学现卖 numpy中arg系列函数被经常使用,通常先进行排序然后返回原数组特定的索引. argmax ...
- C语言复习---迭代法,牛顿迭代法,二分法求根
一:用迭代法求 x=√a.求平方根的迭代公式为:X(n+1)=(Xn+a/Xn) /2. #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> ...