JavaScript 结构化 Structure

结构化(一)

事件循环&宏任务&微任务

  • 事件循环是什么?

    事件循环是浏览器执行任务的机制,它会不断循环判断消息队列中是否有任务,队列中的任务都是指宏任务,而宏任务中包含微任务队列,在宏任务结束前后执行微任务队列,直到微任务队列中为空才结束这个宏任务。

  • 宏任务是什么?

    • 渲染事件(如解析 DOM、计算布局、绘制);
    • 用户交互事件(如鼠标点击、滚动页面、放大缩小等);
    • JavaScript 脚本执行事件;网络请求完成、文件读写完成事件。 为了协调这些任务有条不紊地在主线程上执行,页面进程引入了消息队列和事件循环机制,渲染进程内部会维护多个消息队列,比如延迟执行队列和普通的消息队列。然后主线程采用一个 for 循环,不断地从这些任务队列中取出任务并执行任务。我们把这些消息队列中的任务称为宏任务。
  • 微任务是什么?

    微任务就是一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前。

    • 微任务和宏任务是绑定的,每个宏任务在执行时,会创建自己的微任务队列。
    • 微任务的执行时长会影响到当前宏任务的时长。比如一个宏任务在执行过程中,产生了 100 个微任务,执行每个微任务的时间是 10 毫秒,那么执行这 100 个微任务的时间就是 1000 毫秒,也可以说这 100 个微任务让宏任务的执行时间延长了 1000 毫秒。所以你在写代码的时候一定要注意控制微任务的执行时长。
    • 在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务执行。

其实所有的JS代码都是一个微任务,只是哪些微任务构成了一个宏任务;执行在JS引擎里的就是微任务,执行在JS引擎之外的就是宏任务,循环宏任务的工作就是事件循环。

事件循环不属于JavaScript引擎实现的东西,而是由浏览器或node js宿主环境实现的

script标签、UI交互、setTimeout、setInterval都会创建宏任务

一个宏任务只存在一个微任务队列,微任务根据入队时间顺序执

Promise的then方法以及async函数里的await会将一个微任务入队

宏任务&微任务执行顺序 实验代码

代码

async function afoo(){
    console.log("1");
    await new Promise(resolve => resolve());
    console.log("2");
}
new Promise(resolve => (console.log("3"), resolve()))
    .then(()=>(
        console.log("4"), 
        new Promise(resolve => resolve())
            .then(() => console.log("5")) ));

setTimeout(function(){
    console.log("6");
    new Promise(resolve => resolve()) .then(console.log("7"));
}, 0);
console.log("8");
console.log("9");
afoo();

// 3
// 8
// 9
// 1
// 4
// 2
// 5
// 6
// 7

解析:

  • 解析:
    • 第一个宏任务:
      • 3
        • 入队 4
      • 8
      • 9
      • 1
        • 入队 2
      • 4
        • 入队 5
      • 2
      • 5
    • 第二个宏任务:
      • 6
        • 入队 7
      • 7

结构化(二)

从上到下

  • JS Context => Realm
    • Realm1 Realm2 ... 都会创建一套
      • global
        • Infinity NaN undefined Array Objecy Date ...
  • Macro
  • Micro
  • 函数调用(Execution Context)
  • Statement
  • Expression
  • 直接量/变量/this

Realm

对象分类

  • 宿主对象 (Host Objects): JavaScript 宿主环境提供的对象

    • window
      • 一部分来自 js
      • 一部分来自 浏览器
  • 内置对象 (Build-in Objects): JavaScript 语言提供

    • 固有对象 (Intrinsic Objects): 标准规定,随着 JavaScript 运行时创建而自动创建的对象实例

      • js 执行前就创建,类似基础库
    • 原生对象 (Native Objects): 用户通过 Array RegExp 等内置构造器或特殊语法创建

      native-objects

      • 可以 new 创建新的对象
      • 无法通过 class/extend 或 纯 js 代码实现
      • 这些构造器创建的对象使用了 私有字段,无法被原型继承
    • 普通对象 (Ordinary Objects): 由 {} Object 构造器 或 class 创建,能够被原型继承

对象模拟函数和构造器

通过 私有字段 模拟

  • 函数对象
    • [[call]]
  • 构造器对象
    • [[construct]]

实现 [[call]] 和 [[construct]] 行为不一致

new Date() // object
Date() // string

new Image() // object
Image() // error

function 或 Function 构造器创建,[[call]] 和 [[construct]] 行为相似

function f() {
  return 1
}
f() // [[call]]
new f() // [[constuct]]

[[construct]] 执行过程

  • 以 Object.prototype 创建新对象
  • 以 新对象 为 this,调用 [[call]]
  • [[call]] 返回对象,或 返回 新对象

获取全部固有对象

标准中全部对象的定义,规定了以下全局对象的属性。查找这些对象的 属性 和 Getter/Setter,就可以获得所有 固有对象

  • 三个值
    • Infinity
    • NaN
    • undefined
  • 九个函数
    • eval
    • isFinite
    • isNaN
    • parseFloat
    • parseInt
    • decodeURI
    • decodeURIComponent
    • encodeURI
    • encodeURIComponent
  • 一些构造器
    • Array
    • Date
    • RegExp
    • Promise
    • Proxy
    • Map
    • WeakMap
    • Set
    • WeakSet
    • Function
    • Boolean
    • String
    • Number
    • Symbol
    • Object
    • Error
    • EvalError
    • RangeError
    • ReferenceError
    • SyntaxError
    • TypeError
    • URIError
    • ArrayBuffer
    • SharedArrayBuffer
    • DataView
    • Typed Array
    • Float32Array
    • Float64Array
    • Int8Array
    • Int16Array
    • Int32Array
    • UInt8Array
    • UInt16Array
    • UInt32Array
    • UInt8ClampedArray
  • 四个用于当作命名空间的对象
    • Atomics
    • JSON
    • Math
    • Reflect

函数调用(Execution Context)

执行栈

  execution context2 // running execution context
  execution context1
  execution context0
execution context stack
  • execution context
    • code evaluation state 代码执行位置
      • async await generator
    • Function
      • context 为函数
      • 全局 script 是 null
    • Script/Module
      • 同上
    • Generator
      • generator 产生的,否则是 null
    • Realm
    • LexicalEnvironment
      • 词法环境,获取变量值时用到的
    • VirableEnvironment

LexicalEnvironment

  • this
    • 2019 版本,老版在 context
  • new.target
  • super
  • 变量

VirableEnvironment

历史包袱,处理 var 声明

Environment Record

链表结构

  • Environment Record
    • Declarative Environment Record
      • Function Environment Record
      • Module Environment Record
    • Global Environment Record
    • Object Environment Record
      • with eval

Function Closure

Function: foo
  Environment Record
    y:2
  Code
    console.log(y)
var y = 2
function foo() {
  console.log(y)
}
foo()

嵌套的 Environment

Function: foo3
  Environment Record ---> Environment Record
    x:3                     y:2
  Code
    console.log(y,x)
var y = 2
function foo() {
  var x = 3
  return function foo3() {
    console.log(y, x)
  }
}
foo()

箭头函数,附加 this

Function: foo3
  Environment Record ---> Environment Record
    x:3                     y:2
    this: global
  Code
    console.log(y,x)
var y = 2
function foo() {
  var x = 3
  return () => {
    console.log(y, x)
  }
}
foo()

Realm

var o = new Object() // 不需要 realm,当前 realm 的 lex env 中可以获取到
var o = {} // 需要 realm,比如 别的 iframe 中的 {} 的不是当前的 Object 实例,所以需要确定在哪个 realm
Object.getPrototypeOf({}) === Object.prototype
原文地址:https://www.cnblogs.com/ssaylo/p/13099263.html