异步与同步
异步
1
2
3
4
5
6
7
8
9
10
11
12
13setTimeout(function (res) {
console.log(res)
},3000,"3秒后打印")
setTimeout(function (res) {
console.log(res)
},2000,"2秒后打印")
setTimeout(function (res) {
console.log(res)
},1000,"1秒后打印")
// 结果
// 1秒后打印
// 2秒后打印
// 3秒后打印同步(使用回调将上面的异步变为同步)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function transSync() {
setTimeout(function(res) {
console.log(res)
setTimeout(function(res) {
console.log(res)
setTimeout(function(res) {
console.log(res)
}, 1000, '1秒后打印')
}, 2000, '2秒后打印')
}, 3000, '3秒后打印')
}
transSync()
// 结果
// 3秒后打印
// 2秒后打印
// 1秒后打印通过回调将异步变为同步存在一下几个问题
- 回调层层嵌套,代码冗余
- 回调太多,难以分辨哪个参数来源于哪个回调函数
- 代码之间耦合度太高,一旦其中一个回调函数发生错误,其他回调函数也会遭殃
- 无法用
try catch来捕获错误
基于以上的问题的分析,异步解决方案 Promise 函数、 async 函数及 Generator 函数应运而生。
Promise
1 | let promise = new Promise((resolve, reject) => { |
Promise 优点是代码看起来清晰,每一个 then 里面的参数都是上一个异步返回 resolve 的结果对象。缺点是所有的回调都放在 then 里面,没有语义性。
Generator
用法
Generator函数有两个明显特征,一是function与函数名之间有*号,二是在函数内部使用yield表达式,定义不同的内部状态。yield表示中止执行,而next方法表示开启执行,返回的状态值为yield后面的表达式结果。Generator函数返回一个遍历器对象。示例
1
2
3
4
5
6
7
8
9
10function* fn() {
yield '1'
yield '2'
return 'end'
}
var res = fn()
console.log(res.next()) // {value: "1", done: false}
console.log(res.next()) // {value: "2", done: false}
console.log(res.next()) // {value: "end", done: true}
console.log(res.next()) // {value: undefined, done: true}异步变为同步
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
28
29
30function* gen() {
yield new Promise(resolve => {
setTimeout(res => {
resolve(res)
}, 3000, '3秒后打印')
})
yield new Promise(resolve => {
setTimeout(res => {
resolve(res)
}, 2000, '2秒后打印')
})
yield new Promise(resolve => {
setTimeout(res => {
resolve('1秒后打印') // res 如果不传入 setTimeout 第三个参数则为 undefined
}, 3000)
})
}
let g = gen()
g.next().value.then(res => {
console.log(res)
}).then(res => {
g.next().value.then(res => {
console.log(res)
})
}).then(res => {
g.next().value.then(res => {
console.log(res)
})
})
async
用法
async函数 是Generator函数的语法糖,它只是将Generator函数中的*变成了async,yield变成了await,更具有语义性。async函数直接执行,不需要通过next。async函数返回的是一个promise对象,可以使用then方法添加回调函数。示例
1
2
3
4
5
6async function fn() {
return 'abc'
}
fn().then(res => {
console.log(res) // abc
})异步变同步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24async function foo() {
await new Promise(resolve => {
setTimeout(res => {
console.log(res)
resolve(res)
}, 3000, '3秒后打印')
})
await new Promise(resolve => {
setTimeout(res => {
console.log(res) // res 应为 setTimeout 第三个参数
resolve('2秒后打印')
}, 2000)
})
await new Promise(resolve => {
setTimeout(res => {
console.log(res)
resolve(res)
}, 1000, '1秒后打印')
})
}
foo()