Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 在浏览器中的事件循环 #24

Open
plh97 opened this issue Apr 11, 2018 · 0 comments
Open

JavaScript 在浏览器中的事件循环 #24

plh97 opened this issue Apr 11, 2018 · 0 comments
Assignees
Labels
javaScript 关于js的一些事 博客 写一些前端技术记录 学习 如果不学习,那今天和昨天又有什么区别 看书 其实如果不看书的话,那么每天写的东西都和昨天一样,又有什么意思

Comments

@plh97
Copy link
Owner

plh97 commented Apr 11, 2018

关于js事件

你应该看看image

什么是call stack(调用栈)

  • queues: 先入先出(js和settimeout和gui和时间等线程按照队列形式执行,即先入先出顺序)
  • stack: 后入先出(而调用栈则按照后入先出的顺序依次执行,明白这个道理对后续的异步函数学习很有帮助)

所有被调用的js函数都会被放入栈,按照后入先出的顺序依次执行。理解这个对于理解js异步函数非常重要。JavaScript(引擎)是单线程的,Event loop并不属于JavaScript本身,但JavaScript的运行环境是多线程/多进程的,运行环境实现了Event loop。,js的单线程执行完美避开了GUI(css图形界面渲染)冲突,但同时js的运行环境又是多线程的,常见的线程有js主线程,GUI图形界面绘制进程,点击事件等进程,setTimeout/setInterVal时间进程,这么多进程共同协作,才构成了js灵活多变的浏览器操作。这样的设计异常巧妙。而html5又加入了web worker,但它是另一个进程,和我们所讨论的互不干涉,es6又加入了promise.then,但是promise真的不属于多线程,promise内部原理我是理解不了。
但是请看下图,

  • 1.最先被调用的是正常的js闭包只执行代码。
  • 2.排第二的是nodejs里面的process.nextTick()。
  • 3.排第三的则是promise().then()返回的代码,你可以将他理解做另一个线程,但他一定排在setTimeout线程前面。
  • 4.再就是js标准里面的setTimeout了,他就是另一个线程。
  • 5.再就是nodejs里面的setImmediate,他被放在了最后。

image

再次科普一下promise setTimeout

  • 宏任务主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、setImmediate(Node.js 环境)
  • 微任务主要包含:Promise、MutaionObserver、process.nextTick(Node.js 环境)

我们的JavaScript的执行过程是单线程的,所有的任务可以看做存放在两个队列中——执行队列和事件队列。

执行队列里面是所有同步代码的任务,事件队列里面是所有异步代码的宏任务,而我们的微任务,是处在两个队列之间。

当JavaScript执行时,优先执行完所有同步代码,遇到对应的异步代码,就会根据其任务类型存到对应队列(宏任务放入事件队列,微任务放入执行队列之后,事件队列之前);当执行完同步代码之后,就会执行位于执行队列和事件队列之间的微任务,然后再执行事件队列中的宏任务。

为了再次深入了解promise 和 settimeout和setImmediate,请查看如下代码

image
😴醉了,根本不是线程的问题,promise内部是保证一定完成,才进行下一步,所以必须先将promise内部函数执行完毕,才进行then后的函数,而then则属于微任务,所以它不是setTimeout和setImmediate这种宏任务的的对手,setTimeout线程位于setImmediate线程后面,所以then里面setImmediate先执行,setTimeout后执行

再看一个例子

我将promise命名一个字面量,输出的结果却又不一样了。真令人困惑。promise被分叉成两个.then
image
同样的函数我执行5次,如下图,居然发现输出结果不一致,为什么呢???
image
发现规律就是1永远排在最前面,246为一组,35为一组,这两组不定期排序。。本身是不是说明了事情就是promise的这两个单独的then让promise分叉了,任意时间返回结果。。。但是35是setTimeout线程,而246则是setImmediate线程,settimeout线程不是永远应该排在setImmediate后面么。。。

从 Error看 调用栈 call stack

如图,请认真查看这个报错的stack trace栈追踪,事件执行顺序依然是 foo -> bar -> baz -> object,而这条追踪对应的是error发生的时候记录的栈追踪,非常有意思。
image
当我用node去调用他的时候,没有发生任何变化。
image
浏览器的报错栈树,最外层的anonymous则是最外层我们调用js本身的main.js,这属于浏览器的栈追踪。
image

从调用自身查看stack调用

老司机应该经常看到这种报错,超过最大限量的栈调用
image

Reference:

@plh97 plh97 self-assigned this Apr 11, 2018
@plh97 plh97 added 学习 如果不学习,那今天和昨天又有什么区别 博客 写一些前端技术记录 看书 其实如果不看书的话,那么每天写的东西都和昨天一样,又有什么意思 javaScript 关于js的一些事 labels Apr 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
javaScript 关于js的一些事 博客 写一些前端技术记录 学习 如果不学习,那今天和昨天又有什么区别 看书 其实如果不看书的话,那么每天写的东西都和昨天一样,又有什么意思
Projects
None yet
Development

No branches or pull requests

1 participant