Node.js의 비동기성에 대한 심층 분석

青灯夜游
풀어 주다: 2021-06-08 18:54:48
앞으로
2437명이 탐색했습니다.

이 글에서는 Node.js의 비동기식에 대해 자세히 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Node.js의 비동기성에 대한 심층 분석

Node.js 비동기에 대해 피할 수 없는 두 가지가 있습니다: 비 차단 I/O이벤트 루프입니다. Node.js가 고성능이라 할 수 있고 온라인 환경에서 사용할 수 있는 것은 바로 이 두 가지 때문입니다. 그럼 Node.js의 비동기 메커니즘과 사용법에 대해 알아볼까요? [추천 학습: "nodejs 튜토리얼"]

Node.js의 비차단 I/O

  • I/O는 입력/출력입니다. 시스템의 Input/Output,一个系统的输入和输出
  • 阻塞 I/O 和非阻塞 I/O 的区别就在于系统接收输入再到输出期间,能不能接收其他输入

以点菜吃饭为例子:去饭堂点菜吃饭需要排队等待,在这个过程中,阿姨每次只能接待一个人,“点菜-阿姨抖勺装菜-把饭菜给到你”这个过程中阿姨并不能接收其他人的点菜,这个就是阻塞 I/O;而去餐馆点菜吃饭,去到餐馆就可以跟服务员你要吃番茄炒蛋,服务员记下来之后交给后厨,这时候来了另一桌人就把服务员招呼过去说想吃小龙虾,也就是说,在把菜给你上上来之前服务员接收了其他人的点菜,那这个就是非阻塞型 I/O。

理解非阻塞 I/O 的要点在于

  • 确定一个进行 Input/Output 的系统
  • 思考在 I/O 过程中,能不能进行其他 I/O

那在点菜吃饭这个例子中,一个进行 Input/Output 的系统就是点餐-后厨(阿姨)处理-上菜这样一个能让你吃上饭的系统;点餐就是 Input,上菜就是 Output,在这个例子中判断两者是非阻塞型还是阻塞型的关键就在于在点菜上菜这个过程中能不能接受其它的点菜上菜。就好比你点了个佛跳墙,等上菜可能就要好久了,然后来的人都是点一些简单的菜品,一分钟炒一份炒粉的那种,可能就是来来回回几波人之后都还没能给你上菜。

而 Node.js 它是用来操纵计算机的,一些如读取文件之类的操作是非常耗时的,要是不能进行其它的 I/O,那么处理效率就很会很低了,这也是 Node.js 是非阻塞型 I/O 的一个原因。

Node.js 的事件循环

Node.js 启动的时候会初始化由 libuv 提供的事件循环,每次的事件循环都包含6个阶段,这6个阶段会在每一次的事件循环当中按照下图当中的顺序反复执行,如下图:

Node.js의 비동기성에 대한 심층 분석

  • timers 阶段:这个阶段执行 timersetTimeoutsetInterval)的回调
  • I/O callbacks 阶段 :处理一些上一轮循环中的少数未执行的 I/O 回调
  • idleprepare 阶段 :仅 Node 内部使用
  • poll 阶段 :获取新的 I/O 事件, 适当的条件下 Node 将阻塞在这里
  • check 阶段 :执行 setImmediate() 的回调
  • close callbacks 阶段:执行 socketclose 事件回调

每个阶段都有一个先入先出的(FIFO)的用于执行回调的队列,事件循环运行到每个阶段,都会从对应的回调队列中取出回调函数去执行,直到队列当中的内容耗尽,或者执行的回调数量达到了最大

然后事件循环就会进入下一个阶段,然后又从下一个阶段对应的队列中取出回调函数执行,这样反复直到事件循环的最后一个阶段。而事件循环也会一个一个按照循环执行,直到进程结束。

事件循环当中的6个宏队列和微队列的关系如下:微队列(microtask)在事件循环的各个阶段之间执行,或者说在事件循环的各个阶段对应的宏队列(macrotask입력 및 출력

.

Blocking I/O와 Non-Blocking I/O의 차이점은 입력에서 출력까지의 기간 동안 시스템이 다른 입력을 받을 수 있는지 여부에 있습니다. Node.js의 비동기성에 대한 심층 분석음식 주문을 예로 들어보겠습니다. 매점에서 음식을 주문하려면 줄을 서서 기다려야 합니다. 이 과정에서 이모는 한 번에 한 사람만 받을 수 있습니다. "음식 주문 - 이모" 숟가락을 흔들어 음식을 담는다 - "음식을 가져오는" 과정에서 이모님은 다른 사람의 주문을 받아들일 수 없습니다. 이는 음식을 주문하기 위해 식당에 갈 때 알 수 있습니다. 레스토랑에 가면 토마토 스크램블 에그를 먹고 싶다고 웨이터가 적어서 셰프에게 건네는데, 이때 다른 테이블 사람이 와서 웨이터를 불러 가재를 먹고 싶다고 말한다. 즉, 웨이터

가 음식을 제공하기 전에 다른 사람의 주문을 받은 것입니다. 그렇다면 이것은 논블로킹 I/O입니다.

비차단 I/O를 이해하는 열쇠는 🎜🎜🎜🎜입력/출력을 수행하는 시스템을 결정🎜하는 것입니다. 🎜🎜I/O 프로세스 중에 다른 I/O를 수행할 수 있는지 생각해 보세요🎜. 🎜음식 주문의 예에서 입력/출력을 수행하는 시스템은 주문 - 주방(이모)이 처리 - 서빙은 먹을 수 있는 시스템입니다. 주문은 입력이고 서빙은 출력입니다. 이 예에서 핵심은 두 가지가 무엇인지 결정하는 것입니다. 주문 및 서빙 과정에서 다른 주문 및 요리를 수락할 수 있는지 여부. 마치 부다 점프 오버 더 월(Buddha Jumps Over the Wall)을 주문하면 음식이 나오기까지 오랜 시간이 걸릴 수 있고, 그러면 오는 사람들은 튀길 수 있는 간단한 볶음면을 주문할 것입니다. 1분 정도 사람들이 오고 가는 바람에 아직 음식을 대접할 수 없었을 것 같아요. 🎜🎜그리고 Node.js는 컴퓨터를 제어하는 ​​데 사용됩니다. 파일 읽기와 같은 일부 작업은 시간이 많이 걸립니다. 다른 I/O를 수행할 수 없으면 처리 효율성도 매우 낮습니다. 논블로킹 I/O의 이유. 🎜

🎜Node.js 이벤트 루프🎜🎜🎜Node.js는 시작 시 libuv에서 제공하는 🎜이벤트 루프🎜를 초기화합니다. 각 이벤트 루프에는 6단계가 포함됩니다. 아래 표시된 순서대로 각 이벤트 루프에서 반복적으로 실행됩니다. 🎜🎜Node.js의 비동기성에 대한 심층 분석🎜🎜🎜timers 단계: 이 단계는 timer( setTimeout, setInterval) 콜백🎜I/O <code>콜백 단계: 이전 주기에서 실행되지 않은 몇 가지 I/O를 처리합니다. 콜백🎜idle, prepare 단계: Node에서 내부적으로만 사용됩니다.🎜poll 단계: 새로운 I/O 이벤트를 가져옵니다. Node는 적절한 조건에서 여기를 차단합니다.🎜check 단계: setImmediate()의 콜백 실행🎜콜백 닫기 단계: close 이벤트 콜백 실행 of socket🎜🎜각 단계에는 FIFO(선입선출) 기능이 있습니다. 콜백 실행을 위한 큐와 관련하여 이벤트 루프의 각 단계에서 콜백 함수는 해당 콜백 큐에서 꺼내어 큐의 내용이 소진되거나 실행된 콜백 수가 최대🎜에 도달할 때까지 실행됩니다. 🎜🎜이후 이벤트 루프는 다음 단계로 진입하고, 다음 단계에 해당하는 큐에서 콜백 함수를 꺼내어 실행하며, 이는 이벤트 루프의 마지막 단계까지 반복됩니다. 이벤트 루프도 프로세스가 끝날 때까지 하나씩 실행됩니다. 🎜🎜이벤트 루프의 6개 매크로 큐와 마이크로 큐의 관계는 다음과 같습니다. 마이크로 큐(microtask)는 이벤트 루프의 다양한 단계 사이에서 실행되거나 이벤트 루프의 각 단계에서 해당 매크로가 실행됩니다. 큐 사이에서 실행되는 이벤트 루프(macrotask). 🎜🎜🎜🎜🎜여기 특히 혼란스러운 버전 변경이 있습니다: 🎜
  • Node10 및 이전 버전인 경우: 매크로 대기열에 여러 개의 매크로 작업이 있으며 매크로 대기열의 모든 매크로 작업이 완료될 때까지 마이크로 대기열의 마이크로 작업이 실행되지 않습니다
  • Node11 및 이전 버전인 경우 이후 버전: 단계의 매크로 작업(setTimeout, setIntervalsetImmediate)이 실행되면 I/O를 제외한 세 가지 중 하나 ), 즉시 마이크로태스크 대기열을 실행하고, 마이크로큐에 있는 모든 마이크로태스크를 실행한 후, 바로 지금 매크로큐로 돌아와서 다음 매크로태스크를 실행합니다. 이는 setTimeoutsetIntervalsetImmediate 三者其中之一,不包括I/O)就立刻执行微任务队列,执行完微队列当中的所有微任务再回到刚才的宏队列执行下一个宏任务。这就跟浏览器端运行一致了。

Node.js 异步编程 - callback

  • 回调函数格式规范
    • error-first callback
    • node-style callback
  • 第一个参数是 error,后面的参数才是结果。
// 第一个参数是错误捕获
interview(function (err, res) {
  if (err) {
    console.log(&#39;cry&#39;)
    return;
  }
  console.log(&#39;smile&#39;)
})
function interview(callback) {
  setTimeout(() => {
    if (Math.random() > 0.2) {
      callback(null, &#39;success&#39;)
    } else {
      callback(new Error(&#39;fail&#39;))
    }
  }, 500)
}
로그인 후 복사

异步流程控制:回调地狱、异步并发等问题

  • npmasync.js;可以通过 async.js 来控制异步流程
  • thunk:一种编程方式

Node.js 异步编程 – Promise

  • 可以通过字面意思理解,Promise 是承诺的意思;当前事件循环得不到的结果,但未来的事件循环会给到你结果
  • 它是一个状态机,状态一旦确定为 resolvedrejected 就不会改变
    • pending:初始状态,还没得到结果的状态
    • fulfilled / resolved:成功状态
    • rejected:失败状态

链式调用:.then.catch

  • resolved 状态的 Promise 会回调后面的第一个 .then
  • rejected 状态的 Promise 会回调后面的第一个 .catch
  • 任何一个 rejected 状态且后面没有 .catchPromise,都会造成浏览器/ Node 环境的全局错误
// promise的状态转换以及通过then获取内容
const promise = new Promise((resolve, reject) => {
  setTimeout(function () {
    resolve(3);
    // reject(new Error(4))
  }, 500)
})

promise.then(function (result) {
  console.log(result)
}).catch(function (err) {
  console.log(err)
})

setTimeout(() => {
  console.log(promise)
}, 800)
로그인 후 복사

执行 thencatch 会返回一个新 Promise,该 Promise 最终状态根据 thencatch 的回调函数的执行结果决定

  • 如果回调函数最终是 throw,该 Promiserejected 状态
  • 如果回调函数最终是 return,该 Promiseresolved 状态
  • 但如果回调函数最终 return 了一个 Promise ,该 Promise 会和回调函数 returnPromise 状态保持一致

Node.js 异步编程 – async/await

  • async functionPromise 的语法糖封装
  • 异步编程的终极方案 – 以同步的方式写异步
    • await 关键字可以“暂停” async function 的执行
    • await 关键字可以以同步的写法获取 Promise 的执行结果
    • try-catch 可以获取 await 所得到的错误
(async function () {
  await findJob()
  console.log(&#39;trip&#39;)
})()

async function findJob() {
  try {
    // 进行三轮面试
    await interview(1);
    await interview(2);
    await interview(3);
    console.log(&#39;smile&#39;)
  } catch (e) {
    console.log(&#39;cry at &#39; + e.round)
  }
}

// 进行第round轮面试
function interview(round) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.2) {
        const error = new Error(&#39;failed&#39;);
        error.round = round;
        reject(error);
      } else {
        resolve(&#39;success&#39;);
      }
    }, 500)
  })
}
로그인 후 복사

这是一个穿越事件循环存在的 function

总结

  • 理解非阻塞 I/O 主要在于确定一个进行 I/O 的系统,然后思考判断能不能进行其它 I/O
  • Node.js 的事件循环在 Node11 版本及之后是和浏览器的事件循环运行一致的,要注意区分。
  • Node.js 异步编程的规范是第一个参数是 error,后面的才是结果。
  • Promise是一个状态机,初始状态为 pending,一旦确定状态为 resolvedrejected 就不会改变,可以通过 .then.catch 进行链式调用。
  • async/await 브라우저 측 작업과 일치 합니다.
Node.js 비동기 프로그래밍 - 콜백

콜백 함수 형식 사양

🎜오류 우선 콜백🎜🎜<code>노드 스타일 콜백🎜🎜🎜🎜첫 번째 매개변수는 error이고, 다음 매개변수는 결과입니다. 🎜🎜rrreee🎜비동기 프로세스 제어: 콜백 지옥, 비동기 동시성 및 기타 문제🎜🎜🎜npm: async.js를 전달할 수 있음 async.js code> 비동기 프로세스를 제어하려면🎜🎜<code>thunk: 프로그래밍 방법🎜🎜

🎜Node.js 비동기 프로그래밍 – Promise🎜 🎜🎜 문자 그대로 이해할 수 있습니다. Promise는 약속을 의미합니다. 현재 이벤트 루프는 결과를 얻을 수 없지만 미래의 이벤트 루프는 결과를 제공합니다🎜🎜이것은 상태 머신입니다. 상태가 해결됨 또는 거부로 결정되면 변경되지 않습니다🎜🎜보류: 초기 상태, 결과가 나오지 않은 상태 아직 획득함🎜🎜fulfilled / resolved: 성공 상태 🎜🎜거부됨: 실패 상태 🎜🎜🎜🎜🎜체인 호출: .then .catch🎜🎜🎜resolved 상태 Promise는 첫 번째 .then🎜를 콜백합니다. 🎜rejected 상태의 Promise는 첫 번째 .catch🎜🎜않은 모든 rejected 상태를 콜백합니다. .catchPromise를 따르면 브라우저/노드 환경에서 전역 오류가 발생합니다🎜🎜rrreee🎜thencatch를 실행하면 thencatch의 콜백 함수 실행 결과에 따라 최종 상태가 결정되는 새로운 Promise를 반환합니다. 🎜🎜 🎜콜백 함수가 throw로 끝나는 경우 Promiserejected 상태가 됩니다. 🎜🎜콜백 함수가 로 끝나는 경우 return, Promise해결 상태입니다 🎜🎜그러나 콜백 함수가 최종적으로 Promise반환하면 code>에서 Promise 는 콜백 함수 return🎜🎜

🎜Node.js 비동기 프로그래밍 – async

/await🎜🎜🎜async function의 구문 설탕 패키지입니다. >비동기 프로그래밍에 대한 약속🎜🎜궁극적인 솔루션 - 동기 방식으로 비동기 작성🎜🎜await 키워드는 비동기 함수🎜🎜의 실행을 "일시 중지"할 수 있습니다. await 키워드를 사용할 수 있음 동기식 쓰기 방식으로 Promise🎜🎜try-catch의 실행 결과를 얻어 await에서 얻은 오류를 얻을 수 있음 🎜🎜🎜🎜rrreee🎜이벤트 루프를 통해 존재하는 함수입니다. 🎜

🎜요약🎜

🎜🎜비차단 I/O를 이해하는 것은 주로 🎜I/O를 수행하는 시스템을 결정한 다음 다른 I/O가 O 공연 가능 🎜. 🎜🎜Node.js의 🎜이벤트 루프🎜는 Node11 버전 이상에서 브라우저의 이벤트 루프와 동일하게 실행되므로 차이점에 주의하시기 바랍니다. 🎜🎜Node.js 비동기 프로그래밍의 사양은 첫 번째 매개변수가 error이고 그 결과는 다음과 같습니다. 🎜🎜Promise는 🎜상태 머신🎜입니다. 초기 상태는 pending입니다. 상태가 결정되면 해결됨 또는 가 됩니다. 거부됨 변경되지 않으며 .then.catch를 통해 연쇄 호출이 가능합니다. 🎜🎜async/await 🎜동기식으로 비동기 작성🎜은 비동기 프로그래밍에 대한 궁극적인 솔루션입니다. 🎜🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 비디오🎜를 방문하세요! ! 🎜

위 내용은 Node.js의 비동기성에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿