关于异步和回调

225 阅读3分钟

1、什么是异步?什么是同步?

  • 如果能直接拿到结果,就是同步
    • 比如去医院挂号,只有在拿到号码以后,才会离开
    • 不拿到结果是不会离开的
  • 如果不能直接拿到结果,就是异步
    • 比如去网红餐厅吃饭,取了号后可以去继续逛其他的商店,等轮到自己的号码再来吃饭
    • 每隔几分钟去问一下服务员现在到第几桌了(轮询)
    • 通过小程序、公众号查看当前还有几桌,接受通知(回调)

2、异步举例

  • 以 AJAX 为例
    • request.send() 以后,并不能直接得到 response
    • 需要等待直到 readyState 变为4后,浏览器来回头调用 request.onreadystatechange 函数
    • 这个过程就像是,你在逛街的时候,餐厅发短信提醒你轮到你就餐了

3、什么是回调

  • 写给自己用的函数,不是回调
  • 写给别人用的函数,就是回调
  • 就像 AJAX 中的 request.onreadystatechange函数,就是用于浏览器来调用的
  • 意思就是让浏览器在之后某个时刻来调用以下这个函数

4、回调举例

  • 把函数 1 给另一个函数 2
function f1(){}
function f2(fn){
    fn()
}
f2(f1)
  • f1 是写给 f2 调用的函数,所以 f1 就是回调

5、异步和回调的关系

  • 关联:
    • 异步任务需要在得到结果时,通知 JS 来获取结果(就像在逛街时,需要有 app 来提醒自己还有多久排到自己)
    • 可以让 JS 留一个函数地址(类似于电话)给浏览器
    • 异步任务完成时,浏览器调用回调函数的地址即可(打电话通知)
    • 同时把结果作为参数传给该回调函数(通知可以来吃饭了)
    • 这个函数是通过浏览器调用的,是回调函数
  • 区别:
    • 异步任务需要用到回调函数来通知结果(或者轮询)
    • 但回调函数不一定只用于异步任务里
    • 回调也可以用在同步任务里
    • array.forEach(n => console.log(n)) 就是同步回调

6、如何知道一个函数是同步还是异步?

  • 如果一个函数的返回值处于

    • setTimeout
    • AJAX(即 XMLHttpRequest)
    • AddEventListener
  • 这三个东西内部,那么这个函数就是异步函数

  • 例:摇骰子

function 摇骰子(){
    setTimeout(()=>{
        return parseInt(Math.random()*6)+1
    },1000)
}
  • 分析:

    • 摇骰子() 没有写return,那就是 return undefined
    • 箭头函数里有 return ,返回真正的结果
    • 所以这是一个异步函数/异步任务
  • 例:摇骰子2

const n = 摇骰子()
console.log(n)    // undefined
  • 那么怎么才能拿到异步函数的结果?
    • 答:可以使用回调。写一个函数,然后把函数地址给 摇骰子()
function f1(x){
    console.log(x)
}
摇骰子(f1)
  • 然后要求 摇骰子函数 得到结果后,把结果作为参数(parseInt(Math.random()*6)+1)传给 f1
function 摇骰子(fn){
    setTimeout(()=>{
        fn(parseInt(Math.random()*6)+1)
    },1000)
}
  • 简化
摇骰子(x=>{
    console.log(x)
})
  • 继续简化
摇骰子(console.log)  
//如果参数个数不一致就不能使用这样的简化

7、相关面试题:

  • Why?
  • Because:
  • How

8、总结

  • 异步任务是不能拿到结果的
  • 于是需要传一个回调给异步任务
  • 异步任务完成时,调用回调
  • 调用的时候把结果作为参数