관리 메뉴

Dev Blog

4. Node.js 본문

Learn then Key points/Tech Interview Questions

4. Node.js

Nomad Kim 2021. 3. 29. 14:40

1. nodejs가 무엇인가요? 어디에 사용할 수 있나요?

1) 런타임이란 프로그래밍 언어가 돌아가는 환경, 그리고 node.jsJavaScript 런타임입니다.

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast and scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

2) Features of Node.js

Following are some of the important features that make Node.js the first choice of software architects.

  • Asynchronous and Event Driven − All APIs of Node.js library are asynchronous, that is, non-blocking. It essentially means a Node.js based server never waits for an API to return data. The server moves to the next API after calling it and a notification mechanism of Events of Node.js helps the server to get a response from the previous API call.
  • Very Fast − Being built on Google Chrome's V8 JavaScript Engine, Node.js library is very fast in code execution.
  • Single Threaded but Highly Scalable − Node.js uses a single threaded model with event looping. Event mechanism helps the server to respond in a non-blocking way and makes the server highly scalable as opposed to traditional servers which create limited threads to handle requests. Node.js uses a single threaded program and the same program can provide service to a much larger number of requests than traditional servers like Apache HTTP Server.
  • No Buffering − Node.js applications never buffer any data. These applications simply output the data in chunks.
  • License − Node.js is released under the MIT license.

3) Where to Use Node.js?

Following are the areas where Node.js is proving itself as a perfect technology partner.

  • I/O bound Applications
  • Data Streaming Applications
  • Data Intensive Real-time Applications (DIRT)
  • JSON APIs based Applications
  • Single Page Applications

참고: www.tutorialspoint.com/nodejs/nodejs_introduction.htm

2. 다른 개발환경이 아닌 nodejs 를 사용해야 하는 장점이 무엇인가요?

  • 싱글 쓰레드로 프로그램 작성이 간단
  • 비동기 I/O
  • 논 블로킹 I/O
  • 이벤트 기반
  • 간단한 구조와 경량 프레임워크와 풍부한 라이브러리
  • 서버와 클라이언트에서 사용하는 언어와 같다
  • Linux, Window, Mac OSX 지원

참고: junspapa-itdev.tistory.com/3  https://ktko.tistory.com/entry/nodejs를-왜-익혀야-할까

3. 왜 nodejs 는 single-threaded 인가요

Advantages of Single-Threaded Event Loop over Multi-Threaded Request/Response Stateless Model:

  1. Can handle more & more concurrent client’s requests with ease. A node.js app that isn't doing CPU intensive stuff can run thousands more concurrent connections than Apache or IIS or other thread-based servers.
  2. Eliminates the need of creating more and more threads, because of the Event loop.
  3. Applications built on top of node.js use the least threads possible to reduce memory or resource usage.
  4. 자원 접근 대한 동기화를 신경쓰지 않아도 된다.
    여러개의 스레드가 공유된 자원을 사용할 경우, 각 스레드가 원하는 결과를 얻게 하려면 공용 자원에 대한 접근이 통제되어야 하며, 이 작업은 프로그래머에게 많은 노력을 요구하고 많은 비용을 발생시킨다. 단일 스레드 모델에서는 이러한 작업이 필요하지 않다.
  5. 작업 전환을 요구하지 않는다.
    작업 전환은 여러 개의 프로세스가 하나의 프로세서를 공유할 때 발생하는 작업으로 많은 비용을 필요로 한다.

 

Reason behind node.js uses Single Threaded Event Loop Model architecture: (싱글쓰레드 단점)

  • Initially, node.js was created as an experiment in asynchronous processing and in theory was that doing asynchronous processing on a single thread could provide more performance and scalability under typical web loads than the typical thread-based implementation when the application isn’t doing CPU intensive stuff and can run thousands more concurrent connections than Apache or IIS or other thread-based servers.
  • The single-threaded, asynchronous nature of node.js does also make things complicated but threading is worse than this in terms of time taken to design an application, cost of development, deadlocks, priority inversions, and all the other things that come in the life cycle of an application.
  • There is also a very well known and criticized issue with the one thread per request model for a server which is that they don’t scale very well for several scenarios compared to the event loop thread model, in short, they lack scalability as the application grows to meet the future demands and with the addition of new features.
  • As Node.js follows Single-Threaded with Event Loop Model inspired by JavaScript Event-based model with JavaScript callback mechanism. So, node.js is single-threaded similar to JavaScript but not purely JavaScript code which implies things that are done asynchronously like network calls, file system tasks, DNS lookup, etc. are actually not handled by the main thread and are in C++ as Ryan Dahl is not a fan of JavaScript and also C++ has access to multiple threads that makes it a better language for asynchronous tasks.

참고: www.geeksforgeeks.org/why-node-js-is-a-single-threaded-language/

velog.io/@eunjin/OS-%EC%8B%B1%EA%B8%80%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%9D%98%EB%AF%B8

 

진짜 싱글 쓰레드는 아니다?

참고: pprathameshmore.medium.com/is-it-really-node-js-single-threaded-threading-in-node-js-227177c42d5a

4. nodejs에서 callback을 설명해 보세요

Node.js, being an asynchronous platform, doesn't wait around for things like file I/O to finish - Node.js uses callbacks.

A callback is a function called at the completion of a given task; this prevents any blocking, and allows other code to be run in the meantime.

function processData (callback) {
  fetchData(function (err, data) {
    if (err) {
      console.log("An error has occurred. Abort everything!");
      return callback(err);
    }
    data += 1;
    callback(data);
  });
}

At first glance, it may look unnecessarily complicated, but callbacks are the foundation of Node.js. Callbacks give you an interface with which to say, "and when you're done doing that, do all this."

This allows you to have as many IO operations as your OS can handle happening at the same time.

For example, in a web server with hundreds or thousands of pending requests with multiple blocking queries, performing the blocking queries asynchronously gives you the ability to be able to continue working and not just sit still and wait until the blocking operations come back. This is a major improvement.

 

If the function hits an error, then they typically call the callback with the first parameter being an Error object. If it cleanly exits, then they will call the callback with the first parameter being null and the rest being the return value(s).

 

비동기 처리? 그게 뭔가요?

특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것이 비동기 처리입니다. 자바스크립트에서 비동기 처리가 필요한 이유를 생각해보면, 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 줄지도 모르는데 마냥 다른 코드를 실행 안 하고 기다릴 순 없기 때문입니다. 위에선 간단한 요청 1개만 보냈는데 만약 100개 보낸다고 생각해보세요. 비동기 처리가 아니고 동기 처리라면 코드 실행하고 기다리고, 실행하고 기다리고.. 아마 웹 애플리케이션을 실행하는데 수십 분은 걸릴 겁니다.

 

블로킹은 Node.js 프로세스에서 추가적인 JavaScript의 실행을 위해 JavaScript가 아닌 작업이 완료될 때까지 기다려야만 하는 상황입니다. 이는 이벤트 루프가 블로킹 작업을 하는 동안 JavaScript 실행을 계속할 수 없기 때문입니다.

Node.js에서, I/O 등의 JavaScript가 아닌 작업을 기다리는 것보다 CPU 집약적인 작업 때문에 나쁜 성능을 보여주는 JavaScript는 보통 블로킹이라고 부르지 않습니다. libuv를 사용하는 Node.js 표준 라이브러리의 동기 메서드가 가장 대표적인 블로킹 작업입니다. 네이티브 모듈도 블로킹 메서드를 가질 수 있습니다.

Node.js 표준 라이브러리의 모든 I/O 메서드는 논블로킹인 비동기 방식을 제공하고 콜백 함수를 받습니다.

 

참고

 

nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/

nodejs.org/ko/docs/guides/blocking-vs-non-blocking/

5. nodejs에서 비동기란 무엇인가요

특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것이 비동기 처리입니다. 자바스크립트에서 비동기 처리가 필요한 이유를 생각해보면, 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 줄지도 모르는데 마냥 다른 코드를 실행 안 하고 기다릴 순 없기 때문입니다. 위에선 간단한 요청 1개만 보냈는데 만약 100개 보낸다고 생각해보세요. 비동기 처리가 아니고 동기 처리라면 코드 실행하고 기다리고, 실행하고 기다리고.. 아마 웹 애플리케이션을 실행하는데 수십 분은 걸릴 겁니다.

6. nodejs callback hell이 무엇인가요? 어떻게 이를 피할 수 있을까요?

callback 은 비동기로 돌아가는 자바스크립트의 순서를 제어하는 방법 입니다.

하지만 아래의 const printAll 에서 볼 수 있듯이 printString 을 호출하는 횟수가 많아지면 callback Hell 이 발생할 수 있는데,

함수의 매개 변수로 넘겨지는 콜백 함수가 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상을 말합니다.

즉, 가독성이 떨어진다는 점이 단점이라고 할 수 있습니다.

 

const printAll = () => {
  printString("A", () => {
    printString("B", () => {
      printString("C", () => {
        printString("D", () => {
          printString("E", () => { 
            printString("F", () => { 
              printString("G", () => {
                printString("H", () => {
                ....
              })
            })
          })
        })
      })
    })  
  })
}
printAll() // A, B, C, D, E, F, G, H .....

이를 해결하기 위해,

  1. 동기 함수를 사용
  2. 콜백 함수를 분리
  3. Promise 패턴 도입

세가지 방법이 있는데 그 중 Promise 패턴 도입이 콜백 문제를 해결할 수 있는 가장 효과적인 방법입니다.

Promise 설명: nomadkim880901.tistory.com/349

 

7. nodejs에서 module 이란 무엇인가요?

우선 모듈은 독립적인 하나의 소프트웨어이고 Node.js는 파일 하나하나가 모듈로 기능한다. 브라우저에서는 script 태그로 스크립트를 불러오면 다른 스크립트에서도 이전 스크립트의 변수를 사용할 수 있었지만, Node.js는 명시적으로 이전 스크립트의 변수를 사용하겠다고 선언해주어야 한다. 이러한 특성 때문에 Node.js에서는 모듈 시스템을 이해하는 것이 중요하다.

 

JavaScript를 Client-side에 국한하지 않고 범용적으로 사용하고자 하는 움직임이 생기면서 모듈 기능은 반드시 해결해야하는 핵심 과제가 되었고 이런 상황에서 제안된 것이 CommonJSAMD(Asynchronous Module Definition)이다.

Node.js는 사실상 모듈 시스템의 사실상 표준(de facto standard)인 CommonJS를 채택하였고 현재는 독자적인 진화를 거쳐 CommonJS 사양과 100% 동일하지는 않지만 기본적으로 CommonJS 방식을 따르고 있다.

Node.js는 module 단위로 각 기능을 분할할 수 있다. module은 파일과 1대1의 대응 관계를 가지며 하나의 모듈은 자신만의 독립적인 실행 영역(Scope)를 가지게 된다. 따라서 클라이언트 사이드 JavaScript와는 달리 전역변수의 중복 문제가 발생하지 않는다.

모듈은 module.exports 또는 exports 객체를 통해 정의하고 외부로 공개한다. 그리고 공개된 모듈은 require 함수를 사용하여 임포트한다.

 

*exports

모듈은 독립적인 파일 스코프를 갖기 때문에 모듈 안에 선언한 모든 것들은 기본적으로 해당 모듈 내부에서만 참조 가능하다. 만약 모듈 안에 선언한 항목을 외부에 공개하여 다른 모듈들이 사용할 수 있게 하고 싶다면 exports 객체를 사용해야 한다.

모듈을 파일로 작성하고 외부에 공개할 대상을 exports 객체의 프로퍼티 또는 메소드를 정의한다. 그리고 모듈을 전역 함수 require()를 이용하여 추출한다.

// circle.js
const { PI } = Math;
exports.area = (r) => PI * r * r;
exports.circumference = (r) => 2 * PI * r;

// app.js
const circle = require('./circle.js'); // == require('./circle')
console.log(`지름이 4인 원의 면적: ${circle.area(4)}`);
console.log(`지름이 4인 원의 둘레: ${circle.circumference(4)}`);

**module.exports

exports 객체는 프로퍼티 또는 메소드를 여러 개 정의할 수 있었다. 하지만 module.exports에는 하나의 값(원시 타입, 함수, 객체)을 할당할 수 있다. 원시 타입, 함수, 객체를 할당하는 방법? '참고' 확인.

 

참고: poiemaweb.com/nodejs-module

 

8. nodejs에서 event loop이란 무엇인가요? nodejs에서 비동기 처리를 그림으로 그려서 설명할 수 있나요?

The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.

 

그림설명: drive.google.com/file/d/1w-PLs0jSN8oXbKIjNrHTUpWW9tSzxUzu/view?usp=sharing

영상설명: youtu.be/8aGhZQkoFbQ?t=774

9. Chrome이랑 Node.js 환경 다른점

브라우저

  • 브라우저에서 대부분의 작업은 DOM 또는 쿠키와 같은 다른 웹 플랫폼 API와 상호 작용합니다. 물론 Node.js에는 존재하지 않습니다.
  • 브라우저에서 제공하는 문서, 창 및 기타 모든 개체가 없습니다. 그리고 브라우저에는 Node.js가 모듈을 통해 제공하는 파일 시스템 액세스 기능과 같은 멋진 API가 모두 없습니다.

Node.js

  • Node.js에서 환경을 제어한다는 것입니다. 누구나 어디서나 배포 할 수있는 오픈 소스 애플리케이션을 빌드하지 않는 한 애플리케이션을 실행할 Node.js 버전을 알고 있습니다. 방문자가 사용할 브라우저를 선택할 수있는 사치가없는 브라우저 환경과 비교하면 매우 편리합니다. 이는 Node.js 버전이 지원하는 모든 최신 ES6-7-8-9 JavaScript를 작성할 수 있음을 의미합니다. JavaScript는 매우 빠르게 이동하지만 브라우저는 업그레이드 속도가 약간 느릴 수 있으며 때로는 웹에서 이전 JavaScript / ECMAScript 릴리스를 사용하는 데 어려움을 겪습니다.
  • Node.js는 CommonJS 모듈 시스템을 사용하는 반면 브라우저에서 구현되는 ES 모듈 표준을 보기 시작한다는 것입니다. 실제로 이것은 당분간 Node.js에서 require ()를 사용하고 브라우저에서 가져 오는 것을 의미합니다.

10. 두 환경 모두에서 동일하게 돌아가나요? 브라우저 환경에서는 어떻게?

브라우저와 노드의 차이점중 하나는 Micro-tasks(마이크로 태스크)와 Macro-tasks(매크로 태스크)중 어떻게 우선 순위를 정하냐의 차이이다.

마이크로 태스크와 매크로 태스크의 차이?

마이크로 테스크와 매크로 태스크는 비동기 작업의 2가지 유형을말한다.

그러나 마이크로 태스크가 매크로 태스크보다 우선 순위가 더 높다.

마이크로 태스크의 예는 Promise이며 매크로 테스크는 setTimeout 이다.

Node 버전 v11이상에서는 브라우저와 동작이 일치하지만 그 미만 버전에서는 차이가 발생한다.

HTML5 스펙에 따르면 이벤트 루프는 하나의 매크로 태스크를 처리한 후에 모든 마이크로 태스트 큐를 처리해야한다.

setTimeout1 콜백이 실행될 때 promise 콜백이 스케쥴링된다. 타이머 콜백 큐안에 있는 다른 타이머 콜백으로 이동하기 전에 이벤트 루프는 마이크로 태스크 큐가 비어있다는 것을 확인해야 합니다. 따라서 추가된 promise 콜백을 실행합니다. 그리고 나서 마이크로 태스크 큐가 비어지면 타이머 콜백 큐에 있는 setTimeout2 콜백을 처리합니다.

11. express는 무엇인가요? 무엇을 해 주나요?

Express.js는 Node.js 환경에서 웹 어플리케이션 혹은 API를 제작하기 위해 사용되는 인기있는 프레임워크.

Node.js의 핵심 모듈인 httpConnect 컴포넌트를 기반으로 하는 웹 프레임워크다. 그러한 컴포넌트를 미들웨어(middleware)라고 부른다.

  1. 미들웨어를 붙이기 쉽다.
  2. 자체 라우터를 제공한다.

express 로 리팩토링할 때, 적용할 미들웨어

  1. body parser 미들웨어
  2. CORS 미들웨어

미들웨어란?

요청 오브젝트(req), 응답 오브젝트 (res), 그리고 애플리케이션의 요청-응답 주기 중 그 다음의 미들웨어 함수 대한 액세스 권한을 갖는 함수입니다. 그 다음의 미들웨어 함수는 일반적으로 next라는 이름의 변수로 표시됩니다.

 

1. 미들웨어 태스크 수행

  • 모든 코드를 실행.
  • 요청 및 응답 오브젝트에 대한 변경을 실행.
  • 요청-응답 주기를 종료.
  • 스택 내의 그 다음 미들웨어를 호출.

2. 미들웨어가 쓰이는 경우

  1. 모든 요청에 대해 url이나 메소드를 알고자 할 때
  2. POST 요청 등에서 쓰이는 body(payload)를 쉽게 얻어내고자 할 때
  3. 모든 요청/응답에 CORS 헤더를 붙일 때
  4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인하고 싶을 때

참고: jsqna.com/ejs-1-why-express/ jeong-pro.tistory.com/57

12. package.json 의 역할은 무엇인가요?

 

package.json에는 이 프로그램을 실행시키기 위해 필요한 모듈들이 무엇인지, 프로그램을 실행시키는 방법, 프로그램을 테스트하는 방법 등이 명시되어 있다. 즉, 사용자가 package.json에서 필요하다고 하는 모듈을 npm을 이용해 다운받으면 된다.

이 프로그램을 실행시키기 위해 필요한 실제 모듈은 node_modules이라는 폴더에 다 들어가 있는데, package.json에는 어떤 모듈인지만 적혀 있다.

 

구성

 

1. dependencies

이 프로젝트가 돌아가기위해 반드시 필요한 모듈들이 무엇인지가 적혀 있습니다. 코드가 작동하기 위해 필해요한 모듈들.

"dependencies": { "react": "^16.8.6", }

 

2. devDependencies

이 프로젝트를 개발하는 환경에서 필요한 모듈들이 무엇인지가 적혀 있습니다. 예를 들면 코드 모양을 잡아주는 lint나 테스팅 모듈처럼, 실제 프로젝트 동작에 직접적으로 영향을 주지 않는 모듈들을 명시합니다.

"devDependencies": { "jest": "^2.3.0", "eslint" : "^2.0.0" }

 

3. scripts

npm 으로 실행시킬 수 있는 명령어를 정의합니다. 명령어를 입력하면 어떤 동작을 해야하는지가 적혀 있습니다. 예를들면 npm test 명령어를 입력하면 "test.js 파일을 node 에서 실행시켜라!" 하는 내용들이 들어있습니다. 만약 npm test와 같은 명령어를 실행시켰는데 "정의되지 않은 명령어" 라는 오류 메시지가 나오면, package.json 파일 scripts 에 해당 명령어가 정의되어 있는지를 확인해 보시면 됩니다.

"scripts": { "start": "node app.js", "test": "node test.js", }

예) package.json

{
  "name": "shortly-bare",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "test": "mocha __test__/**.test.js --sort --exit",
    "report": "mocha __test__/**.test.js --sort --exit --reporter @mochajs/json-file-reporter",
    "submit": "codestates-submission"
  },
  "dependencies": {
    "debug": "~2.6.9",
    "dotenv": "^8.2.0",
    "express": "~4.16.1",
    "har-validator": "^5.1.5",
    "morgan": "~1.9.1",
    "mysql2": "^2.1.0",
    "request": "^2.88.2",
    "sequelize": "^6.4.0"
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "chai-http": "^4.3.0",
    "mocha": "^8.0.1",
    "sequelize-cli": "^6.2.0",
    "sinon": "^9.0.2"
  }
}

 

 

'Learn then Key points > Tech Interview Questions' 카테고리의 다른 글

7. Network  (0) 2021.03.29
6. HTTP  (0) 2021.03.29
5. Data Structure  (0) 2021.03.29
3. Javascript  (0) 2021.03.29
2. Web general  (0) 2021.03.29
Comments