2

编译原理

任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)。因此,JavaScript编译器首先会对 var a = 2; 这段程序进行编译,然后做好执行它的准备,并且通常马上就会执行它。

编译一般分为三步:

  • 分词/词法分析(Tokenizing/Lexing)
    这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代

码块被称为词法单元(token)。例如,考虑程序 var a = 2;。这段程序通常会被分解成
为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在
这门语言中是否具有意义。


  • 解析/语法分析(Parsing)

这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法
结构的树。这个树被称为“抽象语法树” (Abstract Syntax Tree,AST)。
var a = 2; 的抽象语法树中可能会有一个叫作VariableDeclaration 的顶级节点,接下
来是一个叫作Identifier(它的值是a)的子节点,以及一个叫作AssignmentExpression
的子节点。AssignmentExpression 节点有一个叫作 NumericLiteral(它的值是 2)的子
节点。


  • 代码生成

将 AST 转换为可执行代码的过程被称为代码生成。这个过程与语言、目标平台等息息
相关。
抛开具体细节,简单来说就是有某种方法可以将var a = 2; 的AST转化为一组机器指
令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在a 中。

单线程

js引擎是单线程的,编译和执行js的线程只有一个。
nodejs和浏览器还有别的线程用于处理其它任务,如处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程。

单线程所以有了事件循环。

消息队列和事件循环

函数调用形成一个栈帧,放入当前执行栈中,帧中包含了当前context需要的参数和局部变量。

堆栈队列.png

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都关联着一个用以处理这个消息的函数。

其它线程将消息放到消息队列,js线程通过事件循环过程去获取消息。

在事件循环期间的某个时刻,运行时从最先进入队列的消息开始处理队列中的消息。为此,这个消息会被移出队列,并作为输入参数调用与之关联的函数。

函数的处理会一直进行到执行栈再次为空为止;然后事件循环将会处理队列中的下一个消息。

异步中的微任务、宏任务

  • 宏任务(task):script,setTimeout,setInterval、setImmediate
  • 微任务(microtask):原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver

执行逻辑很简单,就是先清空当前context的micortask,再执行task

一个例子:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})

Promise.resolve().then(r=>console.log(16))

async function a1(){
    console.log('13')
    await console.log('14')
    console.log('15')
}

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

a1()

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})


识得唔识得啊
117 声望2 粉丝

« 上一篇
js的遍历