浅析异步和回调

168 阅读3分钟

一、什么是同步和异步?

  1. 同步:直接能拿到结果
  2. 异步:不能直接拿到结果

在JS中,有的函数不能立刻拿到结果,需要等一会才能拿到结果,比如发送HTTP请求,等待响应需要一段时间。

如果 JS 不能直接拿到一个函数的结果,可以先去执行别的代码,等结果到了再取结果,这就是异步

 异步的好处是可以把用来等待的时间拿去做别的事情

怎么判断一个函数的结果是同步的还是异步的呢?

如果一个函数的返回值在setTimeout, AJAX, AddEventListener 这三个东西内部,那么这个函数就是异步函数

二、什么是回调?

我们希望能够拿到异步函数的结果,有两种方法:轮询和回调

  • 轮询就是我定时去询问拿到结果了没
  • 回调就是我写一个函数fn,然后传给异步函数,当异步函数执行完毕时,就会调用fn, 于是我们就通过回调拿到了异步处理的结果

满足以下条件的函数就是回调函数:我写给别人用,自己不用的函数

举例:

  1. 我写了函数A,传给函数B, B会调用函数A, 那么A就是回调
    1. arr.forEach((item)=>console.log(item))
    2. (item)=>console.log(item) 这个箭头函数就是一个回调
  1. 有的时候回调还可以传给一个对象,
    1. 当我们写AJAX请求时,我们把回调传给 request.onreadystatechange,等待浏览器来调用

图中标黄的函数就是回调函数

注意:回调可以用于同步任务,不一定非要用于异步任务

回调举例

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)
}

三、总结

我们来总结一下异步与回调的关系

  • 异步任务不能拿到结果

  • 于是我们传一个回调给异步任务

  • 异步任务完成时调用回调函数

  • 调用的时候把结果作为参数