JS的同步异步

96 阅读3分钟

单线程

        Js是单线程语言,所以Js在同一时间只能做一件事。单线程意味着在同一时间有多个任务时,这些任务就需要排队,等前一个任务执行完才能执行下一个任务。下面的例子定义的两个匿名函数将顺序执行。

+function(){
    console.log(1);
}();
(function(){
    console.log(2);
})();
// 输出结果:
1
2

       从上面这个例子中明显看出Js的顺序执行,但有些时候某个函数的执行需要很长的时间(如文件的读取),这样会造成进程堵塞,异步操作能够很好的解决这一问题。

为什么是单线程:

       JavaScript作为浏览器的脚本语言,主要用来实现与用户的交互,利用JavaScript来操作DOM,如果JavaScript是多线程语言,一个线程在DOM节点上增加内容,另一个线程要删除这个DOM节点,从而造成复杂的同步问题,所以JavaScript是点线程的。

同步异步:

       因为Js是单线程的,所以一次只能执行一个任务,所有任务的执行都需要排队,如果一个任务执行时间很长(如读取文件、ajax请求),此时后面的任务就只能全部等待,例如在进入网页的时候请求了大量的数据导致页面迟迟不渲染,影响用户体验。为了解决这个问题,主线程可以完全不用等待文件读取完成或者ajax请求加载完成,可以先挂起那些处于等待状态的任务,先运行后面的任务,等到文件读取完成或者ajax请求有结果后再回头执行挂起的任务。因此任务就可以分为同步任务和异步任务

​ (1)同步任务:

       同步任务是主线程上排队执行的任务。

​ (2)异步任务

       异步任务是不进入主线程,在任务队列中的任务,只有当任务队列通知主线程该任务可执行了才会进入主线程执行。

       下面例子中setTimeout()让fun2异步执行:

function fun1(){
    console.log(1);
}
function fun2(){
    console.log(2);
}
function fun3(){
    console.log(3);
}

fun1();
setTimeout(()=>{
    fun2();
},0);
fun3();

// 输出:
1
3
2

​ (4)异步机制

image-20230325173235032.png

       JS的异步编程通过执行栈和消息队列来实现。首先所有的同步任务都是在主线程上执行的,它会形成一个执行栈,异步任务不会在主线程上执行,当异步任务得到响应(如某个点击事件、服务加载完成、setTimeout等待时间截止)就会被推入消息队列中。当执行栈里面的任务执行完的时候(栈空),JS引擎就会去消息队列中读取任务,它会把这个任务中的回调函数压入执行栈中,然后执行栈就又开始新的同步任务执行。

       这种执行栈空就去消息队列读取任务的过程时不断循环的,每次栈空都会去消息队列读取任务,如果没有任务就一直等待,知道有新的任务出现,这叫做事件循环(event Loop)。关于Event Loop社区中有很多优秀的文章,大家可以去搜一下。