「ROAD 6」结构化程序设计


JS 执行粒度 Realm

  • JS Context => Realm(粒度比宏任务更大)
  • 宏任务
  • 微任务
  • 函数调用
  • 语句/声明
  • 表达式
  • 直接量/变量/this…

如果使用 GLOBAL 变量对象是不需要用到 Realm。

在 JS 内,函数表达式和对象直接量均会创建对象,使用.做隐式转换也会创建对象,这些对象都是有原型的,如果没有 Realm 我们就不知道它们的原型是什么了。

let x = new Object();
// vs
let y = {};

获取所有 GLOBAL 对象

var objects = [
  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, // 所有主流浏览器均默认于2018年1月5日禁用SharedArrayBuffer
  DataView,
  Float32Array,
  Float64Array,
  Int8Array,
  Int16Array,
  Int32Array,
  Uint8Array,
  Uint16Array,
  Uint32Array,
  Uint8ClampedArray,
  Atomics,
  JSON,
  Math,
  Reflect,
];

var queue = [];
var set = new Set();

while (objects.length) {
  let current = objects.shift();
  if (set.has(current)) continue;
  set.add(current), queue.push(current);

  for (let p of Object.getOwnPropertyNames(current)) {
    let property = Object.getOwnPropertyDescriptor(current, p);
    if (
      property.hasOwnProperty("value") &&
      ((property.value != null && typeof property.value === "object") ||
        typeof property.value === "object") &&
      property.value instanceof Object
    ) {
      set.add(property.value), queue.push(property.value);
    }

    if (property.hasOwnProperty("get") && typeof property.get === "function") {
      set.add(property.get), queue.push(property.get);
    }

    if (property.hasOwnProperty("set") && typeof property.set === "function") {
      set.add(property.set), queue.push(property.set);
    }
  }
}

宏任务&微任务

两个角色:宿主环境和 JS 引擎。

  • 宏任务:宿主发起的任务;
  • 微任务:JS 引擎发起的任务;

JS 是单线程执行的。

宏任务内部会有一个微任务列表,在执行下一个宏任务之前,会把上一个宏任务内的微任务全部完成。

分析异步执⾏的顺序:

  • ⾸先我们分析有多少个宏任务
  • 在每个宏任务中,分析有多少个微任务;
  • 根据调⽤次序,确定宏任务中的微任务执⾏次序;
  • 根据宏任务的触发规则和调⽤次序,确定宏任务的执⾏次序;
  • 确定整个顺序。
setTimeout(() => {
  console.log(this.a);
}, 0);
new Promise((resolve) => resolve()).then(() => (this.a = 3));
// 3

思考下面代码的执行顺序:

async function foo() {
  console.log(-2)
  await new Promise(resolve => resolve());
  console.log(-1)
}
new Promise(resolve => (console.log(0), resolve())).then(() => {
  console.log(1);
  new Promise(resolve => resolve()).then(() => console.log(1.5));
})
setTimeout(() => {
    console.log(2);
    new Promise(resolve => resolve()).then(() => console.log(3))
}, 0)
console.log(4)
console.log(5)
foo()˛

会先在一个微任务内执行完所有的同步代码。

宏任务 1:

  • 微任务 1:0,4,5,-2(同步代码)
    • 入队:1,-1
  • 微任务 2:1
    • 入队:1.5
  • 微任务 3:-1
  • 微任务 4:1.5

宏任务 2:

  • 微任务 1:2
  • 微任务 2:3

函数调用(Execution Context)

执行上下文栈(Execution Context Stack)

在函数调用时会进行栈 push,函数执行完毕就会 pop。

  • code evaluation state
  • Function
  • Script or Module
  • Generator
  • Realm
  • Lexical Environment(词法环境)
  • Variable Environment(变量环境)

Lexical Environment

  • this(箭头函数声明的时候就被绑定了?)
  • new.target
  • super
  • 变量

Variable Environment

历史遗留包袱,仅仅用于处理 var 声明。

Environment Record

拓展

在 js 内,逗号表达式永远只返回最后一个值。

let param = 1, 2, 3;
console.log(param) // 3

let param2 = 1, function() {return this.q};
console.log(param2) // function

文章作者: 阿汪同学
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 阿汪同学 !
评论
  目录