异步
单线程
- 何为单线程?
只有一个线程,只能做一件事,只关注一件事
// 循环运行期间,JS 执行和 DOM 渲染暂时卡顿
var i,
sum = 0
for (i = 0; i < 10000000; i++) {
sum += i
}
console.log(sum)
// alert 不处理,JS 执行和 DOM 渲染暂时卡顿
console.log(1)
alert('hello')
console.log(2)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 出现的原因: 避免 DOM 渲染的冲突
- 浏览器需要渲染 DOM
- JS 可以修改 DOM 结构
- JS 执行的时候,浏览器 DOM 渲染会暂停
- 两段 JS 也不能同时执行(都修改 DOM 就冲突了)
- webworker 支持多线程,但是不能访问 DOM
- 解决方案: 异步
console.log(100)
setTimeout(function() {
console.log(200)
}, 1000)
console.log(300)
console.log(400)
1
2
3
4
5
6
2
3
4
5
6
- 前期异步带来的问题
(1) 没按照书写方式执行,可读性差
(2) callback 中不容易模块化
event-loop (事件轮询)
(1) 事件轮询,JS 实现异步的具体解决方案
(2) 同步代码,直接执行
(3) 异步函数先放在 异步队列 中
(4) 待同步函数执行完毕,轮询执行 异步队列 的函数
jquery Deferred
jQuery 1.5 的变化
- 无法改变 JS 异步和单线程的本质
- 只能从写法上杜绝 callback 这种形式
- 它是一种语法糖形式,但是解耦了代码
- 很好的体现:开放封闭原则
// jq 1.5 之前
var ajax = $.ajax({
url: 'data.json',
success: function() {
console.log('success1')
console.log('success2')
console.log('success3')
},
error: function() {
console.log('error')
}
})
console.log(ajax) // 返回一个 XHR 对象
// jq 1.5 之后
var ajax = $.ajax('data.json')
ajax
.done(function() {
console.log('success 1')
})
.fail(function() {
console.log('error')
})
.done(function() {
console.log('success 2')
})
console.log(ajax) // 返回一个 deferred 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Promise 标准
- 异常捕获
// 规定:then 只接受一个参数,最后统一用 catch 捕获异常
result
.then(function(img) {
console.log(img.width)
})
.then(function(img) {
console.log(img.height)
})
.catch(function(ex) {
// 最后统一 catch
console.log(ex)
})
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 多个串联
var src1 = ''
var result1 = loadImg(src1)
var src2 = ''
var result2 = loadImg(src2)
// 链式操作
result1
.then(function(img) {
console.log('第一个图片加载完成')
return result2
})
.then(function(img) {
console.log('第二个图片加载完成')
})
.catch(function(ex) {
// 最后统一 catch
console.log(ex)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- Promise.all & Promise.race
// Promise.all 接受一个 promise 对象的数组
// 待全部完成之后,统一执行 success
Promise.all([result1, result2]).then(datas => {
// 接受到的 datas 是一个数组,依次包含了多个 Promise 返回的内容
console.log(datas[0])
console.log(datas[1])
})
// Promise.rece 接受一个包含多个 Promise 对象的数组
// 只要有一个完成,就执行 success
Promise.race([result1, result2]).then(data => {
//data 即最先执行完成的 Promise 的返回值
console.log(data)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 状态变化
(1) 三种状态: pending fulfilled rejected
(2) 初始状态 pending
(3) pending 变成 fulfilled,或者 pending 变成 rejected
(4) 状态变化不可逆
- then
(1) Promise 实例必须实现 then 这个方法
(2) then() 必须可以接收两个函数作为参数
(3) then() 返回的必须是一个 Promise 实例
async/await 的使用
- 介绍
(1) then 只是讲 callback 拆分了
var w = waitHandle()
w.then(
function() {
console.log('ok 1')
},
function() {
console.log('err 1')
}
).then(
function() {
console.log('ok 2')
},
function() {
console.log('err 2')
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(2) async/await 是直接的同步写法
const load = async function() {
const result1 = await loadImg(src1)
console.log(result1)
const result2 = await loadImg(src2)
console.log(result2)
}
load()
1
2
3
4
5
6
7
2
3
4
5
6
7
- 用法
(1) 使用 await,函数必须用 async 标示 (2) await 后面跟的是一个 Promise 实例 (3) 需要 babel-polyfill
JS 当前异步的解决方案
- jQuery Deferred
- Promise
- async/await