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语言的基本要素和使用惯例的演化大都围绕着这两大主题,两者均值得总结和思考的主题, 这里先 ...
随机推荐
- Session, Cookie区别
答: 1.Session由应用服务器维护的一个服务器端的存储空间:Cookie是客户端的存储空间,由浏览器维护. 2.用户可以通过浏览器设置决定是否保存Cookie,而不能决定是否保存Session, ...
- SSH协议详解
简介 SSH只是一个协议,基于这个协议有不同的实现,这些实现中有开源,也有收费. 原理 普通网络通信一般是明文通信,数据容易被中间人拦截并且解析,而SSH协议则提供了基于内容加密服务. 流程: 第一种 ...
- gcc 与 glibc 的关系 glibc版本查看
glibc是什么,以及与gcc的关系?glibc是gnu发布的libc库,也即c运行库.glibc是linux 系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc.gl ...
- scheme 教程 #lang racket
scheme 教程 #lang racket 来源 https://blog.csdn.net/yemeishenme/article/details/51471037 原文: https://le ...
- 自学Aruba1.1-WLAN一些基本常识
点击返回:自学Aruba之路 自学Aruba1.1-WLAN一些基本常识 1. LAN.WAN.WLAN.WIFI术语 1.1 局域网(Local Area Network,LAN) 是指在某一区域内 ...
- 洛谷 P1437 [HNOI2004]敲砖块 解题报告
P1437 [HNOI2004]敲砖块 题目描述 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖 都有一个分值,敲掉这块砖就能得到相应的分值,如下所示. 1 ...
- token的理解
今天学习了token,它的英文意思是令牌的意思.在我理解即像通行证一样,在用户登录成功系统后,会为这个用户颁发一个token,这样它去其他系统都免登录,因为有了这个令牌. token的生成我们可以用U ...
- jedisClient操作redis实现增删改查功能
这个集群环境下和单机环境下: package com.taotao.sso.dao.impl; import org.springframework.beans.factory.annotation. ...
- 127. Word Ladder(M)
127. Word LadderGiven two words (beginWord and endWord), and a dictionary's word list, find the leng ...
- Swift学习笔记1
1.Swift 的String类型是值类型. 如果您创建了一个新的字符串,那么当其进行常量.变量赋值操作,或在函数/方法中传递时,会进行值拷贝. 任何情况下,都会对已有字符串值创建新副本,并对该新副本 ...