JS中同步和异步
同步和异步的执行顺序
// 伪代码
setTimeout(() => {
task() // 表示一个任务
},2000)
sleep(5000) // 表示一个很复杂的同步任务
定时器中的2秒后执行并不一定是2秒后就一定执行,由于sleep是同步任务同时又由于JS是单线程的,因此必须等sleep结果出来了,JS中主线程处于空闲状态才去执行事件队列Event Queus中的异步结果(定时器会先到Event Table,等定时器的时间到了就会进入Event Queue)
经典面试题
setTimeout({},0)是在什么时候执行
=> 虽然写的是0,但是并不是立即执行,最少也要等到4ms之后才能被执行
// 下面代码的执行结果?
console.log(1)
setTimeout(() => {
console.log(2)
},0)
console.log(3)
执行结果是: 1 3 2
代码自上而下执行,当读到定时器时先放入Event Table等主线程中同步任务(console.log(1)和console.log(3))执行完成开始空闲下来时才会拿到Event Queue中的异步结果(当定时器时间到了,会进入Event Queue中返回结果)
Ajax
定义
Ajax 本身不是一种技术,而是一种将一些现有技术结合起来使用的方法,AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
原理
如何用原生的JS代码实现Ajax?
// 1. 创建XMLHttpRequest对象
var xtmlhttp
var url = 'http://jsonplaceholder.typicode.com/users'
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest()
// 兼容早期浏览器
} else {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
}
// 2. 发送请求
xmlhttp.open('GET',url,true)
xmlhttp.send()
// 3. 接收服务端相应
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
var obj = JSON.parse(xmlhttp.responseText)
console.log(obj);
}
}
将Ajax封装成可复用的函数
function ajax(url,callback) {
// 1. 创建XMLHttpRequest对象
var xtmlhttp
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest()
// 兼容早期浏览器
} else {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
}
// 2. 发送请求
xmlhttp.open('GET',url,true)
xmlhttp.send()
// 3. 接收服务端相应
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
var obj = JSON.parse(xmlhttp.responseText)
callback(obj);
}
}
}
var url = 'http://jsonplaceholder.typicode.com/users'
ajax(url,res => console.log(res))
Callback hell(又叫“回调深渊”或者"回调地狱")
eg: 假如有3个Ajax请求,这3个Ajax是有相互依赖关系,即第一个请求执行结束之后,再 执行第二个请求,第二个请求结束后再执行第三个请求
1 -> 2 -> 3
Ajax是一个异步操作,那我们怎么知道当前1的任务在什么时候完成呢?
前面封装的ajax函数中,传了一个参数callback,如果它被调用就说明ajax请求结束了
因此,我们可以在1的回调函数callback中发送2的ajax请求,然后再在2的回调函数中发送3的ajax请求
eg: 在static目录下新建a.json、b.json、c.json,请求到a.json的结果后再请求b的结果再请求c.json的结果
function ajax(url,callback) {
// 1. 创建XMLHttpRequest对象
var xtmlhttp
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest()
// 兼容早期浏览器
} else {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
}
// 2. 发送请求
xmlhttp.open('GET',url,true)
xmlhttp.send()
// 3. 接收服务端相应
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
var obj = JSON.parse(xmlhttp.responseText)
callback(obj);
}
}
}
// 1 -> 2 -> 3
ajax('static/a.json',res =>{
console.log(res) // {a: '我是A'}
ajax('static/b.json',res => {
console.log(res); // {b: '我是B'}
ajax('static/c.json',res => {
console.log(res); // {c: '我是C'}
})
})
})
这种应用场景还是非常常见的,eg: 省市区三级联动,每个下面的层级都依靠上一层级的结果,产生一定的依赖关系
上面这种层层嵌套异步的ajax请求,每一层都都产生一定的依赖关系,这种就叫callback hell,这种结构对于代码的可读性或者维护都不是很友好