# promise和async/await的区别
# 是什么
# Promise
Promise是ES6中的一个内置对象,实际是一个构造函数,是JS中进行异步编程的新的解决方案。
特点:
- 通常用来解决异步调用问题;
- 解决多层回调嵌套的方案(回调地狱);
- 提高代码可读性、更便于维护。
- 可并行调用。
缺点:
- 1、无法取消Promise,一旦新建它就会立即执行,无法中途取消;
- 2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;
- 3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成);
- 4、Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise的报错堆栈上下文不太友好。
# async/await
async function 用来定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果,。如果你在代码中使用了异步函数,就会发现它的语法和结构会更像是标准的同步函数。
await 操作符用于等待一个 Promise 对象。它只能在异步函数 async function 中使用。
特点:
- async/await是ES7新特性;
- async/await是写异步代码的新方式,以前的方法有回调函数和Promise;
- async/await是基于Promise实现的,它不能用于普通的回调函数;
- async/await与Promise一样,是非阻塞的;
- async/await使得异步代码看起来像同步代码,这正是它的魔力所在。
缺点:
- 1、async/await无法处理promise返回的reject对象,要借助try...catch...,或者使用then();
- 2、await只能串行,做不到并行;
- 3、全局捕获错误必须用window.onerror,不像Promise可以专用window.addEventListener('unhandledrejection', function),而window.onerror会捕获各种稀奇古怪的错误,造成系统浪费
- 4、try...catch...内部的变量无法传递给下一个try...catch...
- 5、async/await无法简单实现Promise的各种原生方法,比如.race()之类。
# 区别
# 1、简洁的代码
使用async函数可以让代码简洁很多,不需要像Promise一样需要些then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。
# 2、错误处理
Promise 中不能自定义使用 try/catch 进行错误捕获,但是在 Async/await 中可以像处理同步代码处理错误。
//#Promise
const makeRequest = () => {
try {
getJSON()
.then(result => {
// this parse may fail
const data = JSON.parse(result)
console.log(data)
})
// uncomment this block to handle asynchronous errors
// .catch((err) => {
// console.log(err)
// })
} catch (err) {
console.log(err)
}
}
//#Async/await
const makeRequest = async () => {
try {
// this parse may fail
const data = JSON.parse(await getJSON())
console.log(data)
} catch (err) {
console.log(err)
}
}
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
# 3、条件语句
条件语句也和错误捕获是一样的,在 Async 中也可以像平时一般使用条件语句
//#Promise
const makeRequest = () => {
return getJSON()
.then(data => {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData => {
console.log(moreData)
return moreData
})
} else {
console.log(data)
return data
}
})
}
//#Async
const makeRequest = async () => {
const data = await getJSON()
if (data.needsAnotherRequest) {
const moreData = await makeAnotherRequest(data);
console.log(moreData)
return moreData
} else {
console.log(data)
return data
}
}
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
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
# 4、中间值
在一些场景中,也许需要 promise1 去触发 promise2 再去触发 promise3,这个时候代码应该是这样的
const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return promise2(value1)
.then(value2 => {
// do something
return promise3(value1, value2)
})
})
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
如过 promise3 不需要 value1,嵌套将会变得简单。如果你有强迫症,则将值1&2使用 promise.all() 分装起来。
const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return Promise.all([value1, promise2(value1)])
})
.then(([value1, value2]) => {
// do something
return promise3(value1, value2)
})
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
但是使用 Async 就会变得很简单
const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}
1
2
3
4
5
2
3
4
5
# 5、错误栈
如过 Promise 连续调用,对于错误的处理是很麻烦的。你无法知道错误出在哪里。
const makeRequest = () => {
return callAPromise()
.then(() => callAPromise())
.then(() => callAPromise())
.then(() => callAPromise())
.then(() => callAPromise())
.then(() => {
throw new Error("oops");
})
}
makeRequest()
.catch(err => {
console.log(err);
// output
// Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
但是对于 Async 就不一样了
const makeRequest = async () => {
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
await callAPromise()
throw new Error("oops");
}
makeRequest()
.catch(err => {
console.log(err);
// output
// Error: oops at makeRequest (index.js:7:9)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 6、调试
async/await能够使得代码调试更简单。2个理由使得调试Promise变得非常痛苦:
- 不能在返回表达式的箭头函数中设置断点
- 如果你在.then代码块中设置断点,使用Step Over快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。
使用await/async时,你不再需要那么多箭头函数,这样你就可以像调试同步代码一样跳过await语句。