看js书籍时看到宿主环境和执行环境,一下子有点懵,所以去查了一下,做个笔记~
js运行环境
js运行环境一般是由宿主环境和执行期环境共同构成。
宿主环境一般是由客户端浏览器这种外壳程序(只要能提供js引擎执行的环境都可以算作是外壳程序)生成的;
宿主环境会创建一套公共对象系统以供所有的脚本语言使用,同一个宿主环境可以装在不同的脚本引擎。
执行期环境则是由js引擎(js解释器)生成。
js执行机制
任务队列
所有任务可以分为两种:同步任务、异步任务或宏观任务、微观任务
同步任务:在主线程上排队执行的任务,前一个执行完毕才会执行下一个任务
异步任务:进入任务队列(event queue)的任务,只有任务队列通知主线程某个异步任务可以执行了,该任务才会进入主线程执行。
按照同步任务和异步任务的分类方式,js的执行机制为:
1.首先判断js是同步还是异步,同步就进入主线程执行,形成一个执行栈,异步就进入event table
2.异步任务在event table中注册函数,当满足触发条件后,被推入event queue。
3.同步任务进入主线程之后一直执行,直到所有同步任务执行完毕主线程空闲时才会去event queue中查看是否有可执行的异步任务,如果有,则推入主线程执行。
4.主线程循环第三步(也就是事件循环----event loop)
这里提到执行栈和执行队列,简单的提一下什么是栈,什么是队列:
栈和队列都是一种数据结构,栈就像是个盒子,只有一个进出口,其特点是先进后出。就像你做罐头,最下面的是最先放进去的,也是最后才能吃到的。
队列就像我们排队,特点是先进先出。就像你去银行排队取钱,先排到的人先取钱,后面的轮到你了之后你才能进行操作。
按照宏观任务和微观任务的分类方式,js的执行机制为:
1。执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的事件队列里
2.当前宏任务执行完之后,再去查看微任务的事件队列,并将里面全部的微任务一次执行完成。
简言之:先执行宏任务,完了之后再去事件队列查看并执行微任务。
补充:
宏观任务—宿主发起的任务 包括整体代码script、setTimeout、setInterval
微观任务—JS引擎发起的任务 包括promise,
事件和回调函数
回调函数:被主线程挂起来的代码。
异步任务必须指定回调函数,当主线程开始执行异步任务就是执行对应的回调函数
主线程的读取过程基本是自动的,由于存在定时器,主线程首先要检查一下执行时间,某些事件只有到了规定的时间才能返回主线程。
定时器
任务队列除了放置异步任务还可以放置定时事件。
定时器(timer):定时执行代码
定时器功能主要有两个函数来完成:setTimeOut()和setTImeInterval()
二者运行机制完全一样,区别在于前者指定的代码一次性执行,后者则为反复执行。
HTML5规定setTImeout的最短间隔不得低于4ms(低于4ms的按4ms计算),对于DOM的变动(页面重新渲染的部分)通常不会立即执行,而是每16毫秒执行一次。(可用requestAnimationFrame()替代)
注意:setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行
大佬链接:
https://segmentfault.com/a/1190000012806637
http://www.ruanyifeng.com/blog/2014/10/event-loop.html