什么是JavaScript承诺?

If you have never heard of Promises in JavaScript, chances are that you have experienced what is often termed as callback hell. Callback hell is referring to the situation wherein you end up having nested callbacks to the extent that the readability of your code is severely hampered.

如果您从未听说过JavaScript中的Promises,那么您很有可能经历过通常称为callback hell的事情回调地狱是指这样的情况,您最终会嵌套嵌套的回调,以致严重阻碍了代码的可读性。

If you have never experienced callback hell, let me give you a glimpse of what it looks like. Brace yourself and try to understand what the following piece of code is trying accomplish!

如果您从未经历过回调地狱,那么让我大致了解一下它的外观。 振作起来,尝试理解下面的代码试图完成什么!

Okay, to be fair, this might have been a slightly exaggerated example. But, it proves the point that attempting to nest callbacks can drastically reduce the readability of your code.

好吧,公平地说, 这可能是一个有点夸张的例子 。 但是,事实证明,尝试嵌套回调可以大大降低代码的可读性。

In case you are wondering as to why you should bother about the readability of the code you write, then take a look at the following article which provides an in-depth answer to the query.

如果您想知道为什么要打扰所编写代码的可读性,那么请看以下文章,该文章提供了对该查询的深入解答。

Now that you realize that callback hell is notorious, let’s also briefly take a look at what causes a developer to fall into this trap in the first place.

既然您已经意识到回调地狱是臭名昭著的,那么让我们也简要地看一下是什么原因导致开发人员首先陷入这个陷阱。

The main reason we use callbacks is to handle asynchronous tasks. Many a times, this can be because we need to make an API call, receive the response, convert it to JSON, use this data to make another API call and so on. This can seem like a problem that’s innate to JavaScript, because the nature of these API calls in asynchronous by default, and there seems to no workaround.

我们使用回调的主要原因是要处理异步任务。 很多时候,这可能是因为我们需要进行API调用,接收响应,将其转换为JSON,使用此数据进行另一个API调用等等。 这似乎是JavaScript固有的问题,因为默认情况下,这些API的本质是异步调用的,而且似乎没有解决方法。

This is where JavaScript Promises come into the picture, because it is a native JavaScript feature released as part of ES6, meant to be used to avoid callback hell, without having to break up the chain of API calls into different functions.

这就是JavaScript Promises出现的地方,因为它是ES6发行的本机JavaScript功能,用于避免回调地狱,而不必将API调用链分解成不同的函数。

A Promise is an object that can be returned synchronously, after the completion of a chain of asynchronous tasks. This object can be in one of the following 3 states:

Promise是一个对象,可以在完成一系列异步任务之后同步返回。 该对象可以处于以下三种状态之一:

  • Fulfilled: This means that the asynchronous tasks did not throw any error, and that all of them have been completed successfully.

    已实现 :这意味着异步任务未引发任何错误,并且所有任务均已成功完成。

  • Rejected: This means that one or more tasks has failed to execute as expected, and an error has been thrown.

    拒绝:这意味着一个或多个任务未能按预期执行,并且引发了错误。

  • Pending: This is like an intermediate state, wherein the Promise has neither been fulfilled nor been rejected.

    待处理:这就像一个中间状态,在该状态中,既未实现也未拒绝承诺。

We say that a Promise is settled, if it is not in a pending state. This means that a Promise is settled even if it is in a rejected state.

我们说,如果Promise未处于待处理状态,则已结算 。 这意味着即使Promise处于拒绝状态,也可以解决。

Promises can help us avoid callback hell, because they can be chained using .then() any number of times.

承诺可以帮助我们避免回调地狱,因为它们可以使用.then()任意次链接。

.then() is non-blocking code. This means that the sequence of callback functions can run synchronously, as long the Promises are fulfilled at every stage of the asynchronous task.

.then()是非阻塞代码。 这意味着只要在异步任务的每个阶段都履行了Promises,回调函数的序列就可以同步运行。

This way, no matter how many asynchronous tasks there need to be, all we need is a Promise based approach to deal with them!

这样,无论需要多少异步任务,我们所需要的只是一种基于Promise的方法来处理它们!

This can work because instead of immediately returning the final value, the asynchronous task returns a Promise to supply the value at some point in the future. Since we have no code that blocks this operation, all the asynchronous tasks can take place as required, and the Promise that is returned will reflect whether or not they failed.

之所以可行,是因为异步任务不是立即返回最终值,而是返回一个Promise,以在将来的某个时刻提供该值。 由于我们没有阻止该操作的代码,因此所有异步任务都可以按需进行,并且返回的Promise将反映它们是否失败。

By now, you understand what a Promise is. But how do you use them? Let’s deal with that in this section.

到目前为止,您已经了解了什么是Promise。 但是如何使用它们呢? 让我们在本节中进行处理。

Consider an example which uses plain old callbacks, which we can then convert to a Promise based approach.

考虑一个使用普通旧回调的示例,然后我们可以将其转换为基于Promise的方法。

Image for post
An example for a set of callbacks
一组回调的示例

As you can see, although this is a contrived example, it is pretty tricky to follow the chain of function calls as the number of callbacks increases. Now, if we chain all our callbacks to the returned promise itself, we can end up with the following Promise chain.

如您所见,尽管这是一个人为的示例,但是随着回调次数的增加,遵循函数调用链非常棘手。 现在,如果我们将所有回调链接到返回的Promise本身,则可以得到以下Promise链。

A Promise chain instead of nested callbacks
A Promise chain instead of nested callbacks
一个Promise链,而不是嵌套的回调

Here, we assume that the demoFunction returns a Promise after it is invoked. This Promise eventually evaluates to either a valid result, or an error. In case the Promise is fulfilled, the .then() statement is executed.

在这里,我们假设demoFunction在被调用后返回一个Promise。 此Promise最终评估为有效结果错误 。 万一无极满足 ,则执行。那么()语句。

It is important to note that every .then() returns a new Promise. So, when the demoFunction returns a Promise, the resolved value is result1 which is used to invoke the next function in the chain, the firstCallback(). This continues until the final callback is invoked.

重要的是要注意每个。 then()返回一个新的Promise。 因此,当demoFunction返回Promise时,解析的值为result1 ,该值用于调用链中的下一个函数firstCallback() 。 这一直持续到调用最终回调为止。

In case any of the Promises get rejected, it means that an error was thrown by one of the callbacks. In that case, the remaining .then() statements are short-circuited and the .catch() statement is executed.

如果任何Promises被拒绝 ,则意味着其中一个回调引发了错误。 在这种情况下,其余的.then()语句将被短路并执行.catch()语句。

You may notice that a single .catch() is needed to act as a error fallback, whereas in the previous version of the code, we had to provide failureCallback function as a fallback error handler, to each callback function call.

您可能会注意到,需要一个.catch()来充当错误回退,而在以前的代码版本中,我们必须为每个回调函数调用提供failureCallback函数作为回退错误处理程序。

This way, you can easily convert a series of nested callbacks into a Promise chain.

这样,您可以轻松地将一系列嵌套的回调转换为Promise链。

Until now we have learnt a new way to deal with callbacks using Promises. But we haven’t discussed where we get these Promises from. In this section, you can learn how to convert any function, such that it returns a Promise which can be chained to a list of .then() statements.

到目前为止,我们已经学习了使用Promises处理回调的新方法。 但是我们还没有讨论从何处获得这些承诺。 在本节中,您将学习如何转换任何函数,使其返回一个Promise,该Promise可以链接到.then()语句列表。

Consider the following example wherein we have a function which doesn’t return a Promise, hence it cannot be included in a Promise chain yet.

考虑下面的示例,其中我们有一个不返回Promise的函数,因此尚不能包含在Promise链中。

setTimeout(() => callbackFunc("5 seconds passed"), 5*1000);

setTimeout(() => callbackFunc("5 seconds passed"), 5*1000);

Here, although the callbackFunc has a very low chance of throwing an error, if it does do so, we have no way to catch the error.

在这里,尽管callbackFunc抛出错误的可能性很小,但是如果这样做,我们就无法捕获错误。

In order to convert this function into one that returns a Promise, we can use the new keyword as follow:

为了将此函数转换为可返回Promise的函数,我们可以使用new关键字,如下所示:

const wait = ms => new Promise((resolve, reject) => {
setTimeout(resolve, ms);
};
wait(5*1000)
.then(() => callbackFunc("5 seconds"))
.catch(failureCallback);

Here, wait represents a function which returns a new Promise every time it’s invoked. We can do so using the Promise constructor, which creates a new Promise object. Hence, when wait is invoked by passing a parameter indicating the duration for setTimeout , it returns a Promise.

在这里, wait表示一个函数,该函数在每次调用时都会返回一个新的Promise 。 我们可以使用Promise构造函数来执行此操作,该构造函数将创建一个新的Promise对象。 因此,当通过传递指示setTimeout持续时间的参数来调用wait时,它将返回Promise。

Once the Promise reaches the fulfilled state, the function associated with resolve i.e, callbackFunc is invoked. If the Promise is rejected, then the failCallback is executed.

一旦Promise达到实现状态,便会调用与resolve相关的函数,即callbackFunc 。 如果Promise被拒绝 ,那么将执行failCallback

To further understand how to create your own Promises, you can go through this article, which provides a more complex example to do so.

要进一步了解如何创建自己的Promises,可以阅读本文本文提供了一个更复杂的示例。

The best resource to dive deeper into the various instance methods in the Promise constructor, is the MDN Docs.

MDN Docs是深入了解Promise构造函数中各种实例方法的最佳资源。

Although the approach laid out in this article is a simple alternative to nested callbacks, a newer version of JavaScript (EcmaScript 2017 or ES8) also has a feature to deal with callback hell!

尽管本文介绍的方法是嵌套回调的一种简单替代方法,但较新版本JavaScript(EcmaScript 2017或ES8)也具有处理回调地狱的功能!

In case you want to look into this feature called async & await, you can go through the following article. Although it is stated as a brand new feature, it is actually just syntactic sugar over the concept of Promises discussed in this article! So, in case you understand the concept of Promises, the ES8 feature of async & await is pretty easy to comprehend.

如果您想研究称为async&await的功能 ,可以阅读以下文章。 尽管它被声明为一个新功能,但实际上只是本文讨论的Promises概念的语法糖 ! 因此,如果您了解Promises的概念,那么async&await的ES8功能非常容易理解。

Hopefully, now that you are armed with Promises, you can successfully avoid falling prey to callback hell, the next time you are tasked with handling a bunch of callback functions!

希望,既然您已经准备好了Promises,就可以成功避免在下次执行一系列回调函数时成为回调地狱的牺牲品!

翻译自: https://medium.com/swlh/what-are-javascript-promises-ab868813897a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值