웹 프론트엔드 JS 튜토리얼 Node.js에서 Async 및 Await 함수 사용

Node.js에서 Async 및 Await 함수 사용

Jun 05, 2018 pm 02:49 PM
async await node.js

이 기사에서는 Node.js의 Async 및 Await 기능에 대한 관련 지식을 주로 소개합니다. 매우 훌륭하고 참고할 가치가 있습니다. 도움이 필요한 친구가 참고할 수 있습니다.

이 기사에서는 Node.js 비동기 사용 방법을 배우게 됩니다. 콜백이나 Promise를 단순화하는 함수(async/await)

C#의 async/await, Kotlin의 코루틴, go의 고루틴과 같은 비동기 언어 구조는 이미 오랫동안 기다려온 기능입니다. 비동기 기능도 기본적으로 구현됩니다.

Node의 비동기 기능이 무엇인가요?

함수가 Async 함수로 선언되면 AsyncFunction 개체를 반환하며, 실행을 일시 중지할 수 있다는 점에서 Generator와 유사합니다. 유일한 차이점은 { value: any, done: Boolean } 객체 대신 Promise를 반환한다는 것입니다. 그래도 여전히 매우 유사하므로 co 패키지를 사용하여 동일한 기능을 얻을 수 있습니다.

비동기 함수에서는 Promise가 완료될 때까지 기다리거나 거부된 이유를 캡처할 수 있습니다.

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()
 })
}
로그인 후 복사

async/await를 사용하여 이 코드를 동기적으로 실행되는 코드처럼 보이게 만들 수 있습니다

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)
}
로그인 후 복사

이전 v8 버전에서는 Promise 거부가 있는 경우 거기에 있습니까? ? 처리되면 경고가 표시되며 거부 오류 리스너 함수를 만들 필요가 없습니다. 그러나 이 경우에는 애플리케이션을 종료하는 것이 좋습니다. 오류를 처리하지 않으면 애플리케이션이 알 수 없는 상태이기 때문입니다.

process.on('unhandledRejection', (err) => { 
 console.error(err)
 process.exit(1)
})
로그인 후 복사

async 함수 패턴

비동기 작업을 다룰 때 동기 코드처럼 보이게 만드는 예가 많이 있습니다. 문제를 해결하기 위해 Promise나 콜백을 사용하는 경우 매우 복잡한 패턴이나 외부 라이브러리를 사용해야 합니다.

루프에서 비동기 데이터 수집을 사용해야 하거나 if-else 조건을 사용해야 하는 경우 매우 복잡한 상황입니다.

지수 폴백 메커니즘

Promise를 사용하여 폴백 로직을 구현하는 것은 꽤 서투릅니다.

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)
 })
로그인 후 복사

코드는 보기 매우 까다롭고, 그런 코드는 보고 싶지 않습니다. async/await를 사용하여 이 예제를 다시 실행하여 더 간단하게 만들 수 있습니다.

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(&#39;Waiting&#39;, timeout, &#39;ms&#39;)
  await wait(timeout)
  console.log(&#39;Retrying&#39;, err.message, i)
 }
 }
}
로그인 후 복사

위 코드는 매우 편안해 보입니다. 그렇죠?

중간 값

3개의 비동기 함수가 상호 의존하는 경우 이전 예제만큼 무섭지 않습니다. , 그러면 여러 가지 추악한 솔루션 중에서 선택해야 합니다.

functionA가 Promise를 반환하면 functionB에는 이 값이 필요하고 functioinC에는 functionA와 functionB가 완료된 후의 값이 필요합니다.

옵션 1: 크리스마스 트리

function executeAsyncTask () {
 return functionA()
 .then((valueA) => {
  return functionB(valueA)
  .then((valueB) => {   
   return functionC(valueA, valueB)
  })
 })
}
로그인 후 복사

이 솔루션을 사용하면 세 번째 then에서 valueA와 valueB를 얻을 수 있고, 그런 다음 이전 두 then과 마찬가지로 valueA와 valueB의 값을 얻을 수 있습니다. 여기서는 크리스마스 트리를 평면화할 수 없습니다(파멸 지옥). 그렇게 하면 클로저를 잃게 되고 valueA는 functionC에서 사용할 수 없게 됩니다.

옵션 2: 상위 수준 범위로 이동

function executeAsyncTask () {
 let valueA
 return functionA()
 .then((v) => {
  valueA = v
  return functionB(valueA)
 })
 .then((valueB) => {
  return functionC(valueA, valueB)
 })
}
로그인 후 복사

이 크리스마스 트리에서는 더 높은 범위의 보유 변수 valueA를 사용합니다. valueA의 범위가 모든 범위 외부에 있으므로 functionC를 가져올 수 있기 때문입니다. 첫 번째 functionA가 완료됩니다.

이것은 .then 체인을 평탄화하기 위한 매우 "올바른" 구문이지만, 이 방법에서는 동일한 값을 유지하기 위해 두 개의 변수 valueA와 v를 사용해야 합니다.

옵션 3: 추가 배열 사용

function executeAsyncTask () {
 return functionA()
 .then(valueA => {
  return Promise.all([valueA, functionB(valueA)])
 })
 .then(([valueA, valueB]) => {
  return functionC(valueA, valueB)
 })
}
로그인 후 복사

functionA의 배열을 사용하여 valueA와 Promise를 함께 반환하면 크리스마스 트리를 효과적으로 평면화할 수 있습니다(콜백 지옥).

옵션 4: 도우미 함수 작성

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))
로그인 후 복사

이것은 가능합니다. 컨텍스트 변수 선언을 마스크하는 도우미 함수를 작성하세요. 그러나 이러한 코드는 읽기가 매우 어렵습니다. 특히 이러한 마법에 익숙하지 않은 사람들에게는 더욱 그렇습니다.

async/await를 사용하면 문제가 마술처럼 사라졌습니다

async function executeAsyncTask () {
 const valueA = await functionA()
 const valueB = await functionB(valueA)
 return function3(valueA, valueB)
}
로그인 후 복사

async/await를 사용하여 여러 병렬 요청 처리

위의 것과 유사합니다. 한 번에 여러 비동기 작업을 실행한 다음 다른 위치에서 사용하려는 경우 값 ​async/await를 사용하여 쉽게 확인할 수 있습니다.

async function executeParallelAsyncTasks () {
 const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ])
 doSomethingWith(valueA)
 doSomethingElseWith(valueB)
 doAnotherThingWith(valueC)
}
로그인 후 복사

배열 반복 방법

map , filter 및 Reduce 메서드에서 비동기 함수를 사용할 수 있습니다. 비록 직관적이지 않을 수 있지만 콘솔에서 다음 코드를 실험해 볼 수 있습니다.

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))
로그인 후 복사

해결 방법:

[ Promise { <pending> }, Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ]
[ 1, 2, 3, 4 ]
10
로그인 후 복사

맵 반복 데이터인 경우 반환 값은 [2, 4, 6입니다. , 8 ], 유일한 문제는 각 값이 AsyncFunction 함수에 의해 Promise에 래핑된다는 것입니다

따라서 해당 값을 얻으려면 Promise.All()에 배열을 전달하여 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))
로그인 후 복사

이게 더 쉬울 것 같나요?

반복자에 장기 실행 동기 논리와 또 다른 장기 실행 비동기 작업이 있는 경우 async/await 버전이 여전히 유용할 때가 많습니다

这种方式当你能拿到第一个值,就可以开始做一些计算,而不必等到所有 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+的版本不妨尝试一下,或许会有新的收获。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

如何获取Vue中的this.$router.push参数

在angularJs-$http中如何实现百度搜索时的动态下拉框

在angularjs数组中如何判断是否含有某个元素

위 내용은 Node.js에서 Async 및 Await 함수 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Node의 메모리 제어에 관한 기사 Node의 메모리 제어에 관한 기사 Apr 26, 2023 pm 05:37 PM

Non-Blocking, Event-Driven 기반으로 구축된 Node 서비스는 메모리 소모가 적다는 장점이 있으며, 대규모 네트워크 요청을 처리하는데 매우 적합합니다. 대규모 요청을 전제로 '메모리 제어'와 관련된 문제를 고려해야 합니다. 1. V8의 가비지 수집 메커니즘과 메모리 제한 Js는 가비지 수집 기계에 의해 제어됩니다.

Node V8 엔진의 메모리와 GC에 대한 자세한 그래픽 설명 Node V8 엔진의 메모리와 GC에 대한 자세한 그래픽 설명 Mar 29, 2023 pm 06:02 PM

이 기사는 NodeJS V8 엔진의 메모리 및 가비지 수집기(GC)에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다.

es6 또는 es7에 비동기가 있습니까? es6 또는 es7에 비동기가 있습니까? Jan 29, 2023 pm 05:36 PM

비동기는 es7입니다. async 및 wait는 ES7에 새로 추가된 기능이며 비동기 작업을 위한 솔루션입니다. async/await는 공동 모듈 및 생성기 기능을 위한 구문 설탕이라고 할 수 있으며, 더 명확한 의미로 js 비동기 코드를 해결합니다. 이름에서 알 수 있듯이 async는 "비동기"를 의미합니다. async는 async와 wait 사이에 엄격한 규칙이 있음을 선언하는 데 사용되며, wait는 비동기 함수로만 작성될 수 있습니다.

최고의 Node.js Docker 이미지를 선택하는 방법에 대해 이야기해 볼까요? 최고의 Node.js Docker 이미지를 선택하는 방법에 대해 이야기해 볼까요? Dec 13, 2022 pm 08:00 PM

Node용 Docker 이미지를 선택하는 것은 사소한 문제처럼 보일 수 있지만 이미지의 크기와 잠재적인 취약점은 CI/CD 프로세스와 보안에 상당한 영향을 미칠 수 있습니다. 그렇다면 최고의 Node.js Docker 이미지를 어떻게 선택합니까?

Node의 파일 모듈에 대해 자세히 이야기해 보겠습니다. Node의 파일 모듈에 대해 자세히 이야기해 보겠습니다. Apr 24, 2023 pm 05:49 PM

파일 모듈은 파일 읽기/쓰기/열기/닫기/삭제 추가 등과 같은 기본 파일 작업을 캡슐화한 것입니다. 파일 모듈의 가장 큰 특징은 모든 메소드가 **동기** 및 ** 두 가지 버전을 제공한다는 것입니다. 비동기**, sync 접미사가 있는 메서드는 모두 동기화 메서드이고, 없는 메서드는 모두 이기종 메서드입니다.

Node.js 19가 공식적으로 출시되었습니다. Node.js의 6가지 주요 기능에 대해 이야기해 보겠습니다! Node.js 19가 공식적으로 출시되었습니다. Node.js의 6가지 주요 기능에 대해 이야기해 보겠습니다! Nov 16, 2022 pm 08:34 PM

Node 19가 정식 출시되었습니다. 이 글에서는 Node.js 19의 6가지 주요 기능에 대해 자세히 설명하겠습니다. 도움이 되셨으면 좋겠습니다!

Node.js의 GC(가비지 수집) 메커니즘에 대해 이야기해 보겠습니다. Node.js의 GC(가비지 수집) 메커니즘에 대해 이야기해 보겠습니다. Nov 29, 2022 pm 08:44 PM

Node.js는 GC(가비지 수집)를 어떻게 수행하나요? 다음 기사에서는 이에 대해 설명합니다.

Node의 이벤트 루프에 대해 이야기해 봅시다. Node의 이벤트 루프에 대해 이야기해 봅시다. Apr 11, 2023 pm 07:08 PM

이벤트 루프는 Node.js의 기본 부분이며 메인 스레드가 차단되지 않도록 하여 비동기 프로그래밍을 가능하게 합니다. 이벤트 루프를 이해하는 것은 효율적인 애플리케이션을 구축하는 데 중요합니다. 다음 기사는 Node.js의 이벤트 루프에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다!

See all articles