Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 633c87d

Browse files
committed
docs(bom): edit engine
1 parent 9121e1f commit 633c87d

File tree

2 files changed

+67
-100
lines changed

2 files changed

+67
-100
lines changed

bom/engine.md

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,19 @@ What time is it?
120120
121121
`javascript:`协议的常见用途是书签脚本Bookmarklet。由于浏览器的书签保存的是一个网址,所以`javascript:`网址也可以保存在里面,用户选择这个书签的时候,就会在当前页面执行这个脚本。为了防止书签替换掉当前文档,可以在脚本最后返回`void 0`
122122
123-
## `<script>`标签的工作原理
123+
## script标签
124124
125-
正常的网页加载流程是这样的。
125+
### 工作原理
126+
127+
浏览器加载JavaScript脚本,主要通过`<script>`标签完成。正常的网页加载流程是这样的。
126128
127129
1. 浏览器一边下载HTML网页,一边开始解析
128130
2. 解析过程中,发现`<script>`标签
129131
3. 暂停解析,网页渲染的控制权转交给JavaScript引擎
130132
4. 如果`<script>`标签引用了外部脚本,就下载该脚本,否则就直接执行
131133
5. 执行完毕,控制权交还渲染引擎,恢复往下解析HTML网页
132134
133-
也就是说,加载外部脚本时,浏览器会暂停页面渲染,等待脚本下载并执行完成后,再继续渲染。原因是JavaScript可以修改DOM(比如使用`document.write`方法),所以必须把控制权让给它,否则会导致复杂的线程竞赛的问题。
135+
加载外部脚本时,浏览器会暂停页面渲染,等待脚本下载并执行完成后,再继续渲染。原因是JavaScript可以修改DOM(比如使用`document.write`方法),所以必须把控制权让给它,否则会导致复杂的线程竞赛的问题。
134136
135137
如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。
136138
@@ -185,7 +187,7 @@ What time is it?
185187
</body>
186188
```
187189

188-
如果有多个script标签,比如下面这样。
190+
如果有多个`script`标签,比如下面这样。
189191

190192
```html
191193
<script src="a.js"></script>
@@ -202,7 +204,7 @@ Gecko和Webkit引擎在网页被阻塞后,会生成第二个线程解析文档
202204

203205
此外,对于来自同一个域名的资源,比如脚本文件、样式表文件、图片文件等,浏览器一般最多同时下载六个(IE11允许同时下载13个)。如果是来自不同域名的资源,就没有这个限制。所以,通常把静态文件放在不同的域名之下,以加快下载速度。
204206

205-
## defer属性
207+
### defer属性
206208

207209
为了解决脚本文件下载阻塞网页渲染的问题,一个方法是加入defer属性。
208210

@@ -222,7 +224,7 @@ Gecko和Webkit引擎在网页被阻塞后,会生成第二个线程解析文档
222224

223225
对于内置而不是连接外部脚本的script标签,以及动态生成的script标签,`defer`属性不起作用。
224226

225-
## async属性
227+
### async属性
226228

227229
解决“阻塞效应”的另一个方法是加入`async`属性。
228230

@@ -245,62 +247,7 @@ Gecko和Webkit引擎在网页被阻塞后,会生成第二个线程解析文档
245247

246248
一般来说,如果脚本之间没有依赖关系,就使用`async`属性,如果脚本之间有依赖关系,就使用`defer`属性。如果同时使用`async``defer`属性,后者不起作用,浏览器行为由`async`属性决定。
247249

248-
## 重流和重绘
249-
250-
渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具有阻塞效应,并且会耗费很多时间和计算资源。
251-
252-
页面生成以后,脚本操作和样式表操作,都会触发重流(reflow)和重绘(repaint)。用户的互动,也会触发,比如设置了鼠标悬停(`a:hover`)效果、页面滚动、在输入框中输入文本、改变窗口大小等等。
253-
254-
重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。比如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流。
255-
256-
大多数情况下,浏览器会智能判断,将重流和重绘只限制到相关的子树上面,最小化所耗费的代价,而不会全局重新生成网页。
257-
258-
作为开发者,应该尽量设法降低重绘的次数和成本。比如,尽量不要变动高层的DOM元素,而以底层DOM元素的变动代替;再比如,重绘`table`布局和`flex`布局,开销都会比较大。
259-
260-
```javascript
261-
var foo = document.getElementById('foobar');
262-
263-
foo.style.color = 'blue';
264-
foo.style.marginTop = '30px';
265-
```
266-
267-
上面的代码只会导致一次重绘,因为浏览器会累积DOM变动,然后一次性执行。
268-
269-
下面是一些优化技巧。
270-
271-
- 读取DOM或者写入DOM,尽量写在一起,不要混杂
272-
- 缓存DOM信息
273-
- 不要一项一项地改变样式,而是使用CSS class一次性改变样式
274-
- 使用document fragment操作DOM
275-
- 动画时使用absolute定位或fixed定位,这样可以减少对其他元素的影响
276-
- 只在必要时才显示元素
277-
- 使用`window.requestAnimationFrame()`,因为它可以把代码推迟到下一次重流时执行,而不是立即要求页面重流
278-
- 使用虚拟DOM(virtual DOM)库
279-
280-
下面是一个`window.requestAnimationFrame()`对比效果的例子。
281-
282-
```javascript
283-
// 重绘代价高
284-
function doubleHeight(element) {
285-
var currentHeight = element.clientHeight;
286-
element.style.height = (currentHeight * 2) + 'px';
287-
}
288-
289-
all_my_elements.forEach(doubleHeight);
290-
291-
// 重绘代价低
292-
function doubleHeight(element) {
293-
var currentHeight = element.clientHeight;
294-
295-
window.requestAnimationFrame(function () {
296-
element.style.height = (currentHeight * 2) + 'px';
297-
});
298-
}
299-
300-
all_my_elements.forEach(doubleHeight);
301-
```
302-
303-
## 脚本的动态嵌入
250+
### 脚本的动态嵌入
304251

305252
除了用静态的`script`标签,还可以动态嵌入`script`标签。
306253

@@ -348,7 +295,7 @@ all_my_elements.forEach(doubleHeight);
348295

349296
此外,动态嵌入还有一个地方需要注意。动态嵌入必须等待CSS文件加载完成后,才会去下载外部脚本文件。静态加载就不存在这个问题,`script`标签指定的外部脚本文件,都是与CSS文件同时并发下载的。
350297

351-
## 加载使用的协议
298+
### 加载使用的协议
352299

353300
如果不指定协议,浏览器默认采用HTTP协议下载。
354301

@@ -393,6 +340,61 @@ all_my_elements.forEach(doubleHeight);
393340

394341
以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的HTML代码还没下载完,但浏览器已经显示出内容了。
395342

343+
### 重流和重绘
344+
345+
渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具有阻塞效应,并且会耗费很多时间和计算资源。
346+
347+
页面生成以后,脚本操作和样式表操作,都会触发重流(reflow)和重绘(repaint)。用户的互动,也会触发,比如设置了鼠标悬停(`a:hover`)效果、页面滚动、在输入框中输入文本、改变窗口大小等等。
348+
349+
重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。比如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流。
350+
351+
大多数情况下,浏览器会智能判断,将重流和重绘只限制到相关的子树上面,最小化所耗费的代价,而不会全局重新生成网页。
352+
353+
作为开发者,应该尽量设法降低重绘的次数和成本。比如,尽量不要变动高层的DOM元素,而以底层DOM元素的变动代替;再比如,重绘`table`布局和`flex`布局,开销都会比较大。
354+
355+
```javascript
356+
var foo = document.getElementById('foobar');
357+
358+
foo.style.color = 'blue';
359+
foo.style.marginTop = '30px';
360+
```
361+
362+
上面的代码只会导致一次重绘,因为浏览器会累积DOM变动,然后一次性执行。
363+
364+
下面是一些优化技巧。
365+
366+
- 读取DOM或者写入DOM,尽量写在一起,不要混杂
367+
- 缓存DOM信息
368+
- 不要一项一项地改变样式,而是使用CSS class一次性改变样式
369+
- 使用document fragment操作DOM
370+
- 动画时使用absolute定位或fixed定位,这样可以减少对其他元素的影响
371+
- 只在必要时才显示元素
372+
- 使用`window.requestAnimationFrame()`,因为它可以把代码推迟到下一次重流时执行,而不是立即要求页面重流
373+
- 使用虚拟DOM(virtual DOM)库
374+
375+
下面是一个`window.requestAnimationFrame()`对比效果的例子。
376+
377+
```javascript
378+
// 重绘代价高
379+
function doubleHeight(element) {
380+
var currentHeight = element.clientHeight;
381+
element.style.height = (currentHeight * 2) + 'px';
382+
}
383+
384+
all_my_elements.forEach(doubleHeight);
385+
386+
// 重绘代价低
387+
function doubleHeight(element) {
388+
var currentHeight = element.clientHeight;
389+
390+
window.requestAnimationFrame(function () {
391+
element.style.height = (currentHeight * 2) + 'px';
392+
});
393+
}
394+
395+
all_my_elements.forEach(doubleHeight);
396+
```
397+
396398
### JavaScript引擎
397399

398400
JavaScript引擎的主要作用是,读取网页中的JavaScript代码,对其处理后运行。

grammar/basic.md

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -440,50 +440,15 @@ switch (x) {
440440
441441
上面代码中,由于变量`x`没有发生类型转换,所以不会执行`case true`的情况。这表明,`switch`语句内部采用的是“严格相等运算符”,详细解释请参考《运算符》一节。
442442

443-
`switch`结构不利于代码重用,往往可以用对象形式重写。
444-
445-
```javascript
446-
function getItemPricing(customer, item) {
447-
switch(customer.type) {
448-
case 'VIP':
449-
return item.price * item.quantity * 0.50;
450-
case 'Preferred':
451-
return item.price * item.quantity * 0.75;
452-
case 'Regular':
453-
case default:
454-
return item.price * item.quantity;
455-
}
456-
}
457-
```
458-
459-
上面代码根据不同用户,返回不同的价格。你可以发现,`switch`语句包含的三种情况,内部逻辑都是相同的,不同只是折扣率。这启发我们可以用对象属性,重写这个判断。
460-
461-
```javascript
462-
var pricing = {
463-
'VIP': 0.50,
464-
'Preferred': 0.75,
465-
'Regular': 1.0
466-
};
467-
468-
function getItemPricing(customer, item) {
469-
if (pricing[customer.type])
470-
return item.price * item.quantity * pricing[customer.type];
471-
else
472-
return item.price * item.quantity * pricing.Regular;
473-
}
474-
```
475-
476-
如果价格档次再多一些,对象属性写法的简洁优势就更明显了。
477-
478443
### 三元运算符 ?:
479444

480445
JavaScript还有一个三元运算符(即该运算符需要三个运算子)`?:`,也可以用于逻辑判断。
481446

482447
```javascript
483-
(contidion) ? expression1 : expression2
448+
(contidion) ? expr1 : expr2
484449
```
485450

486-
上面代码中,如果`contidion``true`,则返回`expression1`的值,否则返回`expression2`的值。
451+
上面代码中,如果`contidion`为`true`,则返回`expr1`的值,否则返回`expr2`的值。
487452

488453
```javascript
489454
var even = (n % 2 === 0) ? true : false;

0 commit comments

Comments
 (0)