Symbol的应用场景
应用场景1:使用Symbol来作为对象属性名(key)
1 | let obj = { |
由上代码可知,Symbol类型的key是不能通过Object.keys()或者for…in来枚举的,它未被包含对象自身的属性名集合(property names)之中。所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。
应用场景2:使用Symbol来替代常量
1 | const TYPE_AUDIO = 'AUDIO' |
如上面的代码中那样,我们经常定义一组常量来代表一种业务逻辑下的几个不同类型,我们通常希望这几个常量之间是唯一的关系,常量少的时候还算好,但是常量一多,你可能还得花点脑子好好为他们取个好点的名字。
现在有了Symbol,我们大可不必这么麻烦了:
1 | const TYPE_AUDIO = Symbol() |
应用场景3:使用Symbol定义类的私有属性/方法
使用的少
彻底搞懂浏览器Event-loop
1. 预备知识
1 | JavaScript的运行机制 |
(1) 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2) 主线程之外,还存在”任务队列”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3) 一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4) 主线程不断重复上面的第三步
概况就是:调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作。
1 | JavaScript中有两种异步任务: |
- 宏任务:script(整体代码),setTimeout、setInterval、setImmediate、I/O、UI rendering
- 微任务:process.nextTick(Nodejs)、Promise、Object.observe、 MutationObServer
2. 事件循环(event-loop)是什么?
主线程从”任务队列”中读取执行事件,这个过程是循环不断的,这个机制被称为事件循环。此机制具体如下:主线程会不断从任务队列中按顺序读取任务执行,每执行一个任务都会检查microtask队列是否为空(执行完一个任务的具体标志是函数执行栈为空),如果不为空则会一次性执行完所有microtask。然后进入下一个循环去任务队列中取下一个任务执行。
当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件, 然后再去宏任务队列中取出一个事件。同一次事件循环中, 微任务永远在宏任务之前执行。
3. 为什么会需要event-loop?
因为 JavaScript 是单线程的。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking)等,用户代理(user agent)必须使用事件循环(event loops)。
node中的event-loop与浏览器之间的差异
浏览器和 Node 环境下,microtask 任务队列的执行时机不同
- Node 端,microtask 在事件循环的各个阶段之间执行
- 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行
1 | console.log('start') |