Skip to content

Commit d0d0d45

Browse files
committed
update
1 parent 36192e2 commit d0d0d45

File tree

10 files changed

+278
-1
lines changed

10 files changed

+278
-1
lines changed

.babelrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["stage-3", "es2015"],
3+
"plugins": ["transform-runtime"]
4+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

README.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,79 @@
1-
# js-async-tutorial
1+
# 深入理解 JavaScript 异步
2+
3+
## 前言
4+
5+
2014年秋季写完了《[深入理解javascript原型和闭包系列](http://www.cnblogs.com/wangfupeng1988/p/4001284.html)》,已经帮助过很多人走出了 js 原型、作用域、闭包的困惑,至今仍能经常受到好评的留言。
6+
7+
很早之前我就总结了**JS三座大山**这个概念(虽然没有到处宣扬),前两座(原型、作用域)已经基本讲明白,而第三座(异步)也应该做一个总结。
8+
9+
于是,2017年初春,我花费大约一周的业余时间来对 JS 异步做一个完整的总结,和各位同学共勉共进步!
10+
11+
## 目录
12+
13+
**基础部分**
14+
15+
- [什么是异步](./part1/01-what-is-async.md)
16+
- [异步和 event-loop](./part1/02-event-loop.md)
17+
- 事件绑定算不算异步?
18+
- 最原始的 callback 处理异步
19+
20+
**jQuery的解决方案**
21+
22+
- jQuery 对异步的思考 - 上
23+
- jQuery 对异步的思考 - 下
24+
25+
**Promise**
26+
27+
- Promise 被 ES6 采用
28+
- Promise 在 ES6 中的具体应用
29+
- 对标一下 Promise/A+ 标准
30+
- Promise 真的取代 callback 了吗?
31+
- 用 Q.js 库来简化 Promise 并且兼容浏览器
32+
33+
**Generator**
34+
35+
- Generator 横空出世
36+
- Iterator 遍历器
37+
- 带着 Iterator 来看 Generator
38+
- Generator 与异步结合
39+
- 使用大名鼎鼎的 co 库
40+
- koa 中使用 Generator
41+
- Generator 的本质是什么?是否取代了 callback
42+
43+
**async-await**
44+
45+
- ES7 中引入 async-await
46+
- async-await 值不值得期待
47+
- async-await 的本质是什么?是否取代了 callback
48+
49+
**最后**
50+
51+
- 总结
52+
53+
54+
## 运行程序的说明
55+
56+
要求本地 node 在`v6`或以上版本,然后执行以下命令下载代码并安装依赖的插件
57+
58+
```shell
59+
$ cd ~
60+
$ git clone git@github.com:wangfupeng1988/js-async-tutorial.git
61+
$ cd js-async-tutorial
62+
$ npm i
63+
```
64+
65+
最后,本地可能需要启动一个静态服务器来运行页面,我使用`http-server`插件
66+
67+
```shell
68+
$ npm install http-server -g
69+
$ cd js-async-tutorial
70+
$ http-server -p 8881
71+
```
72+
73+
然后浏览器访问`http://localhost:8881/xxx/xxx.html`即可
74+
75+
## 求打赏
76+
77+
如果你看完了,感觉还不错,欢迎给我打赏 ———— 以激励我更多输出优质内容
78+
79+
![](http://images2015.cnblogs.com/blog/138012/201702/138012-20170228112237798-1507196643.png)

data/data1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
["a", "b", 100, true]

data/data2.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"a": 100,
3+
"b": 200
4+
}

package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "js-async-tutorial",
3+
"version": "1.0.0",
4+
"description": "深入理解 JavaScript 异步",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/wangfupeng1988/js-async-tutorial.git"
12+
},
13+
"author": "https://github.com/wangfupeng1988",
14+
"license": "ISC",
15+
"bugs": {
16+
"url": "https://github.com/wangfupeng1988/js-async-tutorial/issues"
17+
},
18+
"homepage": "https://github.com/wangfupeng1988/js-async-tutorial#readme",
19+
"dependencies": {
20+
"babel-core": "^6.23.1",
21+
"babel-plugin-transform-runtime": "^6.23.0",
22+
"babel-preset-es2015": "^6.22.0",
23+
"babel-preset-stage-3": "^6.22.0",
24+
"babel-runtime": "^6.23.0",
25+
"co": "^4.6.0",
26+
"node-fetch": "^1.6.3",
27+
"q": "^1.4.1",
28+
"thunkify": "^2.1.2"
29+
}
30+
}

part1/01-what-is-async.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# 什么是异步
2+
3+
提醒:如果你是初学 js 的同学,尚未有太多项目经验和基础知识,请就此打住,不要看这篇教程
4+
5+
我思考问题、写文章一般都不按讨论出牌,别人写过的东西我不会再照着抄一遍。因此,后面所有的内容,都是我看了许多资料之后,个人重新思考提炼总结出来的,这肯定不能算是初级教程。
6+
7+
如果你是已有 js 开发经验,并了解异步的基础知识,到这里来想深入了解一下`Promise` `Generator``async-awati`,那就太好了,非常欢迎。
8+
9+
10+
11+
## 本节内容概述
12+
13+
- JS 为何会有异步
14+
- 异步的实现原理是什么
15+
- 常用的异步操作有哪些
16+
17+
## JS 为何会有异步
18+
19+
首先记住一句话 —— **JS 是单线程的语言**,所谓“单线程”就是一根筋,对于拿到的程序,一行一行的执行,上面的执行为完成,就傻傻的等着。例如
20+
21+
```javascript
22+
var i, t = Date.now()
23+
for (i = 0; i < 100000000; i++) {
24+
}
25+
console.log(Date.now() - t) // 250 (chrome浏览器)
26+
```
27+
28+
上面的程序花费 250ms 的时间执行完成,执行过程中就会有卡顿,其他的事儿就先撂一边不管了。
29+
30+
执行程序这样没有问题,但是对于 JS 最初使用的环境 ———— 浏览器客户端 ———— 就不一样了。因此在浏览器端运行的 js ,可能会有大量的网络请求,**而一个网络资源啥时候返回,这个时间是不可预估的。这种情况也要傻傻的等着、卡顿着、啥都不做吗?**———— 那肯定不行。
31+
32+
因此,JS 对于这种场景就设计了异步 ———— 即,发起一个网络请求,就先不管这边了,先干其他事儿,网络请求啥时候返回结果,到时候再说。这样就能保证一个网页的流程运行。
33+
34+
35+
## 异步的实现原理
36+
37+
先看一段比较常见的代码
38+
39+
```javascript
40+
var ajax = $.ajax({
41+
url: '/data/data1.json',
42+
success: function () {
43+
console.log('success')
44+
}
45+
})
46+
```
47+
48+
上面代码中`$.ajax()`需要传入两个参数进去,`url``success`,其中`url`是请求的路由,`success`是一个函数。这个函数传递过去不会立即执行,而是等着请求成功之后才能执行。**对于这种传递过去不执行,等出来结果之后再执行的函数,叫做`callback`,即回调函数**
49+
50+
再看一段更加能说明回调函数的 nodejs 代码。和上面代码基本一样,唯一区别就是:上面代码时网络请求,而下面代码时 IO 操作。
51+
52+
```javascript
53+
var fs = require('fs')
54+
fs.readFile('data1.json', (err, data) => {
55+
console.log(data.toString())
56+
})
57+
```
58+
59+
从上面两个 demo 看来,**实现异步的最核心原理,就是将`callback`作为参数传递给异步执行函数,当有结果返回之后再触发 `callback`执行**,就是如此简单!
60+
61+
62+
## 常用的异步操作
63+
64+
开发中比较常用的异步操作有:
65+
66+
- 网络请求,如`ajax` `http.get`
67+
- IO 操作,如`readFile` `readdir`
68+
- 定时函数,如`setTimeout` `setInterval`
69+
70+
最后,**请思考,事件绑定是不是也是异步操作**?例如`$btn.on('click', function() {...})`。这个问题很有意思,我会再后面的章节经过分析之后给出答案,各位先自己想一下。
71+
72+
## 求打赏
73+
74+
如果你看完了,感觉还不错,欢迎给我打赏 ———— 以激励我更多输出优质内容
75+
76+
![](http://images2015.cnblogs.com/blog/138012/201702/138012-20170228112237798-1507196643.png)
77+
78+

part1/02-event-loop.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 异步和 event-loop
2+
3+
提到异步,就必须提 event-loop 。event-loop 中文翻译叫做“时间轮询”,它是能体现出单线程中异步操作是如何被执行的。
4+
5+
首先,**强烈大家观看一个歪果仁的视频《[what the hack is event loop](http://www.tudou.com/programs/view/ACDNKZJm6pQ/)**,只有不到半个小时的时间,但是将的非常详细。*如果那个链接失效,访问[这里](http://pan.baidu.com/s/1c1E0rjM)(密码: xx9f)*
6+
7+
其次,再结合阮一峰老师的《[什么是event loop](http://www.ruanyifeng.com/blog/2013/10/event_loop.html)》一起看一下。将这两个看完就基本了解 event loop 了
8+
9+
最后,event-loop 是一块内容比较独立的技术性知识,它是什么样子就是什么样子,讲解起来可变通性非常小。因此,本节说一下我对 event-loop 的理解和体会
10+
11+
## 本节内容概述
12+
13+
- 举例说明
14+
- 核心概念
15+
- 思考两个问题
16+
17+
## 举例说明
18+
19+
给出一段简单的 js 代码
20+
21+
```javascript
22+
console.log('line 1')
23+
setTimeout(console.log, 1000, 'line 2')
24+
console.log('line 3')
25+
```
26+
27+
以上一共三行代码,该程序被执行的时候,会依次挨行执行,这被称作 **main-stack**
28+
29+
- 第一步,执行第一行,将结果`line 1`打印出来
30+
- 第二步,执行第二行,注意此时会将这个操作暂时存储在一个叫做 **call-stack** 的内存地址中,因为`setTimeout`是一个异步执行操作。
31+
- 第三步,执行第三行,将结果`line 2`打印出出来
32+
- 第四步,等待 **main-stack** 的程序(一共三行)都全部执行完了,然后立马实时查看 **call-stack** 中是否还有未执行的异步回调,如果有(1000ms 之后)则把它拿到主线程中来执行
33+
- 第五步,主线程又被执行完了,再实时查看 **call-stack** 中是否还有未执行的异步回调。
34+
35+
以上只拿了`setTimeout`举例子,但是对于网络请求、IO操作、事件绑定道理都是一样的。**如果我讲的简单例子你还是看不懂,一定要去看文章最初提到的《what the hack is event loop》视频,重要重要!!!**
36+
37+
## 核心概念
38+
39+
理解 event-loop 的核心概念是要明白以下几点:
40+
41+
- **main-stack****call-stack** 的区别
42+
- 执行 **main-stack** 时将异步操作暂存到 **call-stack**
43+
- **main-stack** 执行完成之后,实时检查 **call-stack** 的任务是否应该被拿到 **main-stack** 中来执行
44+
45+
46+
## 思考三个问题
47+
48+
**第一题,以下代码的输出顺序是什么**
49+
50+
```javascript
51+
setTimeout(console.log, 0, 'a')
52+
console.log('b')
53+
console.log('c')
54+
```
55+
56+
答案是`b c a`,有疑问的需要再去看上面的介绍或者那个视频。
57+
58+
**第二题,以下代码中,最后输出的结果是否是 500**
59+
60+
```javascript
61+
var i, t = Date.now()
62+
for (i = 0; i < 100000000; i++) {
63+
}
64+
function fn() {
65+
console.log(Date.now() - t) // 输出多少???
66+
}
67+
setTimeout(fn, 500)
68+
```
69+
70+
答案是大于 500ms ,因为 for 函数需要花费一些时间,等 for 执行完之后再开始计算 500ms 之后执行 fn
71+
72+
**第三题,事件绑定是不是异步操作?**
73+
74+
这个问题大家根据 event-loop 的讲解和视频来思考,我们下一节再给出解答。
75+
76+
77+
## 求打赏
78+
79+
如果你看完了,感觉还不错,欢迎给我打赏 ———— 以激励我更多输出优质内容
80+
81+
![](http://images2015.cnblogs.com/blog/138012/201702/138012-20170228112237798-1507196643.png)

part1/03-event-bind.md

Whitespace-only changes.

part1/04-callback.md

Whitespace-only changes.

0 commit comments

Comments
 (0)