异步与同步
简介
- 同步:程序在执行某个任务时,必须等待上一个任务执行完毕才能继续执行下一个任务。这种方式下,程序执行的顺序是按照代码的顺序执行,是一种线性的方式。
- 异步:程序在执行某个任务时,不需要等待上一个任务执行完毕,可以直接继续执行下一个任务。这种方式下,程序执行的顺序是非线性的,可以同时执行多个任务。
判断异步与同步
- 如果一个函数的返回值在以下三个中,那么这个函数就是异步函数
- 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)