add file:js运行机制
This commit is contained in:
parent
7482016d39
commit
9e1121d7c5
@ -19,7 +19,7 @@
|
||||
本文接下来讲渲染机制。
|
||||
|
||||
|
||||
**渲染机制:**
|
||||
**渲染机制**包括的内容:
|
||||
|
||||
- 什么是DOCTYPE及作用
|
||||
|
||||
@ -88,21 +88,21 @@ PS:该DTD包含所有的HTML元素和属性,但包括展示性的和弃用
|
||||
浏览器的渲染过程非常复杂,但是面试只用说几句话就行了,不然太耗时间。如何快速简洁地描述清楚,是关键。
|
||||
|
||||
|
||||
20180310_1257.png
|
||||
![](http://img.smyhvae.com/20180310_1257.png)
|
||||
|
||||
这里先解释一下几个概念,方便大家理解:
|
||||
|
||||
DOM Tree:浏览器将HTML解析成树形的数据结构(DOM 树)。
|
||||
- DOM Tree:浏览器将HTML解析成树形的数据结构(DOM 树)。
|
||||
|
||||
CSS Rule Tree:浏览器将CSS解析成树形的数据结构。
|
||||
- CSS Rule Tree:浏览器将CSS解析成树形的数据结构。
|
||||
|
||||
Render Tree: DOM和CSSOM合并后生成Render Tree。(虽然有了Render Tree,但并不知道节点的位置,需要依靠接下来的layout)
|
||||
- Render Tree: DOM和CSSOM合并后生成Render Tree。(虽然有了Render Tree,但并不知道节点的位置,需要依靠接下来的layout)
|
||||
|
||||
layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去**计算出每个节点在屏幕中的位置**(宽高、颜色等)。
|
||||
- layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去**计算出每个节点在屏幕中的位置**(宽高、颜色等)。
|
||||
|
||||
painting: 按照算出来的规则,通过显卡,把内容画到屏幕上。
|
||||
- painting:按照算出来的规则,通过显卡,把内容画到屏幕上。
|
||||
|
||||
display:打击看到的最终效果。
|
||||
- display:打击看到的最终效果。
|
||||
|
||||
参考链接:
|
||||
|
248
06-前端基础/13-js运行机制:异步和单线程.md
Normal file
248
06-前端基础/13-js运行机制:异步和单线程.md
Normal file
@ -0,0 +1,248 @@
|
||||
|
||||
|
||||
|
||||
## 前言
|
||||
|
||||
|
||||
面试时,关于`同步和异步`,可能会问以下问题:
|
||||
|
||||
- 同步和异步的区别是什么?分别举一个同步和异步的例子
|
||||
|
||||
- 一个关于 setTimeout 的笔试题
|
||||
|
||||
- 前端使用异步的场景哪些?
|
||||
|
||||
|
||||
|
||||
面试时,关于`js运行机制`,需要注意以下几个问题:
|
||||
|
||||
- 如何理解JS的**单线程**
|
||||
|
||||
- 什么是**任务队列**
|
||||
|
||||
- 什么是 EventLoop
|
||||
|
||||
- 理解哪些语句会放入异步任务队列
|
||||
|
||||
- 理解语句放入异步任务队列的**时机**
|
||||
|
||||
|
||||
|
||||
|
||||
## JS的异步和单线程
|
||||
|
||||
> 因为是单线程,所以必须异步。
|
||||
|
||||
我们通过题目来解释以下。
|
||||
|
||||
### 题目一:异步
|
||||
|
||||
现有如下代码:
|
||||
|
||||
```javascript
|
||||
console.log(1);
|
||||
setTimeout(function () {
|
||||
console.log(2);
|
||||
}, 1000);
|
||||
console.log(3);
|
||||
console.log(4);
|
||||
|
||||
```
|
||||
|
||||
|
||||
上面的代码中,我们很容易知道,打印的顺序是`1,3,4,2`。因为你会想到,要等一秒之后再打印`2`。
|
||||
|
||||
可如果我把延时的时间从`1000`改成`0`:
|
||||
|
||||
|
||||
```javascript
|
||||
console.log(1);
|
||||
setTimeout(function () {
|
||||
console.log(2);
|
||||
}, 0);
|
||||
console.log(3);
|
||||
console.log(4);
|
||||
```
|
||||
|
||||
|
||||
上方代码中,打印的顺序仍然是`1,3,4,2`。这是为什么呢?我们来分析一下。
|
||||
|
||||
**总结:**
|
||||
|
||||
js 是单线程(同一时间只能做一件事),而且有一个**任务队列**:全部的同步任务执行完毕后,再来执行异步任务。第一行代码和最后一行代码是同步任务;但是,**`setTimeout`是异步任务**。
|
||||
|
||||
于是,执行的顺序是:
|
||||
|
||||
- 先执行同步任务`console.log(1)`
|
||||
|
||||
- 遇到异步任务`setTimeout`,要**挂起**
|
||||
|
||||
- 执行同步任务`console.log(3)`
|
||||
|
||||
- **全部的同步任务执行完毕后,再来执行异步任务**`console.log(2)`。
|
||||
|
||||
很多人会把这个题目答错,这是因为他们不懂 js 的运行机制。
|
||||
|
||||
注意上面那句话:同步任务执行完毕后,再来执行异步任务。也就是说,**如果同步任务没有执行完,异步任务是不会执行的**。为了解释这句话,我们来看下面这个例子。
|
||||
|
||||
|
||||
### 题目二:异步
|
||||
|
||||
现有如下代码:
|
||||
|
||||
```javascript
|
||||
console.log('A');
|
||||
while (1) {
|
||||
|
||||
}
|
||||
console.log('B');
|
||||
```
|
||||
|
||||
我们很容易想到,上方代码的打印结果是`A`,因为while是同步任务,代码会陷入死循环里出不来,自然也就无法打印`B`。可如果我把代码改成下面的样子:
|
||||
|
||||
```javascript
|
||||
console.log('A');
|
||||
|
||||
setTimeout(function () {
|
||||
console.log('B');
|
||||
})
|
||||
|
||||
while (1) {
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
上方代码的打印结果仍然是`A`。因为while是同步任务,setTimeout是异步任务,所以还是那句话:**如果同步任务没有执行完,队列里的异步任务是不会执行的**。
|
||||
|
||||
|
||||
### 题目三:同步
|
||||
|
||||
```javascript
|
||||
console.log('A');
|
||||
|
||||
alert('haha'); //1秒之后点击确认
|
||||
|
||||
console.log('B');
|
||||
|
||||
```
|
||||
|
||||
`alert`函数是同步任务,我只有点击了确认,才会继续打印`B`。
|
||||
|
||||
### 同步和异步的对比
|
||||
|
||||
我们在上面列举了异步和同步的例子。现在来描述一下区别:【重要】
|
||||
|
||||
因为`setTimeout`是**异步任务**,所以程序并不会卡在那里,而是继续向下执行(即使settimeout设置了倒计时一万秒);但是`alert`函数是**同步**任务,程序会**卡在那里**,如果它没有执行,后面的也不会执行(卡在那里,自然也就造成了**阻塞**)。
|
||||
|
||||
**何时需要异步:**
|
||||
|
||||
- 在可能发上等待的情况。(比如按钮的点击事件,我们不可能卡在按钮那里,什么都不做。所以,应该用异步)
|
||||
|
||||
- 等待的过程中,不能像 alert 那样阻塞程序运行
|
||||
|
||||
- 什么时候需要**等待**,就什么时候用异步。
|
||||
|
||||
|
||||
### 前端使用异步的场景
|
||||
|
||||
|
||||
- 定时任务:setTimeout(定时炸弹)、setInterval(循环执行)
|
||||
|
||||
- 网络请求:ajax请求、动态`<img>`加载
|
||||
|
||||
- 事件绑定(比如说,按钮绑定点击事件之后,用户爱点不点)
|
||||
|
||||
- ES6中的Promise
|
||||
|
||||
|
||||
代码举例:
|
||||
|
||||
```javascript
|
||||
console.log('start');
|
||||
var img = document.createElement('img');
|
||||
img.onload = function () {
|
||||
console.log('loaded');
|
||||
}
|
||||
img.src = '/xxx.png';
|
||||
console.log('end');
|
||||
```
|
||||
|
||||
上图中,先打印`start`,然后执行`img.src = '/xxx.png'`,然后打印`end`,最后打印`loaded`。
|
||||
|
||||
|
||||
## 任务队列和Event Loop(事件循环)
|
||||
|
||||
### 任务队列
|
||||
|
||||
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
|
||||
|
||||
|
||||
总结:**只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制**。【重要】
|
||||
|
||||
|
||||
### Event Loop
|
||||
|
||||
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
|
||||
|
||||
![](http://img.smyhvae.com/20180310_1840.png)
|
||||
|
||||
|
||||
在理解Event Loop时,要理解两句话:
|
||||
|
||||
- 理解哪些语句会放入异步任务队列
|
||||
|
||||
- 理解语句放入异步任务队列的**时机**
|
||||
|
||||
|
||||
### 容易答错的题目
|
||||
|
||||
```javascript
|
||||
for (var i = 0; i < 3; i++) {
|
||||
setTimeout(function () {
|
||||
console.log(i);
|
||||
}, 1000);
|
||||
}
|
||||
```
|
||||
|
||||
很多人以为上面的题目,答案是`0,1,2,3`。其实,正确的答案是:`3,3,3,3`。
|
||||
|
||||
分析:for 循环是同步任务,setTimeout是异步任务。for循环每次遍历的时候,遇到settimeout,就先暂留着,等同步任务全部执行完毕(此时,i已经等于3了),再执行异步任务。
|
||||
|
||||
|
||||
我们把上面的题目再加一行代码。最终代码如下:
|
||||
|
||||
```javascript
|
||||
for (var i = 0; i < 3; i++) {
|
||||
setTimeout(function () {
|
||||
console.log(i);
|
||||
}, 1000);
|
||||
}
|
||||
console.log(i);
|
||||
```
|
||||
|
||||
如果我们约定,用箭头表示其前后的两次输出之间有 1 秒的时间间隔,而逗号表示其前后的两次输出之间的时间间隔可以忽略,代码实际运行的结果该如何描述?可能会有两种答案:
|
||||
|
||||
- A. 60% 的人会描述为:`3 -> 3 -> 3 -> 3`,即每个 3 之间都有 1 秒的时间间隔;
|
||||
|
||||
- B. 40% 的人会描述为:`3 -> 3,3,3`,即第 1 个 3 直接输出,1 秒之后,连续输出 3 个 3。
|
||||
|
||||
循环执行过程中,几乎同时设置了 3 个定时器,这些定时器都会在 1 秒之后触发,而循环完的输出是立即执行的,显而易见,正确的描述是 B。
|
||||
|
||||
上面这个题目的参考链接:
|
||||
|
||||
- [80% 应聘者都不及格的 JS 面试题](https://juejin.im/post/58cf180b0ce4630057d6727c)
|
||||
|
||||
- [深入浅出Javascript事件循环机制(上)](https://zhuanlan.zhihu.com/p/26229293)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user