同步与异步、异步与回调

同步与异步:

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

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

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

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

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

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

回调:

回调函数:在js里面简单点来说,就是函数被当作参数传入另外一个函数当中,并在那个函数中被调用。

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

异步与回调:

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

关于异步我的理解是:

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

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

看一段ajax实现的代码:

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

相关文章
相关标签/搜索