资讯专栏INFORMATION COLUMN

事件循环

imingyu / 1972人阅读

摘要:所以一切版的多线程都是用单线程模拟出来的,一切多线程都是纸老虎事件循环既然是单线程,那就像只有一个窗口的银行,客户需要排队一个一个办理业务,同理任务也要一个一个顺序执行。

1、关于javascript
javascript是一门 单线程 语言,在最新的HTML5中提出了Web-Worker,但javascript是单线程这一核心仍未改变。所以一切javascript版的"多线程"都是用单线程模拟出来的,一切javascript多线程都是纸老虎!
2、javascript事件循环
既然js是单线程,那就像只有一个窗口的银行,客户需要排队一个一个办理业务,同理js任务也要一个一个顺序执行。如果一个任务耗时过长,那么后一个任务也必须等着。那么问题来了,假如我们想浏览新闻,但是新闻包含的超清图片加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?因此聪明的程序员将任务分为两类:

JS分为同步任务和异步任务
同步任务都在主线程上执行,形成一个执行栈
主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件。
一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行

事件循环是通过任务队列的机制来进行协调的。一个 Event Loop 中,可以有一个或者多个任务队列(task queue),一个任务队列便是一系列有序任务(task)的集合;每个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不同源来的则被添加到不同队列。 setTimeout/Promise 等API便是任务源,而进入任务队列的是他们指定的具体执行任务。

宏任务:

macro)task(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,流程如下:
(macro)task->渲染->(macro)task->...
(macro)task主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

微任务:

microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)

运行机制:

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

执行一个宏任务(栈中没有就从事件队列中获取)
执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

流程图如下:

两道题 让你全部理解事件循环

console.log("1")
  setTimeout(function() {
    console.log("2")
    process.nextTick(function() {
      console.log("3")
    })
    new Promise(function(resolve) {
      console.log("4")
      resolve()
    }).then(function() {
      console.log("5")
    })
  })
  process.nextTick(function() {
    console.log("6")
  })
  new Promise(function(resolve) {
    console.log("7")
    resolve()
  }).then(function() {
    console.log("8")
  })
  setTimeout(function() {
    console.log("9")
    process.nextTick(function() {
      console.log("10")
    })
    new Promise(function(resolve) {
      console.log("11")
      resolve()
    }).then(function() {
      console.log("12")
    })
  })
  
  第二题
async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
}
async function async2() {
    console.log("async2");
}
console.log("script start");
setTimeout(function() {
    console.log("setTimeout");
}, 0)
async1();
new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});
console.log("script end");

注意:
async function async1() {                        
    console.log("async1 start");
    await async2();                   
    console.log("async1 end");
}
等同于
async function async1() {
    console.log("async1 start");
    Promise.resolve(async2()).then(() => {
            console.log("async1 end");
    })
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102480.html

相关文章

  • JavaScript事件循环(Event Loop)

    摘要:事件循环的顺序,决定代码执行的顺序。输出第二轮事件循环正式结束三第三轮事件循环第三轮事件循环从宏任务开始。记为遇到,立即执行回调函数放入中注册,然后被分发到微任务事件队列中。 1、为什么要有事件循环? 因为js是单线程的,事件循环是js的执行机制,也是js实现异步的一种方法。 既然js是单线程,那就像只有一个窗口的银行,客户需要排队一个一个办理业务,同理js任务也要一个一个顺序执行。如...

    dmlllll 评论0 收藏0
  • [译]事件循环,Node.js背后的核心概念

    摘要:事件处理器,则是当指定事件触发时,执行的一段代码。事件循环以一个无限循环的形式启动,存在于二进制文件里函数的最后,当没有更多可被执行的事件处理器时,它就退出。 前言 如果你了解过Node.js,那么你一定听说过事件循环。你一定想知道它为什么那么特殊,并且为什么你需要关注它?此时此刻的你,可能已经写过许多基于Express.js的后端代码,但没有接触到任何的循环。 在下文中,我们会先在一...

    Meils 评论0 收藏0
  • 浅谈不同环境下的JavaScript执行机制 + 示例详解

    摘要:如果没有其他异步任务要处理比如到期的定时器,会一直停留在这个阶段,等待请求返回结果。执行的执行事件关闭请求的,例如事件循环的每一次循环都需要依次经过上述的阶段。因此,才会早于执行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任务(Synchronous) 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务 ...

    wanghui 评论0 收藏0
  • 由setTimeout和setImmediate执行顺序的随机性窥探Node的事件循环机制

    摘要:问题引入接触过事件循环的同学大都会纠结一个点,就是在中和执行顺序的随机性。当队列被执行完,或者执行的回调数量达到上限后,事件循环才会进入下一个阶段。嵌套的在下一个事件循环的阶段执行回调输出嵌套的。 问题引入 接触过事件循环的同学大都会纠结一个点,就是在Node中setTimeout和setImmediate执行顺序的随机性。 比如说下面这段代码: setTimeout(() => { ...

    marek 评论0 收藏0
  • Node中的事件循环

    摘要:的事件循环一个线程有唯一的一个事件循环。索引就是指否还有需要执行的事件,是否还有请求,关闭事件循环的请求等等。先来看一下定义的定义是在事件循环的下一个阶段之前执行对应的回调。虽然是这样定义的,但是它并不是为了在事件循环的每个阶段去执行的。 Node中的事件循环 如果对前端浏览器的时间循环不太清楚,请看这篇文章。那么node中的事件循环是什么样子呢?其实官方文档有很清楚的解释,本文先从n...

    lwx12525 评论0 收藏0
  • NodeJS架构 - 单线程事件循环模型

    摘要:客户端可能需要等待服务器释放可用的线程去处理其请求处理阻塞式的任务时浪费时间的架构单线程事件循环不遵循请求响应多线程无状态模型。它采用单线程与事件循环模型。 showImg(https://segmentfault.com/img/remote/1460000017402136); 这篇译章探究了NodeJS的架构和单线程事件循环模型。我们将在本文中讨论NodeJS如何在底层工作,它遵...

    leap_frog 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<