异步与回调

146 阅读4分钟

异步与同步

简介

  • 同步:程序在执行某个任务时,必须等待上一个任务执行完毕才能继续执行下一个任务。这种方式下,程序执行的顺序是按照代码的顺序执行,是一种线性的方式。
  • 异步:程序在执行某个任务时,不需要等待上一个任务执行完毕,可以直接继续执行下一个任务。这种方式下,程序执行的顺序是非线性的,可以同时执行多个任务。

判断异步与同步

  • 如果一个函数的返回值在以下三个中,那么这个函数就是异步函数
    • setTimeout
    • AJAX (即 XMLHttpRequest)、
    • AddEventListener

例如在 AJJAX 中: request.send() 之后,并不能直接得到 response。必须等到 readyState 变为 4 后,浏览器回头调用 request.onreadystatechange 函数,我们才能得到 request.response

异步如何知道什么时候可以拿到函数的结果?

两种方法:轮询回调

  • 轮询:
    • 程序通过一定的时间间隔,循环地查询某个状态或条件是否发生,如果发生就进行相应的处理。
  • 回调:
    • 程序将某个函数或方法的执行权交给另外一个函数或方法处理,当处理完成后,再调用原函数或方法。

回调

  • 回调

    • 程序将某个函数或方法的执行权交给另外一个函数或方法处理,当处理完成后,再调用原函数或方法。
  • 回到函数

    • 回调函数是指在一个函数内部调用另一个函数时,将另一个函数作为参数传递,并由另一个函数在合适的时候调用执行的函数。
    • 可理解为写给别人用,自己不用的函数就是回调函数。

例如在AJAX中,request.onreadystatechange 就是写给浏览器调用的。意思就是你(浏览器)回头调一下这个函数。「回头」也有「将来」的意思。

例子:

function f1(x){
  console.log(x)
}
function f2(fn){
  fn('你好')
}
f2(f1)

写了两个函数,f2调用函数f1,给f1传了个参数’你好’后 f1执行打印,在这里f1被f2调用,f1就是回调函数。

异步与回调的关系

  • 异步是指程序在执行某个任务时,不需要等待上一个任务执行完毕,可以直接继续执行下一个任务的一种执行方式。
  • 异步任务可以用到回调函数通知拿结果。回调是处理异步得到结果的一种方式,还有轮询也可以
  • 回调函数一般用在异步里面。但不一定只用在异步任务里。例如array.forEach( n => console.log(n) ) 就是同步回调
  • 异步回调的过程可以看作是:
    • 异步任务不能拿到结果
    • 于是我们传一个回调给异步任务
    • 异步任务完成时调用回调
    • 调用的时候把结果作为参数

异步回调的例子:

有一个关于摇骰子(ytz)的函数,作用是在1s后生成一个随机数。

function ytz(callback) {
  setTimeout(() => {
    const result = parseInt(Math.random() * 6) + 1;
    callback(result);
  }, 1000);
};

function callback(x){console.log(x);};
ytz(callback);

在这个示例代码中,我们将“摇骰子”函数function ytz(callback) {...}的结果通过回调函数callback传递给调用方ytz(callback)。在 ytz 函数内部,我们使用 setTimeout 来安排一个定时器,然后在定时器回调中生成随机数,并将随机数作为参数传递给回调函数。在调用方,我们通过传递一个回调函数的方式来处理 ysz 函数的执行结果,并在回调函数中进行相应的处理。

ytz(){...} 没有返回值 return。箭头函数里有返回值,返回真正的结果。所以这是一个异步函数/异步任务

回调函数是我们在调用 ytz 函数时传入的函数,即 callback。 在 ytz 函数内部,我们通过调用 callback(result) 将 result 把生成的随机数作为参数传递给传入的回调函数。由于这个函数是在定时器回调函数中被调用的,因此它被称为异步回调函数。

代码可以简写成:

function ytz(callback){
  setTimeout(()=>{
    callback(parseInt(Math.random() * 6) + 1);
  },1000);
}

ytz(console.log)