비동기 실행
: 특정 작업이 완료되었을 때 실행할 콜백을 등록해두고 바로 다음 코드로 실행을 넘기는 것
( 이전 작업의 마무리 여부에 상관없이 그 다음 일을 처리하는 작업 방식 )
> 비동기 실행의 장점
: '동기 실행'에 비해 '비동기 실행'이 훨씬 더 빠름
> 프로그램의 실행 흐름
Process 프로세스 : 하나의 실행 흐름
Thread 스레드 : 그 안에있는 더 작은 단위의 실행흐름
ex) chrome 실행 ( 더블클릭 > 실행)
hard-disk나 SSD에 저장되있던 프로그램 > memory에 올려서 > CPU(central Processing Unit)실행
하나의 크롬 '프로세스'생성 > 그 안에 하나의 '스레드'가 실행 중 상태
영화다운 (스레드-1) / 음악재생 (스레드-2) / 구글검색 (스레드-3) ----실행의 최소단위
컴퓨터 에러 시 '프로세스 강제종료' ----스레드보다 큰 실행흐름
1. 비동기 함수 사용
2. EventEmitter 객체 사용 (event 기반 프로그래밍)
비동기 함수
fs . readFile ( path [, options], callback)
(1) path : 내용을 읽을 파일의 경로 (필수)
(2) options : 파일의 내용을 읽을 때 적용할 옵션 (선택) - ex) utf8
(3) callback : 파일의 내용을 다 읽었을 때 실행될 콜백 (필수)
( 일반적으로 err(error, problem 등의 이름) 인자 첫번째, data(result, output 등) 같이 작업결과 나타내는 인자는 뒤에 )
import { readFile } from 'fs';
readFile('/etc/passwd', (err, data) => {
//함수내용
if (err) throw err;
console.log(data);
});
> 동기 실행 함수
fs . readFileSync ( path [, options] ) 동기 실행함수
import { readFileSync } from 'fs';
// macOS, Linux, and Windows
readFileSync('<directory>');
// => [Error: EISDIR: illegal operation on a directory, read <directory>]
// FreeBSD
readFileSync('<directory>'); // => <data>
setTimeout(callback, milliseconds)
: 특정 밀리세컨즈 초 후에 코드실행
milliseconds(밀리세컨즈, 1000분의 1초) 후에 callback 인자에 설정한 함수를 실행
let num = 1; // 1번
setTimeout(() => { // 2번
num = 2; // 세번째 // 5번
}, 1000);
num = 3; // 3번
console.log(num); // 4번
/*
(1) num 변수에 1을 대입
(2) setTimeout 함수 실행(1초 후에 실행될 콜백 설정)
(3) num 변수에 3을 대입
(4) num 변수의 값 출력
(5) setTimeout에서 설정해둔 콜백 실행
*/
> Node.js 개발 시 주의점
메인 스레드가 작업에 큰 부하를 주지않아야 함.
( CPU로 하는 수치 계산 작업 / 네트워크로 들어오는 클라이언트의 요청 받아들이고 응답하는 작업)
-Node.js 내부에서의 비동기 실행 구현 방법 중 한 가지-
1) 스레드 1개(이 스레드를 '메인 스레드'라고 합니다) 싱글 스레드
- 자바스크립트 코드 실행하기
- 이때 오래 걸리는 작업(작업 A)은 다른 스레드에 넘기기 (ex. fs.readFile('new', callback)에서 파일 읽기는 별도 스레드에 넘기기)
- 그리고 일단 그다음 작업 B를 시작하기
- 작업 A가 완료되었다는 알림과 그 작업 결과를 받으면
- 작업 결과를 가지고 콜백 실행하기(ex. 읽어 들인 파일 내용을 인자로 넣고, callback 실행)
2) 스레드 10개 ( C++ 쓰레드 )
- 메인 스레드가 요청한 작업 처리하기(ex. 파일 읽기)
- 작업이 완료되면 끝났다고 메인 스레드에 알려주고, 작업 결과 전달하기 (ex. 파일 내용을 다 읽고, 그 내용을 메인 스레드에 전달)
1. 메인 스레드는 빠르게 처리할 수 있는 작업들을 집중해서 '혼자' 처리하고,
2. 파일 읽기와 같이 시간이 오래 걸리는 작업은 다른 스레드에 맡김
EventEmitter
> event로 비동기 실행 / core module의 많은 객체들이 EventEmitter 객체.
> 하나의 event관해 여러개의 event handler설정가능
> myEmitter.on ← myEmitter.emit
> callback = listener = event handler
: Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture in which certain kinds of objects (called "emitters")emit named events that cause Function objects "listeners" to be called.
: All objects that emit events are instances of the EventEmitter class.
> EventEmitter 객체 사용법
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
/*
myEmitter.emit('test');
myEmitter.on('test',() => { //test이벤트 이미 발생되어서 callback함수 실행안됨
console.log('success!');
});
*/
myEmitter.on('test',() => { //event발생전에 콜백함수 실행되어야됨
console.log('success!');
});
myEmitter.emit('test');
> on 메소드
: event handler를 설정하는 메소드 ( = emitter.addlistener(eventName, listener) 동일기능의 메소드/짧은 on 선호)
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
const obj = {type : 'text', data:'hello world', date: '2021-09');
myemitter.on ('test', (info) => {
console.log(info);
});
myEmitter.emit('test', obj);
//출력
{type : 'text', data:'hello world', date: '2021-09')
> emit 메소드
: 인위적으로 event 발생시킴 ( 보통 코어모듈 사용하므로 자주사용 x / 나만의 eventemiiter객체 사용시 )
const EventEmitter = require('events'); //events라는 코어모듈 / eventemitter라는 class
const myemitter = new EventEmitter(); //class를 객체에 담아줘야 사용가능
myemitter.on('test', () => { //test라는 이벤트발생 시 callback으로 success출력
console.log('Sucess!');
});
myEmitter.emit('test'); //emit으로 test라는 이벤트 발생시킴
> once 메소드
: on과 유사하지만 해당 event대해서 딱 한번만 반응해서 실행
> listeners 메소드
: 특정 event대한 event handler를 출력
코드 작성시 특정 event에 지금 어떤 event handler들 설정되어 있는지 조회하고 싶을때
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.once('test', () => {
console.log('A');
});
myEmitter.once('test', () => {
console.log('B');
});
myEmitter.once('test', () => {
console.log('C');
});
console.log(myEmitter.listeners('test'));
// [ [fuction], [fuction], [fuction], ] 출력
> off 메소드
: event handler해제 / 해제할 이벤트 핸들러 정확히 지정
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
const callback = () => { //event handler를 변수에 할당해서 off에서 참조될 수 있게
console.log('Success!');
};
myEmitter.on('test', callback);
myEmitter.off('test', callback);
myEmitter.emit('test');
https://nodejs.org/api/events.html#events_class_eventemitter
🔻 비동기 함수의 callback 실행원리
Event Loop
: 각종 콜백들의 실행 조건(특정 시간이 경과했는지 등)을 확인하고, 실제로 콜백을 실행하는 로직
Event Loop는 특정 콜백의 실행 조건이 만족된 것을 확인하면 Queue라는 곳에 콜백(callback)들을 삽입
Queue 큐
: 데이터간 순서관계를 유지
맨 뒤 데이터 추가 / 맨 앞 데이터 삭제 / 맨 앞 데이터 접근
: callback이 저장되는 저장소
: FIFO (First-in-first-out) 가장먼저 들어온 데이터가 가장먼저 삭제됨.
> 콜백이 여러개 일대 각 콜백의 실행조건이 충족될 때, 차례대로 Queue에 들어감
> 콜백들은 Queue에 들어간 순서대로 event loop에 의해 실행
> node로 js파일 실행
1. 하나의 스레드가 js코드를 실행
2. 그 후, 그 스레드가 event loop라는 로직에서 각각의 콜백들에 대한 실행여부 판단, Queue에 넣은 후,
Queue에 담긴 콜백들을 실행
> 여러종류의 Queue존재, 각 콜백들은 그것을 등록한 함수에따라 서로다른 Queue에 담김
> Event loop가 각 Queue의 callback판단하고 처리하는 방식에도 조금씩 차이
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
JavaScript 런타임 환경
: JavaScript 로 짜여진 소스코드를 CPU가 이해할 수 있는 기계어(ex. 0과 1로 이루어진 bytecode)로 변환시키고
프로그램의 메모리를 관리하는 시스템
> 이런 환경을 가능하게끔 하는 것이 Chrome V8 엔진 - 비동기 이벤트-기반의 처리를 이 Chrome V8 엔진이 담당
( 우리가 알고 있는 구글의 크롬 웹브라우저에서 작동하는 엔진.
이 엔진이 브라우저 없이 작동할 수 있도록 만든 환경이 바로 노드)
'Archive' 카테고리의 다른 글
[Node.js] express (0) | 2021.09.13 |
---|---|
[Node.js] Protocol / Port / URL (0) | 2021.09.13 |
[Node.js] Node.js 기본 (0) | 2021.09.12 |
[REACT] State / Event (0) | 2021.09.04 |
[21.09.02] Javascript reverse num (0) | 2021.09.02 |