同步,异步,回调

141 阅读3分钟

参考资料

大家有时间可以看看,都是不错的文章

单线程

js是单线程的,同时只能执行一个任务,其他任务必须排队等待。

好处是执行环境相对单纯,坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 JavaScript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

同步与异步

function a(){}
function b(){}

a()
b()

同步代码,函数b必须等函数a执行完毕后才能执行。

function a(){
  setTimeout(function(){
    b();
  }, 1000);
};
function c(){};
    
a();
c();

执行函数a,不等setTimeout就执行函数c,等待至少1s后执行函数b。

以上就是一段简单的异步代码,js里面最基础的异步实现就是调用setTimeout,setInterval

常见的异步

  • 事件函数
  • Ajax
  • 定时任务

回调函数

函数被当作参数传入另一个函数,并在那个函数中被调用,就是回调函数。

var b = function (){
  //执行相关的代码
}
var a = function (b){
  //执行相关的代码
  b();
}
    
a(b);

可以说b是a的回调函数

回调可以拿到同步与异步的结果,一般使用回调函数主要是将父函数的执行结果通知给回调函数进行处理。

异步与回调

异步与回调并没有直接的联系,回调只是异步的一种实现方式。

因为js是单线程的,如果所有的操作(如ajax操作,获取远程的js文件等IO操作)是同步的,遇到那些耗时的操作,后面的程序必然被阻塞不能执行,页面也就失去了响应。因此js采用了事件驱动机制,在单线程模型下,使用异步回调函数的方式来实现非阻塞的IO操作

看一段ajax代码:

var request = XMLHttpRequest()
request.open('POST', url, true);   //第三个参数决定是否采用异步的方式,默认异步true
request.send(data);
request.onreadystatechange = function(){
if(xhr.readystate === 4 && xhr.status === 200){
  ///xxxx
  }
}

这里ajax请求是异步的,因为浏览器会新开一个线程请求,当请求的状态(readystate)发生改变,因为之前就设置了回调函数,所以每次状态发生改变都会调用相应的回调函数。

异步回调产生的结果就是,函数的调用并不直接返回结果,而往往是交给回调函数进行异步处理。

异步操作中,需要注意几个地方:

  • 需要把依赖于异步函数(需要其执行结果或者达到某种状态)的代码放在对应的回调函数中(例如上面的ajax的例子)
  • 异步函数后面的代码会立即执行(因此需要知道某段代码是否为异步的)