Node.js 비동기 프로그래밍_node.js에서 콜백 및 코드 디자인 패턴 분석
NodeJS의 가장 큰 판매 포인트인 이벤트 메커니즘과 비동기식 IO는 개발자에게 투명하지 않습니다. 개발자는 일부 NodeJS 반대자들로부터 비판을 받아온 이 장점을 활용하기 위해 코드를 비동기적으로 작성해야 합니다. 그러나 어쨌든 비동기 프로그래밍은 실제로 NodeJS의 가장 큰 특징입니다. 비동기 프로그래밍을 마스터하지 않고서는 NodeJS를 진정으로 배웠다고 말할 수 없습니다. 이 장에서는 비동기 프로그래밍과 관련된 다양한 지식을 소개합니다.
코드에서 비동기 프로그래밍의 직접적인 표현은 콜백입니다. 비동기 프로그래밍은 콜백에 의존하지만 콜백을 사용한 후에 프로그램이 비동기화된다고 말할 수는 없습니다. 먼저 다음 코드를 살펴보겠습니다.
function heavyCompute(n, callback) { var count = 0, i, j; for (i = n; i > 0; --i) { for (j = n; j > 0; --j) { count += 1; } } callback(count); } heavyCompute(10000, function (count) { console.log(count); }); console.log('hello');
100000000 hello
보시다시피 위 코드의 콜백 함수는 여전히 후속 코드보다 먼저 실행됩니다. JS 자체는 단일 스레드에서 실행되며 코드 조각의 실행이 완료되기 전에 다른 코드를 실행할 수 없으므로 비동기 실행 개념이 없습니다.
그러나 함수가 하는 일이 다른 스레드나 프로세스를 생성하고, JS 메인 스레드와 병렬로 작업을 수행하고, 작업이 완료되면 JS 메인 스레드에 알리는 것이라면 상황은 다릅니다. 다음 코드를 살펴보겠습니다.
setTimeout(function () { console.log('world'); }, 1000); console.log('hello');
hello world
이번에는 후속 코드 이후에 콜백 함수가 실행되는 것을 볼 수 있습니다. 위에서 언급했듯이 JS 자체는 단일 스레드이므로 비동기적으로 실행할 수 없습니다. 따라서 setTimeout과 같은 JS 사양 외부의 실행 환경에서 제공하는 특수 기능은 병렬 스레드를 생성하고 즉시 반환하는 것이라고 생각할 수 있습니다. JS 마스터에서 프로세스는 병렬 프로세스로부터 알림을 받은 후 후속 코드를 실행하고 콜백 함수를 실행할 수 있습니다. setTimeout 및 setInterval과 같은 일반적인 함수 외에도 이러한 함수에는 fs.readFile과 같은 NodeJS에서 제공하는 비동기 API도 포함됩니다.
또한 JS가 단일 스레드에서 실행된다는 사실로 돌아가서 JS는 코드 조각을 실행하기 전에 콜백 함수를 포함한 다른 코드를 실행할 수 없다고 판단합니다. 즉, 병렬 스레드가 작업을 완료하고 JS 메인 스레드에 콜백 함수를 실행하라고 통보하더라도 JS 메인 스레드가 유휴 상태가 될 때까지 콜백 함수는 실행을 시작하지 않습니다. 다음은 그러한 예입니다.
function heavyCompute(n) { var count = 0, i, j; for (i = n; i > 0; --i) { for (j = n; j > 0; --j) { count += 1; } } } var t = new Date(); setTimeout(function () { console.log(new Date() - t); }, 1000); heavyCompute(50000);
8520
보시다시피 JS 메인 스레드가 다른 코드를 실행하느라 1초 후에 호출되기로 되어 있던 콜백 함수의 실제 실행 시간이 크게 지연되었습니다.
코드 디자인 패턴
비동기 프로그래밍에는 동일한 기능을 달성하기 위해 여러 가지 고유한 코드 디자인 패턴이 있으며 동기 모드와 비동기 모드로 작성된 코드는 매우 다릅니다. 몇 가지 일반적인 패턴이 아래에 소개되어 있습니다.
함수 반환값
한 함수의 출력을 다른 함수의 입력으로 사용하는 것은 매우 일반적인 요구 사항입니다. 동기 모드에서 코드는 일반적으로 다음과 같이 작성됩니다.
var output = fn1(fn2('input')); // Do something.
비동기 모드에서는 함수 실행 결과를 반환값으로 전달하지 않고 콜백 함수를 통해서 전달하기 때문에 일반적으로 코드는 다음과 같은 방식으로 작성됩니다.
fn2('input', function (output2) { fn1(output2, function (output1) { // Do something. }); });
보시다시피 이 메서드는 하나의 콜백 함수 내에 중첩된 하나의 콜백 함수입니다. 너무 많으면 > 모양의 코드를 작성하기 쉽습니다.
배열 탐색
배열을 순회할 때 데이터 멤버에 대한 일부 처리를 순서대로 수행하는 함수를 사용하는 것도 일반적인 요구 사항입니다. 함수가 동기적으로 실행되면 일반적으로 다음 코드가 작성됩니다.
var len = arr.length, i = 0; for (; i < len; ++i) { arr[i] = sync(arr[i]); } // All array items have processed.
함수가 비동기적으로 실행되는 경우 위 코드는 루프가 끝난 후 모든 배열 구성원이 처리되었다고 보장할 수 없습니다. 배열 멤버를 순차적으로 처리해야 하는 경우 비동기 코드는 일반적으로 다음과 같이 작성됩니다.
(function next(i, len, callback) { if (i < len) { async(arr[i], function (value) { arr[i] = value; next(i + 1, len, callback); }); } else { callback(); } }(0, arr.length, function () { // All array items have processed. }));
보시다시피 위의 코드는 다음 배열 멤버만 전달하고 비동기 함수가 한 번 실행되고 실행 결과를 반환한 후 다음 실행 라운드를 시작합니다. 모든 배열 멤버가 처리될 때까지 후속 코드가 실행됩니다. 콜백을 통해 트리거됩니다.
배열 멤버를 병렬로 처리할 수 있지만 후속 코드에서 실행하기 전에 여전히 모든 배열 멤버를 처리해야 하는 경우 비동기 코드는 다음 형식으로 조정됩니다.
(function (i, len, count, callback) { for (; i < len; ++i) { (function (i) { async(arr[i], function (value) { arr[i] = value; if (++count === len) { callback(); } }); }(i)); } }(0, arr.length, 0, function () { // All array items have processed. }));
보시다시피 비동기 직렬 순회 버전과 비교해 위 코드는 모든 배열 구성원을 병렬로 처리하고 카운터 변수를 사용하여 모든 배열 구성원이 처리된 시점을 확인합니다.
예외 처리
JS 자체에서 제공하는 예외 포착 및 처리 메커니즘인 try..catch..는 동기적으로 실행되는 코드에만 사용할 수 있습니다. 아래는 예시입니다.
function sync(fn) { return fn(); } try { sync(null); // Do something. } catch (err) { console.log('Error: %s', err.message); }
Error: object is not a function
보시다시피 예외는 첫 번째 try 문을 만날 때 포착될 때까지 코드 실행 경로를 따라 버블링됩니다. 그러나 비동기 함수는 코드 실행 경로를 방해하므로 비동기 함수 실행 중 및 실행 후에 생성된 예외가 실행 경로가 중단된 위치까지 버블링될 때 try 문이 발견되지 않으면 전역 예외로 발생합니다. . 아래는 예시입니다.
function async(fn, callback) { // Code execution path breaks here. setTimeout(function () { callback(fn()); }, 0); } try { async(null, function (data) { // Do something. }); } catch (err) { console.log('Error: %s', err.message); }
/home/user/test.js:4 callback(fn()); ^ TypeError: object is not a function at null._onTimeout (/home/user/test.js:4:13) at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
因为代码执行路径被打断了,我们就需要在异常冒泡到断点之前用 try 语句把异常捕获住,并通过回调函数传递被捕获的异常。于是我们可以像下边这样改造上边的例子。
function async(fn, callback) { // Code execution path breaks here. setTimeout(function () { try { callback(null, fn()); } catch (err) { callback(err); } }, 0); } async(null, function (err, data) { if (err) { console.log('Error: %s', err.message); } else { // Do something. } });
Error: object is not a function
可以看到,异常再次被捕获住了。在 NodeJS 中,几乎所有异步 API 都按照以上方式设计,回调函数中第一个参数都是 err。因此我们在编写自己的异步函数时,也可以按照这种方式来处理异常,与 NodeJS 的设计风格保持一致。
有了异常处理方式后,我们接着可以想一想一般我们是怎么写代码的。基本上,我们的代码都是做一些事情,然后调用一个函数,然后再做一些事情,然后再调用一个函数,如此循环。如果我们写的是同步代码,只需要在代码入口点写一个 try 语句就能捕获所有冒泡上来的异常,示例如下。
function main() { // Do something. syncA(); // Do something. syncB(); // Do something. syncC(); } try { main(); } catch (err) { // Deal with exception. }
但是,如果我们写的是异步代码,就只有呵呵了。由于每次异步函数调用都会打断代码执行路径,只能通过回调函数来传递异常,于是我们就需要在每个回调函数里判断是否有异常发生,于是只用三次异步函数调用,就会产生下边这种代码。
function main(callback) { // Do something. asyncA(function (err, data) { if (err) { callback(err); } else { // Do something asyncB(function (err, data) { if (err) { callback(err); } else { // Do something asyncC(function (err, data) { if (err) { callback(err); } else { // Do something callback(null); } }); } }); } }); } main(function (err) { if (err) { // Deal with exception. } });
可以看到,回调函数已经让代码变得复杂了,而异步方式下对异常的处理更加剧了代码的复杂度。

핫 AI 도구

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

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

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

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

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

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

뜨거운 주제











파일 업로드를 처리하는 방법은 무엇입니까? 다음 글에서는 Express를 사용하여 노드 프로젝트에서 파일 업로드를 처리하는 방법을 소개하겠습니다. 도움이 되길 바랍니다.

이 기사에서는 Node의 프로세스 관리 도구인 "pm2"를 공유하고 pm2가 필요한 이유, pm2 설치 및 사용 방법에 대해 설명합니다. 모두에게 도움이 되기를 바랍니다!

Pinetwork 노드에 대한 자세한 설명 및 설치 안내서이 기사에서는 Pinetwork Ecosystem을 자세히 소개합니다. Pi 노드, Pinetwork 생태계의 주요 역할을 수행하고 설치 및 구성을위한 전체 단계를 제공합니다. Pinetwork 블록 체인 테스트 네트워크가 출시 된 후, PI 노드는 다가오는 주요 네트워크 릴리스를 준비하여 테스트에 적극적으로 참여하는 많은 개척자들의 중요한 부분이되었습니다. 아직 Pinetwork를 모른다면 Picoin이 무엇인지 참조하십시오. 리스팅 가격은 얼마입니까? PI 사용, 광업 및 보안 분석. Pinetwork 란 무엇입니까? Pinetwork 프로젝트는 2019 년에 시작되었으며 독점적 인 Cryptocurrency Pi Coin을 소유하고 있습니다. 이 프로젝트는 모든 사람이 참여할 수있는 사람을 만드는 것을 목표로합니다.

빠른 적용: PHP의 실제 개발 사례 분석 여러 파일의 비동기 HTTP 다운로드 인터넷의 발전으로 파일 다운로드 기능은 많은 웹 사이트와 응용 프로그램의 기본 요구 사항 중 하나가 되었습니다. 여러 파일을 동시에 다운로드해야 하는 시나리오의 경우 기존 동기 다운로드 방법은 비효율적이고 시간이 많이 걸리는 경우가 많습니다. 이러한 이유로 PHP를 사용하여 HTTP를 통해 여러 파일을 비동기적으로 다운로드하는 것이 점점 더 일반적인 솔루션이 되었습니다. 본 글에서는 실제 개발 사례를 통해 PHP 비동기 HTTP를 활용하는 방법을 자세히 분석해 보겠습니다.

인증은 모든 웹 애플리케이션에서 가장 중요한 부분 중 하나입니다. 이 튜토리얼에서는 토큰 기반 인증 시스템과 기존 로그인 시스템과의 차이점에 대해 설명합니다. 이 튜토리얼이 끝나면 Angular와 Node.js로 작성된 완벽하게 작동하는 데모를 볼 수 있습니다. 기존 인증 시스템 토큰 기반 인증 시스템으로 넘어가기 전에 기존 인증 시스템을 살펴보겠습니다. 사용자는 로그인 양식에 사용자 이름과 비밀번호를 입력하고 로그인을 클릭합니다. 요청한 후 데이터베이스를 쿼리하여 백엔드에서 사용자를 인증합니다. 요청이 유효하면 데이터베이스에서 얻은 사용자 정보를 이용하여 세션을 생성하고, 세션 정보를 응답 헤더에 반환하여 브라우저에 세션 ID를 저장한다. 다음과 같은 애플리케이션에 대한 액세스를 제공합니다.

인터넷의 지속적인 발전과 대중화로 인해 이메일은 사람들의 생활과 업무에 없어서는 안 될 부분이 되었으며, SMTP(Simple Mail Transfer Protocol)는 이메일 전송을 위한 중요한 프로토콜 중 하나입니다. PHP용 비동기 네트워크 통신 프레임워크인 Swoole은 비동기 SMTP 작업을 지원하여 이메일 전송을 더욱 효율적이고 안정적으로 만들어줍니다. 이 기사에서는 Swoole이 동기화 사용을 포함하여 비동기 SMTP 작업을 지원하는 방법을 소개합니다.

인터넷 비즈니스 규모가 지속적으로 성장함에 따라 높은 동시성, 고성능에 대한 요구가 점점 높아지고 있으며, PHP용 네트워크 통신 프레임워크인 Swoole은 개발자들의 선호도가 높아지고 있습니다. 그중 Swoole은 가장 일반적인 애플리케이션 시나리오 중 하나인 비동기 AMQP를 지원합니다. 이제 Swoole이 비동기 AMQP 작업을 어떻게 지원하는지 살펴보겠습니다. 먼저 AMQP가 무엇인지 명확히 해야 합니다. AMQP(AdvancedMessageQueuingProtocol) 고급

동시 및 비동기 프로그래밍 동시 프로그래밍은 동시에 실행되는 여러 작업을 처리하며, 비동기 프로그래밍은 작업이 스레드를 차단하지 않는 일종의 동시 프로그래밍입니다. asyncio는 프로그램이 메인 스레드를 차단하지 않고 I/O 작업을 수행할 수 있도록 하는 Python의 비동기 프로그래밍용 라이브러리입니다. 이벤트 루프 asyncio의 핵심은 I/O 이벤트를 모니터링하고 해당 작업을 예약하는 이벤트 루프입니다. 코루틴이 준비되면 이벤트 루프는 I/O 작업을 기다릴 때까지 이를 실행합니다. 그런 다음 코루틴을 일시 중지하고 다른 코루틴을 계속 실행합니다. 코루틴 코루틴은 실행을 일시 중지하고 다시 시작할 수 있는 함수입니다. asyncdef 키워드는 코루틴을 만드는 데 사용됩니다. 코루틴은 I/O 작업이 완료될 때까지 기다리기 위해 wait 키워드를 사용합니다. 다음과 같은 asyncio의 기본 사항
