前言在看callbacks、deferred的过程中常常遇到异步编程的概念,而异步编程又和事件循环机制息息相关,之前对事件循环和异步编程也是一知半解,所以先花点时间整理一下事件循环和异步编程相关的知识。
一、heap、stack、queue堆(heap):对象被分配在一个堆中,一个用以表示一个内存中未被组织的区域。我们知道,函数是第一等对象,同时函数是“可调用的对象”。因此,当函数在被调用之前,javascript引擎会对函数进行编译(词法分析、语法分析、代码生成)的工作。当完成编译时会将函数(这里不限于函数,javascript所有皆为对象,除了undefined、null)放入堆中,分配内存空间,等待执行或调用。
栈 (stack):当函数调用时,会形成一个“执行栈”。
任务队列:(queue):一个 javascript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。当栈拥有足够内存时,从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数(以及因而创建了一个初始堆栈帧)。当栈再次为空的时候,也就意味着消息处理结束。主线程中的所有同步任务执行完毕,再读取任务队列中的异步任务,这个过程是循环不断的。所以,整个的这种运行机制称为event loop(事件循环)。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,后一个任务才会执行;异步任务指的是不进入主线程、而进入任务队列的任务,只有当主线程上的所有同步任务执行完毕之后,主线程才会读取任务队列,开始执行异步任务。
二、理解浏览器中的事件循环 demo1 function a(){ console.log("2"); } console.log("1"); settimeout(a,1000); console.log("3"); //output: //1 //3 //2
demo2 function a(){ console.log("2"); } console.log("1"); settimeout(a,0); console.log("3"); //output: //1 //3 //2
demo1的运行过程大概是这样子的:
- console.log(1) 进入执行栈,输出 1, 执行完成后出栈
- settimeout( a ,1000) 进入执行栈,出栈,同时 1s 后 把 a 放入到异步队列
- console.log(3) 进入执行栈,输出 3, 执行完成后出栈
- 至此同步队列(主线程队列)已经完成,开始查看异步队列里是否还有任务
- a 进入 执行栈,输出2,出栈。
demo2的运行过程大概是这样子的:
- console.log(1) 进入执行栈,输出 1, 执行完成后出栈
- settimeout( a ,1000) 进入执行栈,出栈,同时 立即 把 a 放入到异步队列
- console.log(3) 进入执行栈,输出 3, 执行完成后出栈
- 至此同步队列(主线程队列)已经完成,开始查看异步队列里是否还有任务
- a 进入 执行栈,输出2,出栈。
哪些操作需要放入到异步队列,而哪些操作属于同步队列呢?可以参考下图。更为具体的分类,请看下篇 js事件循环机制(二)
三、参考文章1.深入理解 javascript 事件循环(一)— event loop
2.mdn并发模型与事件循环
3.what the heck is the event loop anyway?
4.javascript 运行机制详解:再谈event loop
以上就是js之事件循环机制概念详解的详细内容。
