JavaScript:Promise以及Async/Await赢得胜利的原因
异步函数在JavaScript中是好事。好的方面是异步函数是非阻塞的,因此非常快——尤其是在Node.js上下文中。缺点是处理异步函数可能很麻烦,因为有时您必须等待一个函数完成才能获得其“回调”,然后再执行后面的代码。有几种方法可以发挥异步函数调用的优势并正确处理它们的执行,但是有一种方法远胜于其他方法(你猜对了,就是Async / Await)。在本文中,您将了解Promise的来龙去脉以及Async / Await的用法,以及我们对两者比较的看法。享受吧!
Promise和回调(callback)
作为JavaScript或Node.js开发人员,正确理解Promise和Callback之间的区别以及它们如何协同工作至关重要。两者之间有微小但重要 的差异。在每个Promise的核心,都有一个回调来解决某种数据(或错误),这些数据冒泡到被调用的Promise上。
我们先定义一个函数作为回调函数:
function done(err) {
if (err) {
console.log(err);
return;
}
console.log('Passwords match!');
}
然后就可以在validatePassword()函数中使用上面的函数:
function validatePassword(password) {
if (password !== 'my-pwd') {
return done('Password mismatch!');
}
return done(null);
}
如果用Promise呢,我们可以写这样的代码:
// provided a string (password)
function validatePassword(password) {
// create promise with resolve and reject as params
return new Promise((resolve, reject) => {
// validate that password matches my-pwd (the deer)
if (password !== 'my-pwd') {
// password doesn't match, return an error with reject
return reject('Invalid Password!');
}
// password matches, return a success state with resolve
resolve();
});
}
function done(err) {
// if an err was passed, console out a message
if (err) {
console.log(err);
return; // stop execution
}
// console out a valid state
console.log('Password is valid!');
}
// dummy password
const password = 'foo';
// using a promise, call the validate password function
validatePassword(password)
.then(() => {
// it was successful
done(null);
})
.catch(err => {
// an error occurred, call the done function and pass the err message
done(err);
});
Promise
与传统的基于回调的方法相比,Promise为执行、编写和管理异步操作提供了一种更简单的选择。它们还允许您使用类似于同步try/catch
的方法来处理异步错误。Promise还提供了三种独特的状态:
- 待处理 -Promise的结果尚未确定,因为产生结果的异步操作尚未完成。
- 已实现 -异步操作已完成,并且Promise具有价值。
- 已拒绝 -异步操作失败,并且Promise将永远无法实现。在拒绝状态下,Promise会指出操作失败的原因。
当Promise待定时,它可以转换为已实现或已拒绝状态。但是,一旦实现或拒绝了Promise,它就永远不会转变为任何其他状态,其值或失败原因也不会改变。
缺点
Promise没做好的一件事就是解决所谓的“回调地狱”,实际上这只是一系列嵌套函数调用。当然只有一个调用是可以的,很简单。对于许多调用,就容易使您的代码变得难以阅读和维护。
在循环中使用Promise
为了避免使用JavaScript深度嵌套的回调,可以假设您可以简单地遍历Promise,将结果返回到对象或数组,完成后它将停止。不幸的是,这并不容易。由于JavaScript的异步特性,如果您遍历每个Promise,则在代码完成时不会调用Promise的“完成”事件。解决这种情况的正确方法是使用Promise.all()
。此功能在标记为完成之前等待所有完成(或第一个拒绝)。