This article mainly introduces the relevant knowledge of Async and Await functions in Node.js. It is very good and has reference value. Friends in need can refer to it
In this article, you will learn how to Use the async function (async/await) in Node.js to simplify callback or Promise.
Asynchronous language structures already exist in other languages, such as c#’s async/await, Kotlin’s coroutines, and go’s goroutines , with the release of Node.js 8, the long-awaited async function is also implemented by default.
What is the async function in Node?
When a function is declared as an Async function it returns an AsyncFunction object. They are similar to Generators in that execution can be paused. The only difference is that they return a Promise instead of a { value: any, done: Boolean } object. They are still very similar though, and you can use the co package to get the same functionality.
In an async function, you can wait for the Promise to complete or capture the reason for its rejection.
If you want to implement some of your own logic in Promise
function handler (req, res) { return request('https://user-handler-service') .catch((err) => { logger.error('Http error', err) error.logged = true throw err }) .then((response) => Mongo.findOne({ user: response.body.user })) .catch((err) => { !error.logged && logger.error('Mongo error', err) error.logged = true throw err }) .then((document) => executeLogic(req, res, document)) .catch((err) => { !error.logged && console.error(err) res.status(500).send() }) }
You can use async/await to make this code look like synchronously executed code
async function handler (req, res) { let response try { response = await request('https://user-handler-service') } catch (err) { logger.error('Http error', err) return res.status(500).send() } let document try { document = await Mongo.findOne({ user: response.body.user }) } catch (err) { logger.error('Mongo error', err) return res.status(500).send() } executeLogic(document, req, res) }
In the old In the v8 version, if there is a promise rejection that is not handled, you will get a warning and you do not need to create a rejection error listening function. However, it is recommended to exit your application in this case. Because when you don't handle errors, the application is in an unknown state.
process.on('unhandledRejection', (err) => { console.error(err) process.exit(1) })
async function pattern
When dealing with asynchronous operations, there are many examples of making them look like synchronous code. If you use Promise or callbacks to solve the problem, you need to use a very complex pattern or external library.
It is a very complicated situation when you need to use asynchronous acquisition of data in a loop or use if-else conditions.
Exponential rollback mechanism
Using Promise to implement rollback logic is quite clumsy
function requestWithRetry (url, retryCount) { if (retryCount) { return new Promise((resolve, reject) => { const timeout = Math.pow(2, retryCount) setTimeout(() => { console.log('Waiting', timeout, 'ms') _requestWithRetry(url, retryCount) .then(resolve) .catch(reject) }, timeout) }) } else { return _requestWithRetry(url, 0) } } function _requestWithRetry (url, retryCount) { return request(url, retryCount) .catch((err) => { if (err.statusCode && err.statusCode >= 500) { console.log('Retrying', err.message, retryCount) return requestWithRetry(url, ++retryCount) } throw err }) } requestWithRetry('http://localhost:3000') .then((res) => { console.log(res) }) .catch(err => { console.error(err) })
The code is very troublesome to read. , and you don’t want to see code like this. We can redo this example using async/await to make it simpler
function wait (timeout) { return new Promise((resolve) => { setTimeout(() => { resolve() }, timeout) }) } async function requestWithRetry (url) { const MAX_RETRIES = 10 for (let i = 0; i <= MAX_RETRIES; i++) { try { return await request(url) } catch (err) { const timeout = Math.pow(2, i) console.log('Waiting', timeout, 'ms') await wait(timeout) console.log('Retrying', err.message, i) } } }
The above code looks very comfortable, right
Intermediate value
Not as scary as the previous example, if you have 3 async functions that depend on each other in turn, then you have to choose from several ugly solutions.
functionA returns a Promise, then functionB needs this value and functioinC needs the values after functionA and functionB complete.
Option 1: then Christmas tree
function executeAsyncTask () { return functionA() .then((valueA) => { return functionB(valueA) .then((valueB) => { return functionC(valueA, valueB) }) }) }
Using this solution, we can get valueA and valueB in the third then, and then we can do the same as the previous two thens Get the values of valueA and valueB. You can't flatten the Christmas tree (ruin hell) here, if you do you'll lose the closure and valueA won't be available in functioinC.
Option 2: Move to the upper level scope
function executeAsyncTask () { let valueA return functionA() .then((v) => { valueA = v return functionB(valueA) }) .then((valueB) => { return functionC(valueA, valueB) }) }
In this Christmas tree, we use the higher scope retainer valueA because valueA scope Outside all then scopes, so functionC can get the value of the first functionA completion.
This is a very "correct" syntax for flattening the .then chain, however, with this approach we need to use two variables valueA and v to hold the same value.
Option 3: Use an extra array
function executeAsyncTask () { return functionA() .then(valueA => { return Promise.all([valueA, functionB(valueA)]) }) .then(([valueA, valueB]) => { return functionC(valueA, valueB) }) }
Use an array in then of functionA to return valueA and Promise together, which can effectively flatten the Christmas tree (callback hell).
Option 4: Write a helper function
const converge = (...promises) => (...args) => { let [head, ...tail] = promises if (tail.length) { return head(...args) .then((value) => converge(...tail)(...args.concat([value]))) } else { return head(...args) } } functionA(2) .then((valueA) => converge(functionB, functionC)(valueA))
This is feasible, write a helper function to shield the context variable declaration. But such code is very difficult to read, especially for people who are not familiar with these magics.
Using async/await our problems magically disappear
async function executeAsyncTask () { const valueA = await functionA() const valueB = await functionB(valueA) return function3(valueA, valueB) }
Use async/await to handle multiple parallel requests
It’s similar to the above one, if you want to execute multiple requests at once Asynchronous tasks, and then using their values in different places can be easily done using async/await.
async function executeParallelAsyncTasks () { const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ]) doSomethingWith(valueA) doSomethingElseWith(valueB) doAnotherThingWith(valueC) }
Array iteration method
You can use async functions in map, filter, and reduce methods, although they may not seem very intuitive. But you can experiment with the following code in the console.
1.map
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].map(async (value) => { const v = await asyncThing(value) return v * 2 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
2.filter
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].filter(async (value) => { const v = await asyncThing(value) return v % 2 === 0 }) } main() .then(v => console.log(v)) .catch(err => console.error(err))
3.reduce
function asyncThing (value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), 100) }) } async function main () { return [1,2,3,4].reduce(async (acc, value) => { return await acc + await asyncThing(value) }, Promise.resolve(0)) } main() .then(v => console.log(v)) .catch(err => console.error(err))
Solution:
[ Promise { <pending> }, Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ] [ 1, 2, 3, 4 ] 10
If it is map iteration data, you will see that the return value is [2, 4, 6, 8]. The only problem is that each value is wrapped in a Promise by the AsyncFunction function
So if you want to get their values, you need to pass the array to Promise.All() to unwrap the Promise.
main() .then(v => Promise.all(v)) .then(v => console.log(v)) .catch(err => console.error(err)) 一开始你会等待 Promise 解决,然后使用map遍历每个值 function main () { return Promise.all([1,2,3,4].map((value) => asyncThing(value))) } main() .then(values => values.map((value) => value * 2)) .then(v => console.log(v)) .catch(err => console.error(err))
This seems simpler?
The async/await version is still useful if you have a long-running synchronous logic and another long-running asynchronous task in your iterator
这种方式当你能拿到第一个值,就可以开始做一些计算,而不必等到所有 Promise 完成才运行你的计算。尽管结果包裹在 Promise 中,但是如果按顺序执行结果会更快。
关于 filter 的问题
你可能发觉了,即使上面filter函数里面返回了 [ false, true, false, true ] , await asyncThing(value) 会返回一个 promise 那么你肯定会得到一个原始的值。你可以在return之前等待所有异步完成,在进行过滤。
Reducing很简单,有一点需要注意的就是需要将初始值包裹在 Promise.resolve 中
重写基于callback的node应用成
Async 函数默认返回一个 Promise ,所以你可以使用 Promises 来重写任何基于 callback 的函数,然后 await 等待他们执行完毕。在node中也可以使用 util.promisify 函数将基于回调的函数转换为基于 Promise 的函数
重写基于Promise的应用程序
要转换很简单, .then 将Promise执行流串了起来。现在你可以直接使用`async/await。
function asyncTask () { return functionA() .then((valueA) => functionB(valueA)) .then((valueB) => functionC(valueB)) .then((valueC) => functionD(valueC)) .catch((err) => logger.error(err)) }
转换后
async function asyncTask () { try { const valueA = await functionA() const valueB = await functionB(valueA) const valueC = await functionC(valueB) return await functionD(valueC) } catch (err) { logger.error(err) } } Rewriting Nod
使用 Async/Await 将很大程度上的使应用程序具有高可读性,降低应用程序的处理复杂度(如:错误捕获),如果你也使用 node v8+的版本不妨尝试一下,或许会有新的收获。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在angularJs-$http中如何实现百度搜索时的动态下拉框
The above is the detailed content of Using Async and Await functions in Node.js. For more information, please follow other related articles on the PHP Chinese website!

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Atom editor mac version download
The most popular open source editor

SublimeText3 Linux new version
SublimeText3 Linux latest version

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),