下面是关于“理解Javascript_13_执行模型详解”的完整攻略。
1. 理解Javascript执行模型
1.1 什么是执行模型
JavaScript 执行模型是指描述 JavaScript 引擎如何解析和执行 JavaScript 代码的一种方式。简单来说,就是 JavaScript 程序在浏览器中如何被“翻译”成机器能够理解的指令,然后顺序地被执行。
1.2 Javascript的执行顺序
JavaScript 采用单线程执行模型,同一时刻只能执行一个任务,任务按照队列的方式来一次一个地执行。JavaScript 是一门解释型语言。当执行一段 JavaScript 代码时,会按照以下顺序进行解析和执行:
- JavaScript 引擎首先会进行词法分析,将输入的代码文本拆成单个的词法单元。
- 语法分析器会对拆分出来的词法单元进行解析,将语言结构转换为抽象语法树(AST)。
- 解释器会逐行执行抽象语法树。在执行代码的过程中,如果需要执行函数,则先执行函数中的所有代码,然后再返回到调用函数的位置。
1.3 执行上下文
执行上下文是 JavaScript 中非常重要的概念之一,在 JavaScript 程序执行时一直存在。执行上下文可以理解为当前代码被执行时的运行环境。每当 JavaScript 引擎需要执行一段代码时,都会创建一个对应的执行上下文。
JavaScript 的运行环境包括全局执行上下文和函数执行上下文两种情况。全局执行上下文只有一个,由 JavaScript 引擎在页面刷新时自动创建。函数执行上下文在函数被调用时创建,可以有多个。每个执行上下文的生命周期包含三个阶段:创建阶段、执行阶段和销毁阶段。
在创建阶段,JavaScript 引擎会执行以下步骤:
- 创建变量对象:包括函数的所有形参、函数声明、变量声明等。
- 创建作用域链:包括当前函数的作用域和包含该函数的任何父函数的作用域。
- 确定this指向:在函数被调用时根据调用方式来确定this的值。
1.4 Javascript运行位子
在 JavaScript 中,引擎对代码的解析和执行是在两个位置分别进行的。解析阶段由 JavaScript 引擎的编译器负责,执行阶段由 JavaScript 引擎的解释器和执行器负责。
2. 示例说明
2.1 示例一
function func() {
console.log('First');
setTimeout(() => console.log('Second'), 0);
console.log('Third');
}
func();
上面这段代码中,我们调用了一个名为func
的函数。其中的代码包含了一个 setTimeout 函数,该函数是一个异步函数,会在 0 秒之后将参数传给回调函数并将其推入消息队列中。因此在执行的过程中,setTimeout 是在等待一段时间之后才执行回调函数,并且在执行其它代码的同时异步地运行。
当我们执行 func()
函数的时候,JavaScript 引擎首先会在全局作用域中创建变量对象和作用域链。在创建 func
的执行上下文时,JavaScript 引擎会首先在函数作用域中创建变量对象,其中包括函数的参数 arguments
和函数声明 func
。然后在作用域链上添加外部环境的变量对象。接着,JavaScript 引擎会逐行执行函数中的代码,并将 setTimeout 函数的回调函数添加到消息队列中。最终输出First
、Third
和Second
。
2.2 示例二
var flag = false;
setTimeout(() => flag = true, 0);
while (!flag) {}
console.log('done');
上面这段代码包含了一个变量flag
,在 setTimeout 函数中设置flag
的值为 true,然后 0 秒之后将函数添加到消息队列中。紧接着是一个 while 循环,只要flag的值为 false,该循环会一直执行下去,从而阻塞消息队列的处理。在 while 循环结束后,代码会输出done
。
在该代码的执行过程中,我们会发现setTimeout
函数的回调函数一直没有执行。这是因为 while 循环阻塞了消息队列的处理,导致消息队列中的函数不能被执行。在这种情况下,我们可以采用setTimeout与Promise的配合使用来避免循环阻塞。
var flag = false;
new Promise(resolve => {
setTimeout(() => {
flag = true;
resolve();
}, 0);
}).then(() => console.log('done'));
上面这段代码使用 Promise 对setTimeout
函数的回调函数进行了包装,因此在setTimeout
的回调函数执行完成之后才会输出done
。这种写法可以避免循环阻塞。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:理解Javascript_13_执行模型详解 - Python技术站