Home >Web Front-end >JS Tutorial >How to convert JavaScript callbacks to Promises? Method introduction
A few years ago, callbacks were the only way to execute asynchronous code in JavaScript. There are few problems with callbacks themselves, the most notable being "callback hell".
Introduced in ES6 Promise as a solution to these problems. Finally, the async/await
keyword is introduced to provide a better experience and improve readability.
Even with the new methods, there are still many native modules and libraries that use callbacks. In this article, we will discuss how to convert JavaScript callbacks into Promises. Knowledge of ES6 will come in handy, as we'll be using features like the spread operator to simplify what we have to do.
A callback is a function parameter, which happens to be a function itself. Although we can create any function to accept another function, callbacks are mainly used for asynchronous operations.
JavaScript is an interpreted language that can only process one line of code at a time. Some tasks may take a long time to complete, such as downloading or reading large files, etc. JavaScript offloads these long-running tasks to the browser or other processes within the Node.js environment. This way it won't block other code from executing.
Usually asynchronous functions will accept callback functions, so their data can be processed after completion.
For example, we will write a callback function that will be executed after the program successfully reads the file from the hard disk.
So you need to prepare a text file named sample.txt
, which contains the following content:
Hello world from sample.txt
Then write a simple Node.js script to read the file :
const fs = require('fs'); fs.readFile('./sample.txt', 'utf-8', (err, data) => { if (err) { // 处理错误 console.error(err); return; } console.log(data); }); for (let i = 0; i < 10; i++) { console.log(i); }
After running the code, it will output:
0 ... 8 9 Hello world from sample.txt
If you use this code, you should see 0..9
being output to the console before executing the callback. This is because of JavaScript's asynchronous management mechanism. After reading the file, the callback for outputting the file content is called.
By the way, callbacks can also be used in synchronous methods. For example Array.sort()
will accept a callback function that allows you to customize the sorting of elements.
Functions that accept callbacks are called "higher-order functions".
Now we have a better callback method. So let's continue to look at what Promise is.
Promise was introduced in ECMAScript 2015 (ES6) to improve the experience of asynchronous programming. As the name suggests, the "value" or "error" that a JavaScript object will eventually return should be a Promise.
A Promise has 3 states:
Most Promises end up looking like this:
someAsynchronousFunction() .then(data => { // promise 被完成 console.log(data); }) .catch(err => { // promise 被拒绝 console.error(err); });
Promises are very important in modern JavaScript because they are the same as introduced in ECMAScript 2016 Use async/await keywords together. Using
async / await eliminates the need to write asynchronous code with callbacks or
then() and
catch().
try { const data = await someAsynchronousFunction(); } catch(err) { // promise 被拒绝 console.error(err); }This looks a lot like "normal" synchronous JavaScript. Most popular JavaScript libraries and new projects use Promises with the
async/await keyword.
fs module) There is a standard way to do this: pass the callback as the last parameter.
fs.readFile() without specifying the text encoding:
fs.readFile('./sample.txt', (err, data) => { if (err) { console.error(err); return; } console.log(data); });
Note: If you specify utf-8 as the encoding, the resulting output is a string. If not specified the output is
Buffer.
Error since it is the first parameter. There can be any number of outputs afterwards.
const util = require('util');Then use the
promisify method to convert it to a Promise:
const fs = require('fs'); const readFile = util.promisify(fs.readFile);Now, use the newly created function Make promise:
readFile('./sample.txt', 'utf-8') .then(data => { console.log(data); }) .catch(err => { console.log(err); });Alternatively, you can use the
async/await keyword given in the example below:
const fs = require('fs'); const util = require('util'); const readFile = util.promisify(fs.readFile); (async () => { try { const content = await readFile('./sample.txt', 'utf-8'); console.log(content); } catch (err) { console.error(err); } })();You can only use
async Use the
await keyword in the created function, which is why a function wrapper is used. Function wrappers are also known as immediately invoked function expressions.
如果你的回调不遵循这个特定标准也不用担心。 util.promisify()
函数可让你自定义转换是如何发生的。
注意: Promise 在被引入后不久就开始流行了。 Node.js 已经将大部分核心函数从回调转换成了基于 Promise 的API。
如果需要用 Promise 处理文件,可以用 Node.js 附带的库(https://nodejs.org/docs/lates...)。
现在你已经了解了如何将 Node.js 标准样式回调隐含到 Promise 中。从 Node.js 8 开始,这个模块仅在 Node.js 上可用。如果你用的是浏览器或早期版本版本的 Node,则最好创建自己的基于 Promise 的函数版本。
让我们讨论一下怎样把回调转为 util.promisify()
函数的 promise。
思路是创建一个新的包含回调函数的 Promise 对象。如果回调函数返回错误,就拒绝带有该错误的Promise。如果回调函数返回非错误输出,就解决并输出 Promise。
先把回调转换为一个接受固定参数的函数的 promise 开始:
const fs = require('fs'); const readFile = (fileName, encoding) => { return new Promise((resolve, reject) => { fs.readFile(fileName, encoding, (err, data) => { if (err) { return reject(err); } resolve(data); }); }); } readFile('./sample.txt') .then(data => { console.log(data); }) .catch(err => { console.log(err); });
新函数 readFile()
接受了用来读取 fs.readFile()
文件的两个参数。然后创建一个新的 Promise 对象,该对象包装了该函数,并接受回调,在本例中为 fs.readFile()
。
要 reject
Promise 而不是返回错误。所以代码中没有立即把数据输出,而是先 resolve
了Promise。然后像以前一样使用基于 Promise 的 readFile()
函数。
接下来看看接受动态数量参数的函数:
const getMaxCustom = (callback, ...args) => { let max = -Infinity; for (let i of args) { if (i > max) { max = i; } } callback(max); } getMaxCustom((max) => { console.log('Max is ' + max) }, 10, 2, 23, 1, 111, 20);
第一个参数是 callback 参数,这使它在接受回调的函数中有点与众不同。
转换为 promise 的方式和上一个例子一样。创建一个新的 Promise 对象,这个对象包装使用回调的函数。如果遇到错误,就 reject
,当结果出现时将会 resolve
。
我们的 promise 版本如下:
const getMaxPromise = (...args) => { return new Promise((resolve) => { getMaxCustom((max) => { resolve(max); }, ...args); }); } getMaxCustom(10, 2, 23, 1, 111, 20) .then(max => console.log(max));
在创建 promise 时,不管函数是以非标准方式还是带有许多参数使用回调都无关紧要。我们可以完全控制它的完成方式,并且原理是一样的。
尽管现在回调已成为 JavaScript 中利用异步代码的默认方法,但 Promise 是一种更现代的方法,它更容易使用。如果遇到了使用回调的代码库,那么现在就可以把它转换为 Promise。
在本文中,我们首先学到了如何 在Node.js 中使用 utils.promisfy()
方法将接受回调的函数转换为 Promise。然后,了解了如何创建自己的 Promise 对象,并在对象中包装了无需使用外部库即可接受回调的函数。这样许多旧 JavaScript 代码可以轻松地与现代的代码库和混合在一起。
更多编程相关知识,请访问:编程学习!!
The above is the detailed content of How to convert JavaScript callbacks to Promises? Method introduction. For more information, please follow other related articles on the PHP Chinese website!