「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
现在的前端面试基本上都会问Promise,多数面试者也能应付自如。问题无非围绕以下这几个问题
- 是什么
- 解决了什么问题
- 怎么用
什么是Promise
Promise是一个对象,它代表了一个异步操作的最终完成或者失败。
Promise解决了什么问题
Promise解决了回调嵌套引发的回调地狱问题。
回调地狱示例: 看起来像是一个正常一部代码,对于一两个嵌套调用,看起来没问题,但是对于连续嵌套,代码的层级会越来越深,这种情况就被称为回调地狱或者事末日金字塔(把代码竖起来就像一个金字塔)。
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
Promise使代码串联在一起,用.then属性有序输出。将回调绑定到返回的Promise上,形成了一个Promise链条。
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
then 里的参数是可选的,catch(failureCallback) 是 then(null, failureCallback) 的缩略形式。也可以用箭头函数来表示,示例:
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
Promise的用法
Promise对象有两个特点。
1.对象的状态不受外界影响。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
示例:普通写法
var promise = new Promise(function(resolve, reject) {
// 自动调用
// 可以做任何异步操作,
// А когда они завершатся — нужно вызвать одно из:
// resolve(res) 成功
// reject(erroy) 失败
})
示例:箭头函数写法,等待3秒,打印hello。
const wait = time => new Promise((resolve) => setTimeout(resolve, time));
wait(3000).then(() => console.log('Hello!')); // 'Hello!'
async/await是什么?
async函数,就是Generator函数的语法糖,它建⽴在Promises上,并且与所有现有的基于Promise的API兼容。
- Async—声明⼀个异步函数(async function someName(){...})。
- ⾃动将常规函数转换成Promise,返回值也是⼀个Promise对象。
- 只有async函数内部的异步操作执⾏完,才会执⾏then⽅法指定的回调函数。
- 异步函数内部可以使⽤await。
- Await—暂停异步的功能执⾏(var result = await someAsyncCall();)。
- 放置在Promise调⽤之前,await强制其他代码等待,直到Promise完成并返回结果。
- 只能与Promise⼀起使⽤,不适⽤与回调。
- 只能在async函数内部使⽤。
async/await相⽐于Promise的优势?
- async/await代码读起来更加同步,Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担。
- Promise传递中间值⾮常麻烦,⽽async/await⼏乎是同步的写法,⾮常优雅。
- async/await错误处理友好,async/await可以⽤成熟的try/catch,Promise的错误捕获⾮常冗余。
- async/await调试友好,Promise的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,如果你在⼀个.then代码块中使⽤调试器的步进(step-over)功能,调试器并不会进⼊后续的.then代码块,因为调试器只能跟踪同步代码的『每⼀步』。