如何用JavaScript的回调函数做出承诺

news/2024/7/2 23:19:10

by Adham El Banhawy

由Adham El Banhawy

如何用JavaScript的回调函数做出承诺 (How to make a Promise out of a Callback function in JavaScript)

Back-end developers run into challenges all the time while building applications or testing code. As a developer who is fairly new and getting acquainted with those challenges, I have never run into a challenge or inconvenience more frequently — or more memorable — than with callback functions.

后端开发人员在构建应用程序或测试代码时始终遇到挑战。 作为一个相当新手并熟悉这些挑战的开发人员,我从来没有遇到比回调函数更频繁(或更令人难忘)的挑战或不便

I am not going to delve too deeply into the details of callback and its pros and cons or alternatives like promises and async/await. For a more vivid explanation, you can check out this article which explains them thoroughly.

我不会深入探讨回调的细节及其优缺点或诸如promises和async / await之类的替代方法。 有关更生动的解释,您可以查看这篇文章 ,对它们进行彻底的解释。

回调地狱 (Callback Hell)

Callbacks are a useful feature of JavaScript’s that enables it make asynchronous calls. They are functions that are usually passed on as a second parameter to another function that is fetching data or doing an I/O operation that takes time to complete.

回调是JavaScript的一项有用功能,可使其进行异步调用。 它们是通常作为第二个参数传递给另一个函数的函数,该函数正在获取数据或执行需要花费时间才能完成的I / O操作。

For example, try making an API call using the request module or connecting to a MongoDB database. But what if both calls depend on each other? What if the data you’re fetching is the MongoDB URL that you need to connect to?

例如,尝试使用request进行API调用 模块或连接到MongoDB数据库。 但是,如果两个调用相互依赖怎么办? 如果您要获取的数据是您需要连接的MongoDB URL,该怎么办?

You’d have to nest these calls inside each other:

您必须将这些调用相互嵌套:

request.get(url, function(error, response, mongoUrl) {if(error) throw new Error("Error while fetching fetching data");MongoClient.connect(mongoUrl, function(error, client) {if(error) throw new Error("MongoDB connection error");console.log("Connected successfully to server");    const db = client.db("dbName");// Do some application logicclient.close();});});

Okay…so where’s the problem? Well, for one thing, the readability of the code suffers from this technique.

好吧...问题出在哪里? 好吧,一方面,这种技术使代码的可读性受到影响。

It may seem OK at first when the codebase is small. But this doesn’t scale well, especially if you go more layers deeper into the nested callbacks.

当代码库较小时,乍一看似乎还可以。 但这不能很好地扩展,特别是如果您在嵌套回调中更深入一些。

You will end up with a lot of closing brackets and curly braces that will confuse you and other developers no matter how neatly formatted your code is. There is a website called callbackhell that addresses this specific issue.

最终,您将得到大量的括弧和花括号,无论您的代码格式如何整洁,都会使您和其他开发人员感到困惑。 有一个名为callbackhell的网站可以解决此特定问题。

I hear some of you, including my naïve past self, telling me wrap it in an async function then await the callback function. This just doesn’t work.

我听到一些人,包括我过去的天真自我,告诉我将其包裹在async 函数然后await回调函数。 这就是行不通的。

If there is any code block after the the function that uses callbacks, that code block will execute and will NOT wait for the callback.

如果在使用回调的函数之后有任何代码块,则该代码块将执行且不会 等待回调。

Here’s that mistake that I did before:

这是我之前犯过的错误:

var request = require('request');// WRONGasync function(){let joke;let url = "https://api.chucknorris.io/jokes/random"await request.get(url, function(error, response, data) {if(error) throw new Error("Error while fetching fetching data");let content = JSON.parse(data);joke = content.value;});console.log(joke); // undefined};// Wrongasync function(){let joke;let url = "https://api.chucknorris.io/jokes/random"request.get(url, await function(error, response, data) {if(error) throw new Error("Error while fetching fetching data");let content = JSON.parse(data);joke = content.value;});console.log(joke); // undefined};

Some more experienced devs might say “Just use a different library that uses promises to do the same thing, like axios, or just use fetch”. Sure I can in that scenario, but that’s just running away from the problem.

一些经验更丰富的开发人员可能会说:“只需使用一个不同的库即可使用诺言来完成相同的工作,例如axios , 或仅使用提取 ” 当然可以,但是这确实可以解决问题。

Besides, this is just an example. Sometimes you can be locked into using a library that doesn’t support promises with no alternatives. Like using software development kits (SDKs) to communicate with platforms like Amazon Web Services (AWS), Twitter, or Facebook.

此外,这仅是示例。 有时您可能会被锁定为使用不支持promise且没有其他选择的库。 就像使用软件开发套件(SDK)与Amazon Web Services(AWS),Twitter或Facebook之类的平台进行通信一样。

Sometimes, even using a callback to do a very simple call with a quick I/O or CRUD operation is fine, and no other logic depends on its results. But you might be constrained by the runtime environment like in a Lambda function which would kill all process once the main thread finishes, regardless of any asynchronous calls that did not complete.

有时,即使使用回调通过快速的I / O或CRUD操作进行非常简单的调用也可以,并且其他逻辑均不取决于其结果。 但是您可能会受到Lambda函数之类的运行时环境的约束,该函数会在主线程完成后终止所有进程,而不管所有未完成的异步调用如何。

解决方案1(简单):使用Node的“ util”模块 (Solution 1 (easy): Use Node’s “util” module)

The solution is surprisingly simple. Even if you’re a little uncomfortable with the idea of promises in JavaScript, you will love how you can solve this issue using them.

解决方案非常简单。 即使您对JavaScript中的Promise想法有点不满意,您也会喜欢如何使用Promise解决此问题。

As pointed out by Erop and Robin in the comments, Nodejs version 8 and above now support turning callback functions into promises using the built-in util module.

正如Erop和Robin在评论中所指出的那样,Nodejs 8及更高版本现在支持使用内置util模块将回调函数转化为promises。

const request = require('request');const util = require('util');const url = "https://api.chucknorris.io/jokes/random";// Use the util to promisify the request methodconst getChuckNorrisFact = util.promisify(request);// Use the new method to call the API in a modern then/catch patterngetChuckNorrisFact(url).then(data => {let content = JSON.parse(data.body);console.log('Joke: ', content.value);}).catch(err => console.log('error: ', err))

The above code solves the problem neatly using the util.promisify method available from nodejs core library.

上面的代码使用util.promisify巧妙地解决了问题 可从nodejs核心库获得的方法。

All you have to do is use the callback function as an argument to util.promisify, and store it an a variable. In my case, that’s getChuckNorrisFact.Then you use that variable as a function that you can use like a promise with the .then() and the .catch() methods.

您要做的就是将回调函数用作util.promisify的参数,并将其存储为变量。 就我而言,这是getChuckNorrisFact。然后使用该变量作为一个功能,您可以使用像的。然后承诺().catch()方法。

解决方案2(涉及):将回调变成承诺 (Solution 2 (involved): Turn the Callback into a Promise)

Sometimes, using the request and util libraries is just not possible, whether it’s because of a legacy environment/code base or doing the requests from the client-side browser, you have to wrap a promise around your callback function.

有时,无论是由于旧版环境/代码库还是从客户端浏览器执行请求,都无法使用request和util库,您必须在回调函数周围包裹一个Promise。

Let’s take the Chuck Norris example above, and turn that into a promise.

让我们以上面的Chuck Norris为例,并将其变成一个承诺。

var request = require('request');
let url = "https://api.chucknorris.io/jokes/random";// A function that returns a promise to resolve into the data //fetched from the API or an error
let getChuckNorrisFact = (url) => {return new Promise((resolve, reject) => {request.get(url, function(error, response, data){if (error) reject(error);let content = JSON.parse(data);let fact = content.value;resolve(fact);})});
};getChuckNorrisFact(url).then(fact => console.log(fact) // actually outputs a string
).catch(error => console.(error)
);

In the code above, I put the callback-based request function inside a Promise wrapper Promise( (resolve, reject) => { //callback function}). This wrapper allows us to call the getChuckNorrisFact function like a promise with the .then()and .catch() methods. When the getChuckNorrisFact is called, it executes the request to the API and waits for either a resolve() or a reject() statement to execute. In the callback function, you simply pass the retrieved data into the resolve or reject methods.

在上面的代码中,我将基于回调的request函数放入Promise包装器Promise( (resolve, reject) => { //callback function}) 。 这个包装器允许我们像getChuckNorrisFact .then().catch()方法一样调用getChuckNorrisFact函数。 调用getChuckNorrisFact ,它将执行对API的请求,并等待 resolve()reject()语句执行。 在回调函数中,您只需将检索到的数据传递到resolve或reject方法。

Once the data (in this case, an awesome Chuck Norris fact) is fetched and passed to the resolver, the getChuckNorrisFact executes the then() method. This will return the result that you can use inside a function inside the then() to do your desired logic — in this case displaying it to the console.

一旦获取了数据(在这种情况下,这是一个很棒的Chuck Norris事实)并将其传递给解析器,则getChuckNorrisFact执行then()方法。 这将返回结果,您可以then()内部的函数中使用该结果来执行所需的逻辑—在这种情况下,将其显示在控制台上。

You can read more about it in the MDN Web Docs.

您可以在MDN网络文档中阅读有关此内容的更多信息。

翻译自: https://www.freecodecamp.org/news/how-to-make-a-promise-out-of-a-callback-function-in-javascript-d8ec35d1f981/


http://lihuaxi.xjx100.cn/news/239184.html

相关文章

利用java虚拟机的工具jmap分析java内存情况

2019独角兽企业重金招聘Python工程师标准>>> 有时候碰到性能问题,比如一个java application出现out of memory,出现内存泄漏的情况,再去修改bug可能会变得异常复杂,利用工具去分析整个java application 内存占用情况,然…

oracle10g删除asm组,Oracle 10G RAC 删除已有节点

如果现在在RAC集群中有三个节点c1、c2、c3:如果想要卸载c3节点。1、在c1或者c2上删除c3实例运行dbca然后选择Oracle Real Application Clusters database选择Instance Management选择Delete an instance选择实例,填写用户名密码,Next选择c3: …

Vue.js双向绑定的实现原理

Vue.js 最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。本文仅探究双向绑定是怎样实现的。先讲涉及的知识点,再用简化得不能再简化的代码实现一个简单的 hello world 示例。 一、访问器属性 访问器属性是对象中的一种特殊属性&a…

迷宫出路代码_如何在软件开发的迷宫中找到自己的出路

迷宫出路代码by Tim Kleier蒂姆克莱尔(Tim Kleier) 如何在软件开发的迷宫中找到自己的出路 (How to find your way through the corn maze of software development) The corn maze is one of my favorite challenges to tackle. It’s an unnerving experience, especially w…

Oracle数据库联邦,使用联邦数据库将oracle表迁移到DB2(9.7)中的脚本说明

由于兄弟项目组要测试,需要将oracle中的表迁移到db2中,操作步骤如下:#1 在windows数据库中建联邦数据库服务器\用户映射connect to sampleCREATE WRAPPER DRDA LIBRARY db2drda.dll;--创建DB2包装器CREATE WRAPPER NET8 LIBRARY db2net8.dll;…

laravel5.4 关于数据填充的知识

需求:大量excel表格数据 集中整理到一个规定数据表中,并且增加新字段做标记步骤:把需要整理的excel表格提前存放到mysql数据库指定的表中 ,可以用图形化工具来执行! 核心:利用laravel5.4 框架自带的填充功能…

6.1.1 验证注解的使用

数据注解特性定义在名称空间System.ComponentModel.DataAnnotations 中(但接下来 将看到,有些特性不是定义在这个名称空间中)。它们提供了服务器端验证的功能,当在模 型的属性上使用这些特性之一时,框架也支持客户端验证。在名称空间DataAnno…

香草 jboss 工具_香草JavaScript中的记忆游戏

香草 jboss 工具by Marina Ferreira通过玛丽娜费雷拉(Marina Ferreira) 香草JavaScript中的记忆游戏 (Memory Game in Vanilla JavaScript) 在30分钟内构建一个记忆游戏,学习JS,CSS和HTML! (Learn JS, CSS and HTML by building a memory ga…