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语言的基本要素和使用惯例的演化大都围绕着这两大主题,两者均值得总结和思考的主题, 这里先 ...
随机推荐
- delphi执行查询语句时的进度条怎么做
procedure TForm1.FormCreate(Sender: TObject); begin ADOQuery1.ExecuteOptions := [eoAsyncFetch]; ...
- IntelliJ IDEA中文乱码问题
转自 https://blog.csdn.net/m0_37893932/article/details/78280663 1 file->settings->appearence里面有 ...
- 用send_keys输入文本的方法
我们使用app时,输入文字都是调用软键盘.在自动化测试中当然也可以调用软键盘,但是由于输入法设计上的差异,有时候不能达到很好的效果. 例如,搜狗拼音输入法: 选择4-咖啡,然而多打几次,输入法就把“咖 ...
- Spring之注入复杂类型属性
注入类: package helloworld; import java.util.List; import java.util.Map; import java.util.Properties; p ...
- Integration Guide
This document, along with the samples and Javadoc™ in the IBM Sametime Software Development Kit (SDK ...
- c#将文件复制到某个文件夹内winform文件复制
try { //系统盘 string nl = Environment.NewLine; string query = "%SystemRoot%"; string str = E ...
- 洛谷 P2047 [NOI2007]社交网络 解题报告
P2047 [NOI2007]社交网络 题目描述 在社交网络(\(social\) \(network\))的研究中,我们常常使用图论概念去解释一些社会现象.不妨看这样的一个问题.在一个社交圈子里有\ ...
- 【洛谷P1892】团伙
题目大意:维护 N 个人和 M 个关系,对每个人来说符合:我朋友的朋友也是我的朋友,我敌人的敌人也是我的朋友,求最多有多少个朋友构成的联通块. 题目大意:维护关系显然要用到并查集,这里是维护了两种关系 ...
- 离线安装MySQL5.7
无网络环境下安装MySQL5.7 前提: 1.系统环境:CentOS 7 64bit 2.需要的rpm包已经在本地 安装: 1.下载需要的rpm包: mysql-community-client-5. ...
- Java基础-SSM之mybatis快速入门篇
Java基础-SSM之mybatis快速入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 其实你可能会问什么是SSM,简单的说就是spring mvc + Spring + m ...