一、什么是同步和异步?
- 同步:直接能拿到结果
- 异步:不能直接拿到结果 在 JS 中,有的函数不能立刻拿到结果,需要等一会才能拿到结果,比如发送 HTTP 请求,等待响应需要一段时间。 如果 JS 不能直接拿到一个函数的结果,可以先去执行别的代码,等结果到了再取结果,这就是异步 异步的好处是可以把用来等待的时间拿去做别的事情
怎么判断一个函数的结果是同步的还是异步的呢?
如果一个函数的返回值在 setTimeout, AJAX, AddEventListener 这三个东西内部,那么这个函数就是异步函数
二、什么是回调?
我们希望能够拿到异步函数的结果,有两种方法:轮询和回调 • 轮询就是我定时去询问拿到结果了没 • 回调就是我写一个函数 fn,然后传给异步函数,当异步函数执行完毕时,就会调用 fn, 于是我们就通过回调拿到了异步处理的结果 满足以下条件的函数就是回调函数:我写给别人用,自己不用的函数 举例:
-
我写了函数 A,传给函数 B, B 会调用函数 A, 那么 A 就是回调 a. arr.forEach((item)=>console.log(item))
b. (item)=>console.log(item) 这个箭头函数就是一个回调 -
有的时候回调还可以传给一个对象, a. 当我们写 AJAX 请求时,我们把回调传给 request.onreadystatechange,等待浏览器来调用 这里我们回顾下 AJAX 请求步骤
let xhr=new XMLHttpRequest() xhr.open('get',url) xhr.onreadystatechange=function(){ if(xhr.readyState===4&&xhr.status===200){ console.log(request.response) } } xhr.send()
注意:回调可以用于同步任务,不一定非要用于异步任务 回调举例
function 摇骰子() {
setTimeout(() => {
return parseInt(Math.random() * 6) + 1;
}, 1000);
}
注意在这个代码里, 摇骰子()没有写 return ,即 return undefined, 箭头函数里有 return, 返回真正的结果,所以这是一个异步函数
const n = 摇骰子();
console.log(n); // n 是 Undefined
那么我们应该怎么去拿到 setTimeout 的结果呢? 可以用回调
function callback(x) {
console.log(x)
}
摇骰子(callback){
setTimeout(()=>{
callback(parseInt(Math.random()\*6) + 1)
},1000)
}
我们可以把 callback 函数简化成箭头函数
摇骰子((x) => {
console.log(x);
});
// 由于这里函数的参数和需要用到的值是一样的,所以还可以简化为
摇骰子(console.log);
但是如果参数个数不一样,就不能这么简化, 举例:
const array = ["1", "2", "3"].map(parseInt);
得到的结果是[(1, NaN, NaN)];
这里错误的原因就是因为 忽略了 Map 函数和 parseInt 函数参数不同 首先我们来复习一下 map 函数
let new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
map 的回调函数有三个参数,分别是 currentValue, index, array 本身 而 parseInt 有两个参数 string 和 radix,表示将一个字符串 string 转换为 radix 进制的整数 parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数
const array = ["1", "2", "3"].map(parseInt);
这种写法等价于[("1", "2", "3")].map((currentValue, index, array) => {
parseInt(currentValue, index, array);
// parseInt('1', 0) 把'1'换成 0 进制,那就是 1
// parseInt('2', 1) 把'2'换成 1 进制,1 进制里没有 2,所以是 NaN
// parseInt('3', 2) 把'3'换成 2 进制,2 进制里没有 3,所以是 NaN
});
下面是正确的写法,就是写明参数即可
['1', '2', '3'].map((currentValue, index, array) => {
parseInt(currentValue)
}
三、总结 我们来总结一下异步与回调的关系 • 异步任务不能拿到结果 • 于是我们传一个回调给异步任务 • 异步任务完成时调用回调函数 • 调用的时候把结果作为参数