JavaScript、异步编程和 Promises
在本教程中,您将了解 JS 中的 Promise 是什么、JavaScript Promise 可以处于哪些状态,以及如何处理 JS Promise 中的异步错误。
到目前为止,您只处理常规值。您创建了一个变量或常量,保存了一些内容,然后就可以立即使用了。例如,您可以将其打印到控制台。
但是,如果值不是立即出现,而是需要先经过一段时间,该怎么办?我们经常从数据库或外部服务器获取数据。这些操作需要时间,有两种方法可以处理它们:
- 我们可以尝试阻止程序的执行,直到我们收到数据
- 或者我们可以继续执行,稍后在数据出现时处理
这并不是说一种方法一定比另一种更好。两者都适合不同的需求,因为我们在不同情况下需要不同的行为。
如果您等待的数据对于后续操作至关重要,那么您需要阻止执行,这是无法回避的。而如果您可以推迟处理,那么当然就不值得浪费时间,因为您可以做其他事情。
JavaScript Promise 到底是什么?
Promise是一种特殊类型的对象,可以帮助您处理异步操作。
在无法立即检索值的情况下,许多函数将向您返回承诺。
const userCount = getUserCount();
console.log(userCount); // Promise {<pending>}
在这种情况下,getUserCount
是返回的函数Promise
。如果我们尝试立即显示变量的值userCount
,我们会得到类似这样的结果Promise {<pending>}
。
会发生这种情况,因为目前还没有数据,我们需要等待。
JavaScript 中的 Promise 状态
承诺可以处于多种状态:
- 待处理- 响应尚未准备好。请等待。
- 已完成- 响应已准备就绪。成功。获取数据。
- 已拒绝- 发生错误。请处理。
在pending状态下,我们无法做任何有用的事情,只能等待。在其他情况下,我们可以添加处理函数,当 Promise 进入 fulfilled 或 rejected 状态时调用这些函数。
为了处理数据的成功接收,我们需要一个then
函数。
const userCount = getUserCount();
const handleSuccess = (result) => {
console.log(`Promise was fulfilled. Result is ${result}`);
}
userCount.then(handleSuccess);
对于错误处理 - catch
。
const handleReject = (error) => {
console.log(`Promise was rejected. The error is ${error}`);
}
userCount.catch(handleReject);
请注意,该getUserCount
函数返回一个 Promise,因此我们不能直接使用userCount
。为了在数据出现时对其进行一些有用的处理,我们需要向then
和 函数添加处理程序catch
,这些处理程序将在成功或错误时被调用。
then
和函数catch
可以顺序调用。在这种情况下,我们将同时处理成功和失败的情况。
const userCount = getUserCount();
const handleSuccess = (result) => {
console.log(`Promise was fulfilled. Result is ${result}`);
}
const handleReject = (error) => {
console.log(`Promise was rejected. The error is ${error}`);
}
userCount.then(handleSuccess).catch(handleReject);
JS Promise 中的错误处理
假设我们有一个getUserData(userId)
函数,它返回有关用户的信息,或者如果参数出现问题则抛出错误userId
。
之前我们添加了正则try/catch
并在catch块中处理错误。
try {
console.log(getUserData(userId));
} catch (e) {
handleError(e);
}
但是,承诺中的异步代码中发生的错误无法通过常规方法捕获try/catch
。
让我们尝试用返回承诺的异步函数替换getUserData(userId)
立即返回结果的同步函数。fetchUserData(userId)
我们希望保持相同的行为 - 如果成功则显示结果,如果发生错误则处理错误。
try {
fetchUserData(userId).then(console.log);
} catch (e) {
handleError(e);
}
但我们不会成功。同步代码没有问题,所以执行会继续。但是,当异步代码中发生未处理的错误时,我们会收到一个错误UnhandledPromiseRejection
,程序也会结束。
为了更好地理解程序的执行顺序,我们来添加一个finally
块。它会一直运行(正如预期的那样),但它会在 之前还是之后运行呢UnhandledPromiseRejection
?
try {
fetchUserData(userId).then(console.log);
} catch (e) {
handleError(e);
} finally {
console.log('finally');
}
让我们一步一步尝试一下:
- 在
try
块中我们调用fetchUserData
函数,该函数返回Promise
状态pending
。 - 该
catch
块被忽略,因为块中没有错误try
。异步执行尚未运行! - 该
finally
行显示在屏幕上。 - 异步代码中发生错误,我们在控制台中看到错误消息 -
UnhandledPromiseRejectionWarning
为了避免 Promises 中未处理的拒绝,您应该始终在 中处理它们.catch()
。
fetchUserData(userId).then(console.log).catch(handleError);
代码变得更短、更干净,并且我们摆脱了破坏代码的意外错误。
这是一个关于处理 JavaScript 承诺链中的错误的有趣的编码面试问题。
文章来源:https://dev.to/coderslang/javascript-asynchronous-programming-and-promises-1epl