js bifrost回调地狱

Welcome to The JS Bifrost, your pathway to the rock-solid foundation for God-level JavaScript. This article is all about how to avoid ‘Callback Hell’ and how to deal with it.

欢迎来到JS Bifrost,这是通往神级JavaScript坚实基础的途径。 本文全部涉及如何避免“回调地狱”以及如何处理它。

Image for post

The way to God-level JavaScript is not easy. It takes more than just being a good problem solver. Clean and efficient code will any day give you an edge above the others.

通往神级JavaScript的方法并不容易。 它不仅仅是一个好的问题解决者。 整洁而高效的代码将使您在任何时候都比其他任何优势。

In this article, we’ll discuss Callbacks and how to deal with the situation of Callback Hell. Callback hell is an enemy of clean and efficient code.

在本文中,我们将讨论回调以及如何处理回调地狱的情况 打回来 地狱是干净高效的代码的敌人。

Image for post

Knowing how to deal with this hell, will take you one step forward on the Bifrost to God Level JS!

知道如何应对这个地狱,将使您在Bifrost上迈向JS级!

Let’s start with the component that this hell is made up of.

让我们从组成地狱的组件开始。

回呼 (Callbacks)

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete its action. They’re so common in JavaScript that you probably have used callbacks yourself without knowing that they’re called callbacks.

回调函数是作为参数传递给另一个函数的函数,然后在外部函数内部调用该回调函数以完成其操作。 它们在JavaScript中非常常见,以至于您可能自己使用了回调,却不知道它们被称为回调。

A very simple example of the callback is:

回调的一个非常简单的示例是:

const numbers = [3, 4, 10, 20] 
const getLessThanTen = num => num < 10// Passing getLessThanTen function into filter
const lesserThanTen = numbers.filter(getLessThanTen)

In this case, getLessThanTen is the callback. Array.filter is a function is an acceptor of a callback function.

在这种情况下, getLessThanTen是回调。 Array.filter是一个函数,是回调函数的接受器。

Image for post

Callback functions are everywhere once you know what they are!

一旦知道回调函数的作用,无处不在!

Callbacks are used in two ways — in synchronous functions and asynchronous functions. In Synchronous functions, when you want a part of the code to be swapped with something else. In Asynchronous functions, when JavaScript needs to wait for something to complete, and execute the rest of the tasks given to it while waiting.

回调有两种使用方式-在同步函数和异步函数中。 在同步函数中,当您希望一部分代码与其他代码交换时。 在异步函数中,当JavaScript需要等待某些事情完成时,并在等待时执行分配给它的其余任务。

The biggest hurdle people face when trying to understand callbacks is understanding the order in which statements execute as the program runs. This majorly happens in Asynchronous codes.

人们在试图理解回调时面临的最大障碍是理解程序运行时语句执行的顺序。 这主要发生在异步代码中。

The problem in Javascript is that the only way to “pause” a computation and have “the remaining” execute asynchronously is to put “the remaining” inside a callback.

Javascript中的问题在于,“暂停”计算并使“其余”异步执行的唯一方法是将“剩余”放入回调中。

For example, say I want to run code the following code:

例如,说我要运行以下代码:

a = getData();
b = getMoreData(a);
c = getMoreData(b);
...

What happens if now I want to make the above functions asynchronous, meaning that I get want to run some other code while I am waiting for them to return their values?

如果现在我想使上述函数异步,那意味着我想在等待其他函数返回它们的值时运行其他代码,会发生什么?

In Javascript, the way to do it is using continuation passing style:

在Javascript中,方法是使用延续传递样式:

getData(function(a){
getMoreData(a, function(b){
getMoreData(b, function(c){
...
});
});
});

The above code gets uglier with every increase in callbacks. See the pyramid shape and all the closing braces at the end? This is known as Callback Hell.

上面的代码随着回调的增加而变得更加难看。 看到金字塔形状和末尾所有的闭合括号了吗? 这称为回调地狱

回调地狱 (Callback Hell)

Callback hell is a block where the use of function callbacks in asynchronous code becomes obscure or difficult to follow. Usually, when there is more than one level of indirection, code with callbacks become difficult to follow, refactor and test.

回调地狱是一个块,其中异步代码中函数回调的使用变得晦涩难懂或难以遵循。 通常,当间接引用的级别不止一种时,带有回调的代码将变得难以遵循,重构和测试。

This is how your code might look like, a Pyramid of Doom!

这就是您的代码的样子,一个“厄运金字塔”!

Image for post

If you had a file full of these, even God of JavaScript would not be able to save you! Why?

如果您有一个包含这些文件的文件,那么即使JavaScript的上帝也无法拯救您! 为什么?

Because when you have lots of callback functions in your code it gets harder to work with them.

因为当您的代码中包含大量回调函数时,使用它们会变得更加困难。

Callback Hell occurs because in JavaScript the only way to delay a computation, so that it runs after the asynchronous call returns, is to put the delayed code inside a callback function.

发生回调地狱的原因是,在JavaScript中,延迟计算的唯一方法是将延迟的代码放入回调函数中,从而延迟异步调用返回,然后再运行。

You cannot delay a code that was written in a synchronous style, so you’ll need nested callbacks.

您不能延迟以同步方式编写的代码,因此需要嵌套回调。

Let’s create a callback hell of our own and then learn the methods to deal with it.

让我们创建一个自己的回调地狱,然后学习处理它的方法。

构造回调地狱 (Constructing a Callback Hell)

Let’s imagine we are trying to make a sandwich. To make a sandwich, we need to go through the following steps:

假设我们正在尝试做一个三明治。 要制作三明治,我们需要执行以下步骤:

  1. Get patty

    取得小馅饼
  2. Cook the patty

    煮小馅饼
  3. Get the bread

    拿面包
  4. Put the cooked patty between the bread

    将煮好的肉饼放在面包之间
  5. Serve the sandwich

    服务三明治

These steps are asynchronous. We have to wait for one step to finish until we proceed with another. To wait for something in JavaScript means, we need to use a callback.

这些步骤是异步的。 我们必须等待一个步骤完成,然后再继续进行下一步。 要等待JavaScript中的内容,我们需要使用回调。

To make the sandwich, we have to make the patty first. We can only cook the patty after we get the patty from the fridge.

要制作三明治,我们必须先制作馅饼。 从冰箱里拿到小馅饼后,我们才可以煮小馅饼。

const makeSandwich = () => {
getPatty(function(patty) {
// We can only cook patty after we get it.
});
};

To cook the patty, we need to pass patty into the cookPatty function. Then, we have to wait for the patty to get cooked.

要烹饪小馅饼,我们需要将小馅饼传递给cookPatty函数。 然后,我们必须等待小馅饼煮熟。

Once the patty gets cooked, we get the bread.

小馅饼煮熟后,我们就拿到面包了。

const makeSandwich = () => {
getPatty(function(patty) {
cookPatty(patty, function(cookedPatty) {
getBread(function(bread) {
// Put patty in bread
});
});
});
};

After we get the bread, we need to put the patty between the pieces of bread.

拿到面包后,我们需要将小馅饼放在两片面包之间。

const makeSandwich = () => {
getPatty(function(patty) {
cookPatty(patty, function(cookedPatty) {
getBread(function(bread) {
putPattyBetweenBread(bread, patty, function(sandwich) {
// Serve the sandwich
});
});
});
});
};

We can’t return sandwich from makeSandwich because it’s asynchronous. We need to accept a callback to serve the sandwich.

我们无法从makeSandwich返回sandwich ,因为它是异步的。 我们需要接受回调来提供三明治。

const makeSandwich = () => {
getPatty(function(patty) {
cookPatty(patty, function(cookedPatty) {
getBread(function(bread) {
putPattyBetweenBread(bread, patty, function(sandwich) {
nextStep(sandwich)
});
});
});
});
};// Make and serve the sandwich
makeSandwich(function (sandwich) => {
serve(sandwich)
})

回调地狱的解决方案 (Solutions to Callback Hell)

There are 4 solutions:

有4个解决方案:

  1. Using Comments

    使用评论
  2. Modularise

    模块化
  3. Using Promises

    使用承诺
  4. Using Async/Await

    使用异步/等待

第一个解决方案:使用注释(First Solution: Using Comments)

The makeSandwich callback hell is simple to understand. But, if you’re reading makeSandwich for the first time, you may think “Why do we need so many callbacks to make a sandwich? It doesn’t make sense!”.

makeSandwich回调地狱很容易理解。 但是,如果您是第一次阅读makeSandwich ,您可能会想:“为什么我们需要这么多回调来制作三明治? 这没有道理!”。

In such a case, we can leave comments to explain our code.

在这种情况下,我们可以留下注释来解释我们的代码。

// Makes a sandwich
// makeSandwich contains four steps:
// 1. Get patty
// 2. Cook the patty
// 3. Get bread for the sandwich
// 4. Put the cooked patty between the bread
// 5. Serve the sandwich (from the callback)
// Callbacks are used here because each step is asynchronous.const makeSandwich = () => {
getPatty(function(patty) {
cookPatty(patty, function(cookedPatty) {
getBread(function(bread) {
putPattyBetweenBread(bread, patty, function(sandwich) {
nextStep(sandwich)
});
});
});
});
};// Make and serve the sandwich
makeSandwich(function (sandwich) => {
serve(sandwich)
})

But this gives us a reason why we had to write this type of code (Pyramid of Doom). It doesn’t ease your pain of refactoring, testing and maintaining it.

但这为我们提供了为什么必须编写此类代码(“厄运金字塔”)的原因。 它并没有减轻您进行重构,测试和维护的痛苦。

第二种解决方案:模块化 (Second Solution: Modularise)

We need to modularise our code so that it is easier to keep track of.

我们需要对代码进行模块化,以便于跟踪。

For getPatty, our first callback, we have to go to the fridge to get the patty. There are two fridges in the kitchen. Our patty is in the right fridge.

对于getPatty ,这是我们的第一个回调,我们必须去冰箱拿馅饼。 厨房里有两个冰箱。 我们的馅饼在正确的冰箱里。

const getPatty = nextStep => {
const fridge = leftFridge;
const patty = getPattyFromFridge(fridge);
nextStep(patty);
};

Now imagine if you have to write each of these steps in makeSandwich , you’ll probably faint with the sheer amount of code!

现在想象一下,如果您必须在makeSandwich编写这些步骤中的makeSandwich ,您可能会对大量的代码makeSandwich

第三种解决方案:使用承诺 (Third Solution: Using Promises)

Promises make callback hell much easier to manage. Instead of the nested code, you’ll have this:

承诺使回调地狱更易于管理。 您将拥有以下代码,而不是嵌套的代码:

const makeSandwich = () => {
return getPatty()
.then(patty => cookPatty(patty))
.then(cookedPatty => getBread(patty))
.then(breadAndPatty => putPattyBetweenBread(breadAndPatty));
};

// Make and serve sandwich
makeSandwich().then(sandwich => serve(sandwich));

This is so much easier to read, understand and manage.

这非常容易阅读,理解和管理。

第四种解决方案:异步/等待 (Fourth solution: Async/Await)

With Async/Await, you can write makeSandwich as if it’s synchronous again!

使用Async / makeSandwich ,您可以编写makeSandwich ,就好像它又是同步的一样!

const makeSandwich = async () => {
const patty = await getPatty();
const cookedPatty = await cookPatty(patty);
const bread = await getBread();
const sandwich = await putPattyBetweenBread(cookedPatty, bread);
return sandwich;
};

// Make and serve sandwich
makeSandwich().then(serve);

So easy right?

这么容易吧?

Callback Hell is not that big a problem after you see Promises and Async/Await.

在看到Promises和Async / Await之后,Callback Hell并不是什么大问题。

Image for post

Yes, they are a blessing! If you know how to use them wisely, you can really keep your code easier to follow, easier to refactor, and easier to test.

是的,他们是祝福! 如果您知道如何明智地使用它们,则可以真正使代码更易于遵循,更易于重构和更易于测试。

总结思想 (Closing Thoughts)

Promises and Async/Await are a great boon when you have to deal with Callback Hell. Writing comments and modularising the code are good solutions but only for small programs. As your code becomes large both of them will fail.

当您必须处理Callback Hell时,Promise和Async / Await是一个很大的福音。 编写注释和模块化代码是不错的解决方案,但仅适用于小型程序。 随着代码变大,它们两个都将失败。

Image for post

“You’re building your own maze, in a way, and you might just get lost in it.”― Marijn Haverbeke, Eloquent JavaScript

“某种程度上,您正在建造自己的迷宫,而您可能会迷失其中。”-雄辩JavaScript Marijn Haverbeke

Asynchronous JavaScript can be a maze of its own. But now you know the tools to deal with it and get out of the maze easily.

异步JavaScript本身就是一个迷宫。 但是,现在您知道了处理它并轻松摆脱迷宫的工具。

Congrats! You’ve moved a step forward on the Bifrost to God Level JavaScript.Watch this space to make more progress on your way to ‘God level JavaScript’ with ‘The JS Bifrost’.

恭喜! 您已经在Bifrost上向上帝级别JavaScript迈进了一步。观看此空间,可以进一步提高使用“ JS Bifrost”到“上帝级别JavaScript”的方式。

翻译自: https://medium.com/globant/the-js-bifrost-callback-hell-4c699e1954b8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值