JavaScript Promises - 像我五岁一样解释
如果您觉得这篇文章对您有帮助,那么您很可能也会觉得我的推文对您有所帮助。所以,请务必在Twitter上关注我,以获取更多关于 Web 开发和内容创作的信息。本文最初发表在我的博客上。
大家好👋,欢迎阅读我的全新系列文章《揭秘 JavaScript Promises——一种新的学习方式》。JavaScriptpromises
非常特别。作为 Web 开发者,我们几乎无法避免学习它。相信我,即使你不相信,你的面试官也确实喜欢 Promises 😉!
另一方面,如果我们就“最难处理的 JavaScript 概念是什么? ”进行一项民意调查,你会发现“promise”正逐渐跻身榜首。你不相信吗?这是最近的民意调查结果 🙂。
在 LinkedIn 上
在推特上
因此,它无疑成为了promises
讨论的“主题”。在本系列中,你将学习 JavaScript,Promises
从入门到高级。我们将涵盖:
- 是什么
Promise
以及它的特点是什么? Promise Chain
并举例说明。- 如何处理
errors
Promises 中的问题? Mistakes
您可以使用 Promises 来做出承诺。- 如何为你的(承诺)做准备
interviews
?
本文将主要以初学者友好的方式介绍对 JavaScript promise 及其特性的基本理解。
杰克和吉尔的故事
“杰克和吉尔上山了…… ”童谣有两个主要人物:小男孩杰克和他的妹妹吉尔。让我们来改编一下这个故事,介绍一下他们的祖父母。
于是,杰克和吉尔带promise
他们的祖父母fetch
去山顶的井里打了一些水。他们开始行动去打水。与此同时,祖父母们正忙着讨论日常生活,他们想等孩子们打完水回来就开始做饭。
💡上面的插图是我根据著名的杰克和吉尔童谣即兴创作的。如有任何与世间任何事物相似之处,纯属巧合。🙂
现在有两种可能性,
- 杰克和吉尔带着水下来,开始做饭。
- “杰克摔倒了,摔碎了王冠。吉尔也跟着摔倒了。”——在这种情况下,杰克和吉尔回来了,但不幸的是,他们没有得到水。
在这个短篇故事中,有一个promise
关于如何取水的活动。孩子们可以履行这个承诺(取水),也可以因为灾难而拒绝。请注意,当杰克和吉尔在履行executing
承诺时,祖父母们并没有闲着。他们正在计划这一天。
JavaScript 的 Promise 也类似。作为开发者,我们创建它们是为了获取某些数据(来自数据存储、配置等等)。通常,获取操作可能不会立即发生。我们希望异步获取数据。这意味着我们不希望应用程序等待响应,而是在响应可用时继续处理。
因此我们的类比表可能看起来像这样,
现实生活中(使用 JavaScript) | 在我们的故事中 |
---|---|
承诺 | 杰克👦和吉尔👧取水 |
执行器函数 | 取水🏃♀️🏃♂️ |
活动 | 获取🧶 |
响应中的预期数据 | 水💧 |
消费者 | 祖父母👵👴 |
解决/实现 | ✔️成功获取烹饪用水 |
拒绝/已拒绝 | ❌ 取水灾难(错误) |
获取数据成功后的任务 | 烹饪🍚 |
如果某些术语对您来说看起来陌生或令人困惑,请不要担心。我们将在本文末尾重新讨论。
JavaScript 中的 Promise
Apromise
是一个 JavaScript 对象,允许你进行异步(又称 async)调用。当异步操作成功完成时,它会返回一个值;如果未完成,则会返回一个错误。
您可以使用构造函数方法创建承诺,
let promise = new Promise(function(resolve, reject) {
// Do something and either resolve or reject
});
我们需要将一个函数传递给Promise Constructor
。这个函数叫做executor function
(还记得打水吗?)。执行器函数接受两个参数,resolve
和reject
。这两个是执行器用来宣布结果的回调函数。
该resolve
方法表示任务成功完成(取水),而reject
则表示发生错误(灾难)。您无需实现 resolve/reject 方法。JavaScript 会提供这些方法。您需要在执行器函数中调用它们。
因此,在杰克和吉尔的故事中,该executor
函数可能如下所示,
- 例如
resolve
:
let promise = new Promise(function(resolve, reject) {
// Got the water
let value = 'water';
resolve(value); // An assurance of getting the water successfully
});
- 例如
reject
:
let promise = new Promise(function(resolve, reject) {
// OOPS, Jack fell down and broke his crown.
// And Jill came tumbling after.
reject(new Error("Disaster")); // Throwing and error
});
Promise 对象和状态
在杰克和吉尔的故事中,祖父母并没有等着孩子们去取水。他们一边计划着当天的安排,一边在计划着。无论成功取水还是遭遇灾难,杰克和吉尔都会告知他们。而且,祖父母也是用水来做饭的人。
类似地,承诺对象应该能够在执行开始、完成(解决)或返回错误(拒绝)时通知消费者。
承诺对象具有以下内部属性,
- state:此属性可以具有以下值,
- pending:执行函数启动时。在我们的故事中,就是杰克和吉尔开始打水的时候。
- fulfilled:当 Promise 成功解决时。例如,杰克和吉尔回到了水边。
- 拒绝:当承诺被拒绝时。例如,杰克和吉尔无法完成任务。
- result:此属性可以具有以下值,
- undefined:最初,当状态值为 时
pending
。 - value:当承诺被解决时(值)。
- error:当承诺被拒绝时。
- undefined:最初,当状态值为 时
已解决或已拒绝的承诺称为已解决的承诺。
因此消费者(如祖父母)需要依靠promise
对象来了解状态和价值/错误。
处理消费者的承诺
promise
构造函数返回的对象包含new Promise
所有内容。消费者可以使用它来了解state
(待处理、已完成或已拒绝)以及可能的结果(value
或error
)。
但是等等。这些属性是内部的。它们无法通过代码访问,但可以检查。这意味着我们可以使用调试工具检查state
和result
属性值,但无法直接使用程序访问它们。
那么呢?这就是我们有三个重要的处理程序方法,.then()
、.catch()
和。当 Promise 解析或拒绝时,.finally()
这些方法帮助我们在 和消费者之间建立链接。executor
.then() Promise 处理器
每个 Promise都会有一个.then()
方法。该方法的唯一目的是让消费者了解 Promise 的结果。它接受两个函数作为参数:result
和error
。
promise.then(
(result) => {
console.log(result);
},
(error) => {
console.log(error);
}
);
如果您只对成功的结果感兴趣,您可以选择只传递一个参数,
promise.then(
(result) => {
console.log(result);
}
);
类似地,如果您只对错误感兴趣,请将其null
作为第一个参数的值传递。
promise.then(
null,
(error) => {
console.log(error)
}
);
在错误情况下显式传递 a 的语法有点奇怪null
。因此,我们有一个替代方案,称为.catch()
方法,我们很快就会看到。
还要注意,你可以在该.then()
方法中做三件非常特殊的事情,
- 您可以从中得到
return
另一个。promise
- 您可以
return
包含一个值undefined
。 - 您可能会
throw
犯错误。
这三点将作为后续文章学习的基础Promise Chain
。现在,让我们为杰克和吉尔编写代码,履行给祖父母取水的承诺。
// 1. Create a Promise to fetch the water
let promise = new Promise(function(resolve, reject) {
// Pretend a delay of 2 sec to fetch it!
setTimeout(function() {
// Fetched the water. Let's resolve the promise
resolve('Hurray! Fetched the Water.');
}, 2000);
});
// 2. Function to Set up the handler to handle a promise result.
// It is to inform the grandparents when the result is available.
const grandParentsCooking = () => {
// The handler function to handle the resolved promise
promise.then(function(result) {
// Fetched the water. Now grandparents can start the cooking
console.log(`cooking rice with the ${result}`);
});
}
// 3. Calling the function to activate the set up.
grandParentsCooking();
输出,
cooking rice with the Hurray! Fetched the Water.
因此,上面的代码中发生了三件事,
-
我们创建了 Promise。在执行器函数中,我们延迟 2 秒来模拟异步调用(实际上,爬山和取水需要更多时间!)。然后我们解析 Promise,并返回“好耶!取到水了!”
-
我们设置了一个信息机制,让祖父母们知道何时取水成功。我们使用了
.then()
处理程序来实现这个目的。一旦他们取到水,他们就开始做饭。注意,这里我们只是定义了它,而不是调用它。 -
通过调用函数来激活处理程序。
.catch() Promise 处理器
你可以使用这个处理程序方法来处理 Promise 的错误(拒绝)。正如我们之前讨论过的,用这个处理程序来处理错误比用方法处理要好得多.then()
。所以现在让我们用 JavaScript Promise 来处理“杰克摔倒了……”的情况。
// 1. Create the promise
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
// Reject it as the disaster happend.
reject(new Error('Jack fell down and broke his crown. And Jill came tumbling after.'));
}, 2000);
});
// 2. Inform grandparents
// but this time we are using the .catch
const grandParentsCooking = () => {
promise.catch(function(error) {
console.error(`OMG ${error.message}`);
});
}
// 3. Call the function
grandParentsCooking();
输出,
需要注意的几点
- 我们使用
reject
上面代码中的方法来拒绝这个承诺。 reject
你可以像方法一样向方法传递任何类型的参数resolve
。不过,建议使用Error
对象。我们将在后续关于使用 Promise 进行错误处理的文章中详细讨论。- 我们使用
.catch()
Handler 来处理拒绝。在实际应用中,你会同时使用.then()
和.catch()
方法来处理 resolve 和 rejection 的情况。我们将在本系列的 Promise 链式调用文章中学习它。
.finally() Promise 处理器
handler方法.finally()
执行清理操作,例如停止加载器、关闭活动连接等等。无论 Promise 被 resolve 还是 rejection,该.finally()
方法都会被调用。
let loading = true;
loading && console.log('Loading...');
// Getting the promise
promise = getPromise();
promise.finally(() => {
loading = false;
console.log(`Promise Settled and loading is ${loading}`);
}).then((result) => {
console.log({result});
});
需要注意的关键点是,该.finally()
方法会将结果或错误传递给下一个处理程序,该处理程序可以再次调用.then()
或.catch()
。这很方便,我们将在 Promise 链文章中看到很多这样的例子。
总之
总而言之,
Promise
是 JavaScript 中异步概念的重要组成部分。- 您可以使用构造函数创建一个承诺。
- 构造函数接受执行函数作为参数并返回承诺对象。
- 对象
promise
有两个内部属性:state 和 result。这些属性无法通过代码访问。 - 承诺的消费者可以使用
.then()
、.catch()
和.finally()
方法来处理承诺。 - 通过杰克和吉尔的故事等例子可以更好地理解承诺。
我希望现在您能够更好地理解类比表。
现实生活中(使用 JavaScript) | 在我们的故事中 |
---|---|
承诺 | 杰克👦和吉尔👧取水 |
执行器函数 | 取水🏃♀️🏃♂️ |
活动 | 获取🧶 |
响应中的预期数据 | 水💧 |
消费者 | 祖父母👵👴 |
解决/实现 | ✔️成功获取烹饪用水 |
拒绝/已拒绝 | ❌ 取水灾难(错误) |
获取数据成功后的任务 | 烹饪🍚 |
暂时就这些。请继续关注本系列的第二篇文章。我们将Promise Chain
通过另一个故事来了解。
希望你喜欢这篇文章,或者觉得它对你有帮助。欢迎在Twitter 上关注我 (@tapasadhikary),分享我的想法、技巧和代码实践。
您可能还喜欢,
文章来源:https://dev.to/atapas/javascript-promises-explain-like-im- Five-525g