详解JavaScript的进程和线程,js为什么是单线程,js的异步执行原理

进程:是cpu资源分配的最小单位,是能拥有资源和独立运行的最小单位。拥有独立的地址空间。
线程:是cpu调度的最小单位,安排CPU执行的最小单位。同一个进程下的所有线程,共享进程的地址空间。(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

进程和线程的关系

  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
  • 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
  • 处理机分给线程,即真正在处理机上运行的是线程。
  • 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体。
  • 线程是在进程内部工作,而进程负责向外界输出。
  • 一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
  • 不同进程之间也可以通信,不过代价较大

线程的优点

  • 易于调度。
  • 提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
  • 开销少。创建线程比创建进程要快,所需开销很少。。
  • 利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行

单线程

单线程就是一个进程中只有一个线程。程序顺序执行,前面的执行完,才会执行后面的程序。

JS为什么是单线程的

现在有2个进程,process1 process2,由于是多进程的JS,所以他们对同一个dom,同时进行操作。process1 删除了该dom,而process2 编辑了该dom,这样会对浏览器同时下达两个矛盾的命令,这是不合理的

JS为什么需要异步

如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验

JS单线程又是如何实现异步

    console.log(1)
    
    setTimeout(function(){
        console.log(2)
    },0)
 
    console.log(3)

上述代码会依次输出 1 3 2

由于Js的执行机制只要主线程空了,就会去读取任务队列导致的,js中所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

  • 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  • 主线程之外,还存在一个任务队列(event queue)。只要异步任务有了运行结果,就在任务队列之中放置一个事件。
  • 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列(event queue),看看里面有哪些异步任务可以执行,进入执行栈,开始执行。
  • 主线程不断重复上面的第三步。(event loop)

事件和回调函数

任务队列是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在任务队列中添加一个事件,表示相关的异步任务可以进入执行栈了。主线程读取任务队列,就是读取里面有哪些事件。

任务队列中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入任务队列,等待主线程读取。

所谓回调函数(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。

任务队列是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,任务队列上第一位的事件就自动进入主线程。但是,由于存在后文提到的定时器功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。

定时器执行的过程

定时器功能主要由setTimeout()和setInterval()这两个函数来完成。它们的内部运行机制完全一样,区别在于前者指 
定的代码是一次性执行,后者则为反复执行。以下主要讨论setTimeout()。

console.log(1)
setTimeout(function () {
   console.log(2) 
}, 2000)
console.log(3)

上面代码的执行结果是1,3,2,因为setTimeout()将第二行推迟到2000毫秒之后执行

如果将setTimeout()的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后,立即执行(0毫秒间隔)指定的回调函数。setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在”任务队列”的尾部添加一个事件,因此要等到同步任务和”任务队列”现有的事件都处理完,才会得到执行。

HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。

需要注意的是,setTimeout()只是将事件插入了任务队列,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

从哪里可以得出javaScript是单线程

比如你页面一上来就alert(“hello world~”);只要你不关闭这个对话框,后续的js代码就不会再执行。因为,单线程就是这样一步一步的顺次执行,前面不执行完,后面不会执行。也就是说,在具体的某一时刻,只有一段代码在执行。

多线程
多线程就是一个进程中只有多个线程。在进程内部进行线程间的切换,由于每个线程执行的时间片很短,所以在感觉上是并行的。

多线程优点

  • 使用线程可以把占据时间长的程序中的任务放到后台去处理
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。

多线程的缺点

  • 如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
  • 更多的线程需要更多的内存空间。
  • 线程可能会给程序带来更多“bug”,因此要小心使用。
  • 线程的中止需要考虑其对程序运行的影响。
  • 通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。
  • 系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wflynn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值