JavaScript中的异步

异步—代码烧脑的原因

1.同步和异步

同步:等待结果

异步: 不等待结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//同步
function sleep(seconds){
var a = new Date();
while(new Date() - a < seconds * 1000){

}
return
}
console.log(1);
sleep(3);
console.log('wake up');
console.log(2);
//运行结果 1 wake up 2
// 同步是需要等待的,但是 JavaScript 没有这一项功能,所以只能让他不停的工作,然后到达3秒钟
1
2
3
4
5
6
7
8
9
10
// 异步
function sleep(seconds,fn){
setTimeout(fn,seconds * 1000); // 实际上是在设置闹钟,让浏览器 xx秒 后执行 fn
return;
}
console.log(1);
sleep(3,()=>{console.log('wake up ')});
console.log(2)
//运行结果 1 2 wake up
// 为什么 setTimeout 可以模拟异步? 因为 setTimeout 方法是浏览器提供并负责执行的,JS告诉浏览器3S以后执行fn,然后它就可以去干下一步事情了。

可以看出,使用异步,JS空闲了很多。

但是注意,JS空闲的时间,浏览器的计数器一直在工作。

2.前端经常用到的异步

1
2
var w = document.getElementsByTagName('img')[0].width;
console.log(w) // 0

明明有图片,为什么宽度为0呢?

因为图片加载需要时间。

例子

注意把 Network 的缓存禁用,可以看到效果

解决方案

在图片加载完成后会有一个 onload事件

1
2
3
4
var img = document.getElementsByTagName('img')[0];
img.onload = function(){
console.log(img.width) //400
}

3.遍历的异步

1
2
3
4
5
6
7
8
9
10
11
var li_List =document.querySelectorAll('li');
for(var i = 0;i<li_List.length;i++){
li_List[i].onclick = function(){
console.log(i)
}
}
//期望值:点击哪一个 li , 就会出现该 li 的序号
//结果:打印出的结果会全部都是 n+1
//原因:var i= 0,变量声明提升,会导致循环里用的都是一个 i ,i 最后循环结果会变为 n+1
//解决方法: let i = 0 ,let 在每次循环的时候都会制造一个分身,绑定到该 li_List[i]上
//哪里的异步? li_List[i].onClick = function(){} JS没有功夫等你触发 onclick 事件,直接进行了下一步 i++

例子

4.AJAX中的异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let requsest = $.ajax({
url:'.',
async:false
})
console.log(request.responseText);
//同步的ajax , 在请求过程中,JS会一直等待响应,非常浪费资源

$.ajax({
url:'.',
async:true,
success:function(res){
console.log(res)
}
})
console.log('OK')
//结果 : OK res
//异步的ajax
// 为什么使用 success 接收请求? 因为这是异步的,使用 var xx = $.ajax({}) 是得不到任何数据的,所以我们告诉浏览器,当接收到请求的时候再用 success 处理

5.异步拿到结果的形式

两种方式

  1. 轮训 :不推荐
  2. 回调 :推荐

回调的形式

1.nodejs的 error-first 形式

1
2
3
4
5
6
7
fs.readFile('./1.txt',(error,content)=>{
if(error){
//error
}else{
//success
}
})

2.Jquery 的 success-error 形式

1
2
3
4
5
$.ajax({
url:'',
success:()=>{},
error:()=>{}
})

3.Jquery的 done/fail/always形式

1
2
3
4
5
$.ajax({

url:'xxx'

}) . done( ()=>{} ) . fail( ()=>{} ).always( ()=>{} )

4.Promise 的 then 形式

1
2
3
4
5
axios({

url:'xxxx'

}).then( ()=>{ success } ,()=>{ fail }).then(()=>{})

6.Promise的错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
axios({
url:'.',
async:true
}).then((x)=>{
console.log('succ1')
return 'aaaaa'
},(y)=>{
console.log('err1')
}).then((x)=>{
console.log('succ2',x) // succ2 aaaa
},(y)=>{
console.log('err2')
console.log(y)
})

succ1和err1中的代码任意一个有错误,都由err2来处理 , err2的第一个参数可以接受错误值

succ1成功,转入succ2

succ1 return 的值会传入 succ2的参数

手动失败 return Promise.reject('xxx')

catch可以放在最后搞定之前没写 失败函数的then ,但是 .catch((err)=>{}) === .then(undefined,(err)=>{})

例子

7.手写一个Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function ajax(){
return new Promise((resovle,reject)=>{
//做事情
// 成功resovle
// 失败 reject
})
}
function buy(){
return new Promise((res,rej)=>{
setTimeout(()=>{
res('apple')
},2000)
})
}
buy().then((res)=>{console.log(res)},(err)=>{console.log(err)})

例子

8.async/await

以同步的方式写异步

1
2
3
4
5
6
7
8
function buy(){
return new Promise((res,rej)=>{
setTimeout(()=>{
res('apple')
},2000)
})
}
var res = await buy();