싱글스레드
자바스크립트는 싱글 스레드이다.
-
싱글 스레드
하나의 스레드가 모든 일을 하나 씩 처리하는 방식
- 장점 : 경쟁 상태 X, 코드 복잡도가 낮음
- 단점 : 여러 명이서 일하는 병렬 처리보다 성능이 떨어짐
-
멀티 스레드
여러 스레드가 모든 일을 나눠서 처리하는 방식
- 장점 : 싱글 스레드보다 성능이 좋음
- 단점 : 경쟁 상태를 고려해야함
→ 자바스크립트는 싱글스레드로 작동하는 언어
- 비동기 처리 방식을 도입해 성능이 낮은 것을 극복한다.
(현재는 멀티스레드를 지원하긴 한다)
경쟁 상태
여러 사람이 같은 리소스에 접근하는 것 → Lock을 걸어 해결할 수 있음
blocking & non-blocking
blocking
- 순차적 실행 방식
- 작업이 길어지면 다음 작업이 지연
- 자바스크립트에서는 “동기"라는 단어와 혼용
non-blocking
- 하나의 작업이 진행 중에도 다른 작업을 실행하는 실행 방식
- “작업을 실행시켜놓기만 하는 행위" → 결과를 기다리지 않음
- 작업이 길어져도 지연되는 일이 없음
- 결과값을 return 문으로 리턴받지 못해 콜백함수를 이용하게 된다.
- 자바스크립트에서는 “비동기"라는 단어와 혼용 → 위임하고 병렬 처리하는 것
- 이 방식을 지원해 동시성을 보여준다.
→ 자바스크립트는 싱글 스레드이지만 위임의 방법으로 병렬 작업을 한다.
(콜백함수가 모두 병렬처리는 아니다)
실행 환경 Runtime
자바스크립트 엔진
- 인터프리터 : 읽고 실행시킴 (vs 컴파일러 : 전후처리가 있음)
- 코드를 읽고 해석하고 작업을 수행하는 역할
- 작업을 수행할 뿐이다. 비동기 / 동기와는 관계가 없다.
- 예시 : V8(크롬, Node.js 가장 많이 사용), SpiderMonkey(firefox), JavaScriptCore(사파리→ 상위 웹킷)
이벤트 루프 + 큐
자바스크립트 코드가 비동기 실행될 수 있도록 도와주는 중심적인 역할
- 큐
- 이벤트 루프
- 큐에 쌓인 콜백 함수들을 꺼내 엔진에 전달해주는 역할 → 우선순위에 맞춰 가져옴
- 엔진은 그저 전달 받은 순서대로 실행한다
- Node.js 에서는 libuv가 담당
외부 API
- 비동기/동기 작업들의 묶음
- 비동기는 대부분 외부 API를 통해 일어난다.
- 비동기 작업 수행시 마쳤을 때 실행되는 콜백함수를 대부분 API 호출시 매개변수로 전달한다.
- 작업이 완료되면 큐에 콜백 함수를 등록 한다.
- 예시 : setTimeout, setInterval, fetch, console, fs, path
- setTimeout의 시간이 다 지나면 큐에 쌓이고 이것을 이벤트 루프가 콜백을 읽어 엔진에 전달해준다.
- Node.js는 API를 모듈로 가져온다.
비동기 작업 수행 방식
전통 : 콜백 패턴
- 비동기 작업들은 return이 아닌 별도의 결과를 반환하는 방식이 필요해서 도입
- 이것이 없었으면 완료 여부를 수동으로 확인해야하는 낭비가 발생했을 것이다.
- JS는 함수를 일급 객체로 취급하기에 가능하다! (변수로 사용할 수 있음)
fs.readFile("data.json",(err,data)=>{
if(err) throw err;
console.log(data)
});
map은 콜백함수가 아니고 고차함수이다. (from 함수형 프로그램)
문제 : 콜백 지옥 (ㅋㅋ)
- 중첩 함수로 인해 가로로 길어진다.
- DX 가 좋지 않다
DX : Developer eXperience : 개발자가 효율적으로 짤 수 있게 연구하는 분야
혁명 : Promise 패턴
- 순차적으로 호출되어야 하는 비동기 함수들을 쉽게 연결하는 then을 이용한다.
- 비동기 함수를 일관성있게 처리하도록 도와준다 → then, catch, finally
- 기타 비동기 함수의 기능을 추가 :
.all
, .allSettled
, .any
, .race
fetch('data.json')
.then(response=>response.json())
.then(
문제
- 초기 호환성 문제 : ECMA Script가 표준이 되기 이전에 만들어진 비동기 함수
- 미완성품이 있음
- node.js : util.promisify 지원
- 길어지는 then 체인으로 DX는 여전히 아쉬움
async/await 패턴
- 비동기 코드를 동기 코드 같이 보는 방법
- 가독성 향상 → 읽기 쉬움
- 높은 호환성 : 비동기 함수에 async await을 붙이면 된다.
- error를 name을 구분하여 각각 처리하도록 해야한다.
async function main(){
try{
const response = await fetch('data.json')
const samples = await response.json()
} catch(error){
}
}
⚡️ 오늘날 자바스크립트는 멀티스레드를 지원한다 by Worker Thread
Node.js
이전 자바스크립트는
- 브라우저의 전유물로 웹페이지 작성시에만 interactive를 목적으로 사용되는 언어로 인식
- web 2.0 이후로 중요도가 상승하고 여러 브라우저에서 경쟁하게 됨
- server-side의 필요성이 생기기 시작
V8 엔진 (크롬)
- 자바스크립트 엔진 중 오픈소스로 만들어진 엔진
- 서버사이드 프로그램에 대한 희망이 생김
⬇️ 탄생
Ryan Dahl이 2009년에 출시
- 비동기 실행 방식을 지원
- IO 관련 작업시 최고의 성능을 보여준다.
- npm으로 구성된 생태계로 인기가 많다.
구성 (V8 + Libuv + 라이브러리)
Libuv
- C로 작성된 이벤트 루프
- 비동기 작업을 마친 후 콜백함수들을 각종 큐에서 우선순위에 맞게 꺼내와 엔진에 전달한다.
- 싱글 스레드
- 다른 언어도 사용함.
기본 라이브러리
- 일반 머신 환경에서 실행되기에 Wep API와 여러 라이브러리들이 포함돼있음
- node.js는 브라우저 환경이 아님
- fs, path, crypto(암호화), Stream, zlib, childe_process(깃사용 가능), EventEmitter
기본 생태계 (runtime + 패키지 매니저 + npm registry)
패키지 매니저 : 전체 프로젝트 관리
- npm, yarn, pnpm
- node.js 프로젝트의 의존성 관리, 테스크 작성 npm registry 배포, 메타데이터(package.json) 작성
NPM registry : 개발한 모듈을 다른 개발자가 사용할 수 있도록 올려두는 공간
- node.js / vanilla.js로 작성한 서드 파티 라이브러리 / 모듈을 업로드하는 공간
- 컴파일 후 패키지화 되어있음
정리
- 서버사이드 자바스크립트의 문을 연 node.js
- 비동기 방식으로 작동하나 브라우저와 내부 스펙이 다르다.
- IO 관련 작업이 많을 수록 효율이 좋지만, 싱글 스레드 상 CPU가 많이 사용하는 고차원 연산이 많으면 효율이 극단적으로 떨어진다
오늘의 코드
const { ~ } = fromData
→ 변수명을 똑같이 설정해두면 객체가 알아서 맞춰서 들어간다.
return Object.values(formState)
.reduce((flag,{value,validator})=>validator(value)&&flag,true)
→ flag의 값을 두어 false를 판단. 해당 값 중 하나라도 맞지 않다면 ~