深度剖析事件循环机制

线程和异步

进程

当一个应用程序运行时,需要使用内存和CPU资源,这些资源需要向操作系统申请,操作系统以进程的方式来分配这些资源,一个进程就代表着一块其他进程的内存空间

一个应用程序要运行,必须至少有一个进程启动

进程的最大的特点就是独立,一个进程不能随意访问其他进程的资源。这就保证了多个程序在操作系统上运行互不干扰。

线程

任何一个进程在启动的时候,操作系统都会给其分配一个线程,应用程序的入口函数在主线程中运行。

在应用程序的运行过程中,可能有多个任务需要同时执行,于是可以向操作系统申请分配更多的线程来执行不同的任务。

比如,浏览器启动后,会开启多个线程来处理不同的事情。

浏览器进程中的多个线程

  • 执行线程
  • GUI
  • 事件监听
  • 计时
  • 网络

进程与进程之间的资源是隔离的,不共享资源。线程之间的资源不是隔离的,它们可以共享数据,并且线程可以被调度。

<h1 id="title">Bella</h1>
<button onclick="test()">click me</button>
<script>
	function test(){
    	title.innerHTML = "青霞";
    	while(true){}
	}    
</script>

这段代码执行完后页面中的Bella并不能变成青霞,因为while一直在循环,执行线程还没有执行完GUI(渲染)线程是不会开始的。因为浏览器中的执行线程和GUI线程就是被调度为互斥的,当GUI线程执行渲染时,执行线程会被阻塞。

我们所说的 [ JS中是单线程 ] 的语言,是指在宿主环境中,执行JS代码的线程只有一个

面试题

1、怎样理解JS的异步?

JS是一个单线程的语言,意味着宿主仅为其分配了一个执行线程

而在实际的开发中,JS有时需要执行一些耗时的操作,比如等待一个DOM事件发生、等待网络通信完成、等待计时结束等等。如果在执行线程上去等待,就浪费线程的宝贵执行时间,阻塞后续操作。更可怕的是,由于浏览器的GUI线程和JS线程是互斥的,这就导致浏览器界面会JS的等待处于卡死状态。

因此,JS通过异步来解决这个问题,当需要等待的时候,通知宿主的其他线程去做处理,执行线程则继续后续执行。当其他线程完成处理后,会发出通知,此时执行线程转而去执行事先定义好的回调函数即可。

异步的方式充分解放了执行线程,让执行线程可以毫无阻塞的运行,也就避免了浏览器宿主因为等待操作完成出现卡死现象

执行栈

function A(){
    console.log("A");
    B();
}

function B(){
    console.log("B");
}
A();
console.log("global")

//输出顺序为A、B、global
//执行过程为:
/**
	执行栈里面先有一个全局上下文,接着走到A(),创建一个函数调用执行上下文,并且入栈,函数执行的时候会从call stack里取栈顶的执行,接着运行A函数内部,console.log("A");会创建log执行上下文,输出A后,log执行上下文出栈,继续执行A,再创建B函数执行上下文,接着运行......
**/

执行过程

执行栈(call stack):在执行栈中一开始会有全局上下文Global Context(可以认为整个script中的代码),每一次遇见函数调用,就会创建一个新的上下文,叫做函数调用执行上下文。然后入栈(栈的顶端),js执行只会栈顶端的上下文。

面试题
function A(){
    A();
}
A();//报错——会导致执行栈溢出   因为一直在创建A的执行栈上下文
function B(){
    var n = 0;
    while(n>=0){
        n++
    }
}
B();//进入了死循环

事件循环

setTimeout(function func1(){
    console.log(1);
    a();
},0)

function a(){
    setTimeout(function func2(){
        console.log(2)
    },0)
    console.log(3)
}
a();
console.log(4);

执行过程:

先创建全局执行上下文,依次执行代码,创建setTimeout fun1()上下文,时间到了后将其进入执行队列,接着创建a的执行上下文,接着执行a里面的代码,再创建setTimeout func2执行上下文,将其放入执行队列中等待执行,接着输出3,将a函数执行上下文移出call stack,输出4,call stack中已经清空了,最后将执行队列里的任务放到call stack中,先放入 func1,输出1后,再创建a函数执行上下文,再创建setTimeout的执行上下文,最后将setTimeout移入执行队列中,当call stack中空了就会运行执行队列里的代码。

最后输出3、4、1、3、2、2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libevent是一个事件驱动的网络编程库,适用于高并发的网络应用。通过深度剖析libevent源码,我们可以更好地理解其工作原理和实现机制。 首先,在下载libevent源码之前,我们需要确认所需的版本和平台兼容性,这样可以避免不必要的错误和兼容性问题。 在深度剖析libevent源码时,我们可以从以下几个方面入手: 1. 事件循环机制:libevent基于事件循环机制实现事件的响应和处理。源码会包含事件循环的实现细节,如事件的注册、删除、触发等操作。研究这些实现可以帮助我们理解事件驱动模型的运行机制。 2. IO多路复用:libevent在底层使用了IO多路复用技术,可以同时处理多个网络连接,提高并发处理能力。源码会涉及到IO多路复用的实现细节,如select、epoll等。了解这些实现可以帮助我们深入理解libevent是如何高效地管理和处理网络连接的。 3. 常用数据结构和算法:libevent在源码使用了一些常用的数据结构和算法,如链表、堆等。通过研究这些数据结构和算法的实现,可以提高我们对libevent整体架构的理解。 4. 错误处理和调试机制:源码通常也会包含一些错误处理和调试机制,可以帮助我们排查和解决问题。了解这些机制可以提高我们在使用libevent时的调试和排错能力。 总之,深度剖析libevent源码可以帮助我们更好地理解其工作原理和实现机制,从而更好地使用和调优libevent,提高网络应用的性能和并发处理能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值