微任务

原生js深入理解系列(七)--- 读JavaScript 执行机制的一点小总结

微笑、不失礼 提交于 2020-03-24 20:30:40
3 月,跳不动了?>>> 总结: js的执行机制是:单线程运行,主线程跑任务,线程队列一个一个宏任务来运行,并且把宏任务内的微任务的全部运行完再继续下一个宏任务。 首先是同步执行其次是异步执行 除了广义的同步任务和异步任务,我们对任务有更精细的定义: macro-task(宏任务):包括整体代码script,setTimeout,setInterval micro-task(微任务):Promise,process.nextTick(promise的回调then()是微任务) 主线程里立即执行的是:new promise, promise 语句, console.log 按出现的先后执行 立即执行的执行完后执行同一个宏任务里的微任务队列,微任务依次执行完毕后再继续下一个宏任务。下面请看掘金作者ssssyoki大佬的娓娓道来,为我们彻底的细致的理解js的执行机制。 这一次,彻底弄懂 JavaScript 执行机制 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定的几行代码,我们需要知道其输出内容和顺序。因为javascript是一门单线程语言,所以我们可以得出结论: javascript是按照语句出现的顺序执行的 看到这里读者要打人了

浏览器执行js原理

和自甴很熟 提交于 2020-03-07 18:45:00
在js任务循环机制中,为什么会有宏任务与微任务之分? 是不是大都数前端开发者都会有这样的疑惑,确实,我自己在开发的过程中每次碰到promise,setTimeout,requestAnimationFrame都会去想,在这个执行的过程中到底发生了什么? 解析: 在前端执行一系列任务的时候,渲染进程会创建一个消息队列,在这个消息队列里存放着待执行的任务函数,按照先进先出的原则,依次执行任务函数。因此只要消息队列里有任务,JS执行主线程就会不断的执行消息队列里的任务。这便是js单线程执行js代码的简单原理,当然涉及的深的话,应该还要有IO线程,专门处理新加进来的任务,以及其它进程过来的任务。 但是js执行过程作为一个单线程的执行过程,其实是有缺点的。上面说过了,消息队列是“先进先出”的属性,也就是说放入队列中的任务,需要等待前面的任务被执行完,才会被执行。鉴于这个属性,那js是如何处理高优先级的任务? js是如何处理高优先级的任务? 比如一个典型的场景,DOM节点的变化,增、删,改,如果页面上的一个输入框状态需要实时的映射到页面上。一个通用的设计的是,利用 JavaScript 设计一套监听接口,当变化发生时,渲染引擎同步调用这些接口,这是一个典型的观察者模式,即给这个输入框添加一个变化事件的监听。 但是这个模式有一个问题,就是如果当前的DOM变化非常的频繁,都去执行js任务的话

nextTick实现原理 (vue 05)

我的梦境 提交于 2020-02-28 14:37:47
文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 【2.5.17】 【Vue原理】NextTick - 白话版 nextTick 是 Vue 中比较重要的一部分,源码独立而简短,稍作修改就可以拿出来为你的项目服务, 我已经有在项目中使用了 想必大家写 Vue 项目的时候,应该也有使用过 nextTick 一般我是用在数据渲染完毕之后执行某些操作 this.list = xx,xx,xx this. $nextTick (( ) = > { this.isLoading = false } ) nextTick 按我的理解,就是设置一个回调,用于异步执行 异步执行,比如,就是把你设置的回调放在 setTimeout 中执行,这样就算异步了,等待当时同步代码执行完毕再执行 但是,每设置一个 nextTick 就新建一个 setTimeout 又不实际, 毕竟一个 setTimeout 是异步,两个setTimeout 也是异步,两个都要等在 同步代码执行完毕之后才执行 那我直接只设置一个 setTimeout 不就好了 那一个 setTimeout 怎么执行多个回调呢? 1 存在 回调数组 里。每次调用 nextTick,便往数组里面 push 设置的回调 2 只注册一个 setTimeout,时间为0,用于遍历 回调数组

浅谈Event Loop

六月ゝ 毕业季﹏ 提交于 2020-02-25 22:50:02
众所周知,js是一种单线程语言。为什么是单线程呢?我引用一句烂大街的话:假设js同时有两个线程,一个线程想要在某个dom节点上增加内容,另一个线程想要删除这个节点,这时要以哪个为准呢?当然,多线程有多线程的解决办法,加锁啊,但是这样的话,又会引入锁、状态同步等问题。 js是浏览器脚本语言,主要用途是与用户互动,操作dom,多线程会带来很复杂的同步问题。 好吧,那就单线程吧。但是单线程又带来了单线程的问题,只有一个线程啊,任务要排队执行,如果前一个任务执行时间很长(ajax请求后台数据),后面的任务就都得等着。 Event Loop就出现了,来背单线程的锅。 Event Loop 往下看之前你应该知道栈、队列、同步任务、异步任务、执行栈这些基本概念。 关于执行栈有一篇很详细的文章推荐:JavaScript深入之执行上下文栈 请看下图: js在执行代码时,代码首先进入执行栈,代码中可能包含一些同步任务和异步任务。 同步任务立即执行,执行完出栈,over。 异步任务也就是常见的ajax请求、setTimeout等,代码调用到这些api的时候,WebAPIs来处理这些问题,执行栈继续执行。 异步任务有了运行结果时,(当ajax请求结果返回时),WebAPIs把对应的回调函数放到任务队列。 执行栈为空时来读取任务队列中的第一个函数,压入执行栈。 步骤5不断重复,执行栈为空时

前端面试题(亲身面试经验)

南楼画角 提交于 2020-02-22 14:43:55
  最近面试了一些公司,趁着疫情期间,总结一波。大家可以看看 会有用的。 webpack 1、webpack中entry和output的作用 webpack中的entry标记入口文件,它可以是一个字符串(单入口)或者一个数组(多入口),output用来标记输出,主要有两个属性 path和 filename。其次就是publicPath 和chunkFileName 2、webpack中loader和plugin的作用 loader 用于加载某些资源文件。 因为webpack 本身只能打包commonjs规范的js文件,对于其他资源例如 css,图片,或者其他的语法集,比如 jsx, coffee,是没有办法加载的。 这就需要对应的loader将资源转化,加载进来。loader是用于加载的,它作用于一个个文件上。 plugin 用于扩展webpack的功能。它直接作用于 webpack,扩展了它的功能。当然loader也是变相的扩展了 webpack ,但是它只专注于转化文件。而plugin的功能更加的丰富,而不仅局限于资源的加载。 3、webpack中可以有哪些优化 1、优化Loader的文件搜索范围,指定include、exclude 2、把Babel编译过的文件缓存起来 loader: 'babel-loader?cacheDirectory=ture' 3、懒加载、按需加载

JS的事件循环(Event Loop)

这一生的挚爱 提交于 2020-02-14 01:27:27
说明: Javascript是一门非阻塞单线程脚本语言; 浏览器是多进程的,系统给它的进程分配了资源(CPU、内存),打开 Chrome 会有一个主进程,每打开一个 Tab 页就有一个独立的进程; JavaScript的任务分为同步任务和异步任务,所有的同步任务都会进入到主执行栈(形成一个执行栈execution context stack),等待任务的回调结果进入一种任务队列(task queue),直到主执行栈的任务执行完毕才会执行任务队列的异步任务,异步任务会塞入主执行栈,异步任务执行完毕后会再次进入下一个循环,整个执行过程,我们称为事件循环过程。任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。 macro-task大概包括: script(整体代码) setTimeout setInterval setImmediate I/O UI render micro-task大概包括: process.nextTick Promise Async/Await(实际就是promise) MutationObserver(html5新特性) 整体执行流程图: async/await执行顺序注意: 输出:script start => async2 end => Promise => script end =

宏任务和微任务

梦想的初衷 提交于 2020-02-12 22:49:34
1、宏任务 (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 环境) 2、微任务 microtask (又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说, 在当前task任务后,下一个task之前,在渲染之前 。 所以它的响应速度相比 setTimeout(setTimeout是task) 会更快,因为无需等渲染。也就是说,在某一个 macrotask(宏任务) 执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。 microtask主要包含:Promise.then、MutaionObserver、process.nextTick

vue批量异步更新策略

筅森魡賤 提交于 2020-02-12 14:31:52
异步更新队列 vue高效的秘诀是一套批量,异步的更新策略 在程序中有好多个组件,每个组件对应一个watch实例,在一次事件循环更新周期内,可能有好多数据发生变化,可能每个组件都会变,这时候最好的方式就是将组件批量的一次更新完之后,浏览器再刷新页面,这时候是最高效的做法 概念 事件循环:浏览器为了协调事件处理、脚本执行、网络请求和渲染等任务而制定的一套工作机制。 宏任务:代表一个个离散的、独立工作单元。 浏览器完成一个宏任务,在下一个宏任务执行开始前,会对页面进行重新渲染 。主要包括创建主文档对象、解析HTML、执行主线JS代码以及各种事件如页面加载、输入、网络事件和定时器等。 微任务:微任务是更小的任务,是在当前宏任务执行结束后立即执行的任务。 如果存在微任务,浏览器会清空微任务之后再重新渲染 。微任务的例子有 promise 回调函数(异步回调函数)、DOM发生变化、watch的update函数等。 总结: 在执行一次宏任务之后,看有没有微任务,有微任务,就清空微任务之后浏览器再刷新页面,没有微任务就直接刷新页面 先做同步任务,再做异步任务,把call stack给清空掉 体验一下 vue中的具体实现 异步:只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。 批量:如果同一个 watcher 被多次触发,只会被推入到队列中一次

js 异步执行顺序

柔情痞子 提交于 2020-02-07 01:07:43
1.js的执行顺序,先同步后异步 2.异步中任务队列的执行顺序: 先微任务microtask队列,再宏任务macrotask队列 3.调用Promise 中的resolve,reject属于微任务队列,setTimeout属于宏任务队列 注意以上都是 队列,先进先出。 微任务包括 `process.nextTick` ,`promise` ,`MutationObserver`。 宏任务包括 `script` , `setTimeout` ,`setInterval` ,`setImmediate` ,`I/O` ,`UI rendering`。 在node环境下,process.nextTick的优先级高于Promise,也就是可以简单理解为:在宏任务结束后会先执行微任务队列中的nextTickQueue部分,然后才会执行微任务中的Promise部分。 javascript事件机制 题目1: console.log('script start') async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') } async1() setTimeout(function() { console.log(

【1/33】调用堆栈

你说的曾经没有我的故事 提交于 2020-02-06 03:44:46
33 文章目录 调用栈 JavaScript 引擎 执行上下文 创建执行上下文 变量环境: 执行阶段 javascript事件循环 setTimeout setInterval Promise与process.nextTick(callback) 调用栈 调用栈 是解释器(就像浏览器中的JavaScript解释器)追踪函数执行流的一种机制。当执行环境中调用了多个函数函数时,通过这种机制,我们能够追踪到哪个函数正在执行,执行的函数体中又调用了哪个函数。 拥有 LIFO(后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文。 当 JavaScript 引擎第一次遇到你的脚本时,它会创建一个全局的执行上下文并且压入当前执行栈。每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的顶部。 每调用一个函数,解释器就会把该函数添加进调用栈并开始执行。每一个进入调用栈的都称为 调用帧 。 正在调用栈中执行的函数还调用了其它函数,那么新函数也将会被添加进调用栈,一旦这个函数被调用,便会立即执行。 当前函数执行完毕后,解释器将其清出调用栈,继续执行当前执行环境下的剩余的代码。 当分配的调用栈空间被占满时,会引发 堆栈溢出 。 JavaScript 引擎 谷歌的 V8 引擎: 在这里插入代码片 这个引擎主要由两部分组成: 内存堆:这是内存分配发生的地方 调用栈