异步和回调

181 阅读3分钟

同步和异步

简单来说,同步能直接拿到结果,异步不能直接拿到结果
在JS中,有的函数不能立刻拿到结果,需要等一会才能拿到结果,比如发送HTTP请求,等待响应需要一段时间。 如果 JS 不能直接拿到一个函数的结果,可以先去执行别的代码,等结果到了再取结果,这就是异步 异步的好处是可以把用来等待的时间拿去做别的事情

如何判断同步函数和异步函数

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

回调

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

  • 轮询就是我定时去询问拿到结果了没,一般不用这种方法
  • 回调就是我写一个函数fn,然后传给异步函数,当异步函数执行完毕时,就会调用fn, 于是我们就通过回调拿到了异步处理的结果
    简单来说,回调函数就是写给别人用,自己不用的函数

举例

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 进制的整数

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

总结

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

  • 异步任务不能拿到结果

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

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

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