同步与异步、异步与回调

同步与异步:

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

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

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

首先执行函数a,并且不等setTimeout执行就执行函数c,等待至少1s的时候后才会执行函数b.实际上在是等待了1s后将函数b放到了event queue里面,此时要等待主线程空闲的时候,才会取event queue里面等待的回调函数进行执行。html

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

关于js的异步实现请看下面的list:
谈谈javascript的异步实现ajax

回调:

回调函数:在js里面简单点来讲,就是函数被看成参数传入另一个函数当中,并在那个函数中被调用。编程

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

异步与回调:

你们可能平时听的比较多的是异步回调,可是必须搞清楚,异步与回调并无直接的联系,回调只是异步的一种实现方式。
固然还有同步回调,即上面回调部分举的简单的例子。通常使用回调函数主要是将父函数的执行结果通知给回调函数进行处理。segmentfault

关于异步个人理解是:浏览器

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

异步任务 是指js在主线程(stack)运行的过程中,当stack空闲的时候,主线程对event queque轮询(事实上一直在轮询)后,将异步任务放到stack里面进行执行。简单点说,只要指定过回调函数,那么当这些事件发生的时候就会进入事件队列,等待主线程的stack空闲的时候,就会对event queue里面的回调读取并放到stack里面执行。异步

看一段ajax实现的代码:async

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

这里ajax请求是异步的,由于浏览器会新开一个线程请求,当请求的状态(readystate)发生改变,由于以前就设置了回调函数,每次状态发生改变都会调用相应的回调函数,当(xhr.readystate === 4 && xhr.status === 200)的时候,回调函数进入了event queue,等待主线程空闲的时候,而且event queue里面排在这个回调前面没有其余回调的时候就会获得执行。

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

所以在异步编程当中,须要注意几个地方:

  • 须要把依赖于异步函数(须要其执行结果或者达到某种状态)的代码放在对应的回调函数中(例如上面的ajax的例子)

  • 异步函数后面的代码会当即执行(所以须要知道某段代码是否为异步的)

另外还有一个关于script标签异步加载的内容:
你们记得请求远程脚本标签吗?

<script src='xxxx' async></script>

在script标签里面加入了async属性或者defer属性后,一样变成了异步了。
关于这部分的内容,请移步:
async和defer的区别

另外关于这部分的内容还有一些List:
并发模型与event loop
朴灵评阮老师的event loop