자바스크립트는 단일 스레드입니다.

단일 스레드라는 것은 하나의 스택이라는 뜻으로 동시에 하나의 일만 가능하다는 것을 의미합니다.

 

하지만,

자바스크립트가 사용되는 환경을 보면 비동기 작업을 통해 여러개를 동시에 처리하고 있는것 같습니다. 

멀티 스레드라고 착각할 수도 있을 것 같은데,

어떻게? 이렇게 동작할 수 있는지를 알아보도록 하겠습니다.

 

 

자바스크립트 엔진

메모리 힙(Memory Heap)과 콜 스택(Call Stack)으로 이루어져 있습니다.

  • 메모리 힙
    • 구조화되지 않은 넓은 메모리 영역을 말한다.
    • 객체들이 할당된다
      • 프로그램에 선언한 변수, 함수 등
  • 콜 스택
    • 함수 호출은 프레임들의 스택을 형성
    • 먼저 들어온 것이 나중에 나가는 선입 후출

 

자바스크립트 엔진에는 설명하려는 이벤트 루프가 등장하지 않는데, 이유는 간단합니다.

비동기 작업에서 필요한 중요한 요소인 이벤트루프, 콜백 큐등은 자바스크립트를 구동시키는 환경(=브라우저, 노드)이 담당하고 있기 때문입니다.

 

 

브라우저 환경

출처: https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

 

  • Web APIs
    • 브라우저에서 제공하는 API들, 웹 브라우저에 내장되어 있다
      • DOM, Ajax, Timeout 등..
      • 브라우저 및 주변 컴퓨터 환경의 데이터를 노출하고 이를 사용하여 유용한 복잡한 작업을 수행 할 수 있다
  • Callback Queue
    • 처리할 메시지 목록인 메시지 대기열
    • 먼저 들어온 것이 먼저 나가는 선입선출
      • Task Queue
        • ex: setTimeout
      • Micro Task Queue (= Job Queue) 
        • ex: Promise의 .then()
      • Animation Frames
        • ex: requestAnimationFrame API
  • Event Loop
    • 콜 스택과 콜백 큐를 감시한다
    • 콜 스택이 비어있으면 콜백 큐에서 태스크를 가지고 와서 콜 스택에 추가하는 행동을 한다

+ Event Table: 특정 이벤트가 발생했을때 어떤 콜백함수가 호출되어야하는지 알고 있는 자료구조

 

 

크롬 기준

Micro Task Queue > Animation Frames > Task Queue 순으로 실행됩니다.

그 외에 Queue들도 설명하는 블로그 글도 있기는 하나 정확한 정보는 못 찾았다고 합니다.

도움이 되는 글이라 생각하니 방문해서 읽어보세요~

velog.io/@thms200/Event-Loop-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84#animation-frames

 

Event Loop (이벤트 루프)

이번 글은 Event Loop (이벤트 루프) 에 대해 정리해보려고 한다. Event Loop? Event Loop 출처 How JavaScript works: an overview of the engine, the runtime, and the call stack Event Loop는 MDN 문서로 검색하면 "큐의 다음 메시

velog.io

 

여튼 동작을 예로 들면.. 

ES6의 Promise의 then이 Micro Task Queue로 들어가며 setTimeout 함수는 Task Queue로 들어간다.

이때 Task Queue 대기열에 Task가 있어도 Micro Task Queue가 먼저 이벤트 루프에 의해 콜 스택으로 이동된다.

 

 

Micro Task Queue와 Job Queue는 같은 것 일까?

공부하던 중에 논란이 있음을 인지했고 찾아본 두 블로그 글을 가져와봅니다.

정확한 설명은 링크를 통해 들어가서 확인해보세요^^

 

ECMA에선 PromiseJobs라는 내부 큐(internal queue)를 명시합니다.

V8 엔진에선 이를 '마이크로태스크 큐(microtask queue)'라고 부르기 때문에 이 용어가 좀 더 선호되고 있습니다.

- ko.javascript.info/microtask-queue

 

브라우저마다 프라미스의 호출 순서가 다른 문제를 지적했다.

프라미스가 ECMAScript에 정의되어 있는 반면에 마이크로 태스크는 HTML 스펙이 정의되어 있는데,

둘의 연관관계가 명확하지 않기 때문이다.

ES6부터 프라미스를 위해 잡 큐(Job Queue)라는 항목이 추가되었지만, HTML 스펙의 마이크로 태크스와는 별도의 개념이다.

프라미스A+ 스펙문서의 Note를 보면 구현 시에 일반(macro) 태스크나 마이크로 태스크 둘 다 사용할 수 있다고 적혀 있다.

실제로 프라미스가 처음 자바스크립트에 도입되는 시점에는 프라미스를 어떤 순서로 실행할 것인가에 대한 논의가 꽤 있었던 것으로 보인다.

하지만 앞서 언급한 것처럼 현재는 프라미스를 마이크로 태스크라고 정의해도 무리가 없을 것 같다.

- meetup.toast.com/posts/89

 

 


참고

ko.javascript.info/microtask-queue

meetup.toast.com/posts/89

 

프로그래밍의 관점을 갖게하고 결정하는 역할인 프로그램의 패러다임에 대해 알아보겠습니다.

발전하게 된 순서는 '절차적 -> 객체지향 -> 함수형'으로 단점들을 극복을 위해 나왔다고 합니다.

 

 

프로그래밍 패러다임

명령형 프로그래밍(How): 알고리즘을 명시하고 목표는 명시하지 않는다

  • 프로그램의 상태와 상태 변경을 시키는 '구문'의 관점에서 연산을 설명하는 방식
    • 절차적 프로그래밍: 수행되어야 할 연속적인 계산 과정을 포함하는 방식
    • 객체지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현
  • 선언형 프로그래밍(What): 알고리즘을 명시 하지않고 목표만 명시한다
    • 어떤 방식(How)가 아닌 무엇(What)과 같은지를 설명하는 방식
      • 함수형 프로그래밍: 순수함수를 보조함수와 조합하는 방식

 

 

명령형 프로그래밍

절차적 프로그래밍 (위키백과)

실행 절차에 중점을 둔 프로그래밍 방식으로 순차적인 처리방식으로 프로그램 전체가 유기적인 연결이 있다. 

순차적인 처리방식은 컴퓨터의 동작 방식과 같아서 처리 시간이 빠르다고 한다.

 

특징

  1. 하나의 큰 기능을 처리하기 위해 작은 단위의 기능들로 나누어 처리하는 Top-Down 방식
  2. 비교적 작은 규모의 작업을 수행하는 함수 생성
  3. 인수, 반환 값으로 명령을 전달하고 수행
  4. 데이터와 함수를 별개 취급
  5. 특정 기능을 수행하려면 해당 메소드를 직접 호출

 

장단점

장점

  • 개인 프로젝트에 적합
  • 객체 지향에 비해 빠르다

단점

  • 대형 프로젝트에 부적합
  • 유지보수가 어렵다
  • 코드 순서가 중욯서 순서 변경 시 다른 결과 초래 가능
  • 분석과 디버깅이 어렵다

 

 

객체지향 프로그래밍 (위키백과, 관련포스팅)

기능별로 모듈화하여 하드웨어가 같은 기능을 중복하지 않게하고 모듈을 재활용하여 하드웨어의 처리량을 줄인다.

'객체'라는 기본 단위로 나누고 이들의 상호작용으로 서술하는 방식

클래스를 이용해 연관있는 처리부분과(함수) 데이터부분(변수)을 하나의 객체(인스턴스)로 묶어 생성, 사용, 작은 문제를 해결하는 객체를 생성해 큰문제를 해결하는 Bottom-Up 방식.

네가지 특징(추상화, 캡슐화, 다형성, 상속)을 지키며 코딩해야하며 이 조건을 지키지 않고 클래스 단위로 프로그래밍하는 것은 객체지향이 아닌, 클래스기반(캡슐화)을 사용하는 것이다.  

 

특징

1. 추상화

현실세계 대상을 관찰하여 핵심적인 특징(속성과 행위)을 뽑아내는 과정이다.

이때 관련있는 것들을 묶게되면 캡슐화가 되고 묶은 개념은 추상화가 되고 주체는 클래스가 된다.

'객체'는 클래스로 부터 실체화 된것으로 눈에 보이며 실체한다.

'클래스'는 추상적이기에 눈에 보이지 않고 개념적으로만 존재한다.

 

2. 캡슐화

속성과 행위를 관련있는 것끼리 묶는다.

여기서 중요한 것은 접근이 필요한 부분을 제외하고 구체적인 로직은 내부로 숨긴다. (=은닉성)

구체적인 로직을 내부로 은닉하는 목적

  • 클래스 내부 구현의 '응집도'를 증가
  • 외부 다른 클래스와의 '결합도'를 감소
    • 이때 일반적인 객체지향언어는 '접근제한자'를 지원한다. (public, private, protected)

 

3. 상속

대상이 되는 클래스의 모든 특징을 물려받는 것, 이때 자식 클래스로 부터 부모 클래스가 대체되어도 의미가 성립되어야한다.

계층형 구조

  • 부모 클래스와 자식클래스는 '상속관계'
  • 관계가 아래로 내려갈수록 '구체화된다'라고 말한다. (=> 고유 특징이 증가)
  • 관계가 위로 올라올수록 '일반화된다'고 말한다. (=> 더 많은 객체에 영향을 준다)

 

장단점

장점

  • 부모 클래스로 부터 물려 받은 특징으로 인해 같은 내용을 다시 구현할 필요가 없어 '코드의 재사용성'이 향상된다.

단점

  • 재 사용성만 고려하여 상속한다면 혼란이 생긴다.
  • 상속은 '다형성'을 구현하기 위해 사용할 것을 권장한다.
    • 좋은 상속관계는 is-a 관계 (~은 ~이다) : 바나나는 과일이다 / 자동차는 바퀴가 있는 탈 것이다
    • 혼란을 줄 수 있는 상속관계는 has-a 관계 : 사람-팔 / 자동차-바퀴 / 새-날개

 

4. 다형성

하나의 속성이나 행위가 상황에 따라 다른 의미로도 해석될 수 있는 특성으로 오버로딩, 오버라이딩을 통해 다형성을 구현 할 수 있다.

  • 오버로딩
    • 매개 변수에 따라 여러 종류의 타입을 받아 같은 기능으로 하도록 하기 위한 작업
    • 자바스크립트는 자유로운 언어이므로 기본 제공하지는 않는다
    • 함수는 변수로 취급하며 모든 변수는 전역 객체로 취급하기 때문에 같은 이름이라면 하나만 취급
    • 따라서 타입체크해서 기능을 구현하도록 함수를 만들 수는 있다
  • 오버라이딩
    • 상위 클래스의 메서드를 하위 클래스에서 재 정의하는 것(상속)

 

 

절차적 프로그래밍과 객체지향 프로그래밍 차이

두 방식이 아예 반대개념이라고 할 수는 없다.

둘다 명령형 프로그램의 하위 개념이기에 공유하는 것이 많다.

그리고 절차적이지 않은 프로그램은 없기 때문이다.

다만

  • 절차적 프로그래밍
    • 프로그램의 순서와 흐름을 먼저 세우고 필요한 자료구조와 함수를 설계
    • (=데이터 중심으로 절차적 실행에 초점)
  • 객체지향 프로그래밍
    • 반대로 자료구조와 함수를 먼저 설계하고 그 후 실행순서와 흐름을 설계
    • (=객체간의 관계에 초점)

 

선언현 프로그래밍

함수형 프로그래밍 (위키백과)

순수함수를 보조함수와 조합하고 소프트웨어를 만드는 방식

로직내에 복잡성을 해결하고 변수사용을 억제하여 상태변경을 피하려는 프로그래밍 패러다임

 

특징

1. 일급객체

사용할때 다른 요소와 아무런 차별이 없는 객체 (자바스크립트 함수는 객체, 일급함수)

  1. 변수나 데이터 구조 안에 담을 수 있다
  2. 파라미터로 전달 할 수 있다
  3. 반환값(return value)로 사용할 수 있다
  4. 할당에 사용한 이름과 관계없이 고유한 구별이 가능하다
  5. 동적으로 프로퍼티 할당이 가능하다
  6. 비교연산이 가능하다

 

2. 고차함수

람다 계산법에서 만들어진 용어로 함수는 함수를 파라미터로 전달할 수 있어야하며 함수의 반환값으로 함수를 사용할 수 있습니다. (일급 객체의 부분집합)

(React의 고차컴포넌트는 컴포넌트를 이용하여 위의 조건을 만족하는 컴포넌트를 말한다)

 

3. 불변성

변하지 않는 성질을 말한다.

자바스크립트는 자유로운 언어로 데이터의 변경이 언제든 가능하나 안되는 언어들이 존재한다.

불변성을 지키기 위해서는 데이터 변경이 필요할 경우 원본을 유지한 채 복사본을 만들어 작업해야한다.

 

4. 순수함수

동일한 입력에는 항상 같은 값을 반환해야한다.

함수의 실행은 프로그램의 실행에 영향을 미치지말아야한다. (Side Effect가 없어야함)

함수 내부에서 인자값의 변경이나 프로그램의 상태를 변경하면 안된다.

 

5. 합성함수

새로운 함수를 만들거나 계산하기 위해서는 둘 이상의 함수를 조합하는 과정을 말한다.

함수형 프로그래밍은 작은 여러개의 함수들로 이루어져 있기에 이러한 함수들을 연쇄적으로 또는 병렬로 호출해서 더 큰 함수를 만드는 과정으로 전체 프로그래밍을 구축한다.

 

 

명령형 프로그래밍과 함수형 프로그래밍 비교

 

명령형 프로그래밍

함수형 프로그래밍

프로그램이란

프로그램은 명령의 수행이다

프로그램은 함수의 계산이다

중점적 시각

어떻게?

무엇?

 

 

객체지향 프로그래밍과 함수형 프로그래밍의 차이

함수형 프로그래밍과 객체지향 프로그래밍은 약간의 차이가 있다.

  • 객체지향: 관리하는 모듈함수에 의한 재사용성에 관심을 가지고 있으며 클래스(또는객체,Object)가 일급객체
    • 클래스와 객체들의 관계를 중심으로 코드 작성
    • 상태, 멤버변수, 메서드 간의 긴밀한 관계
    • 멤버변수의 상태에 따라 결과가 달라짐
  • 함수형: 순수함수와 일급객체에 관심을 가지고 있으며 함수(Function)자체가 일급객체
    • 값의 연산 및 결과 도출 중심으로 코드 작성
    • 함수 내부로 넘겨받은 인자 값을 별도로 저장하지 않으며 간결한 과정으로 처리하고 매핑하는데 주 목적입니다.

 

 

 

 

위키백과에서 먼저 정의를 살펴보았습니다.

 

 

"라이브러리는 주로 소프트웨어를 개발할 때 컴퓨터 프로그램이 사용하는 비휘발성 자원의 모임이다.

여기에는 구성 데이터, 문서, 도움말 자료, 메시지 틀, 미리 작성된 코드, 서브루틴, 클래스, 값, 자료형 사양을 포함할 수 있다."

 

"컴퓨터 프로그래밍에서, 소프트웨어 프레임워크는 복잡한 문제를 해결하거나 서술하는 데 사용되는 기본 개념 구조이다.

간단히 뼈대, 골조, 프레임워크라고도 한다."

 

글만 간단히 보아도 두 개념이 많이 다른 것을 알 수 있습니다.

라이브러리는 프레임워크에 비해 작은 개념입니다.

 

 

프론트개발을 할때 쉽게 접하는 것을 예로 들어보자면 jQuery, React 같은 것들이 라이브러리입니다.

엥? 왜 React가 라이브러리이지? 프레임워크 아니었어? 하는 사람이 있을 수도 있습니다.

과거의 저도 헷갈렸었는데, 정확히 리액트의 생태계는 프레임워크이지만 리액트만은 라이브러리라고 합니다.

 

프레임워크로 분류되기 위해서는 필수로 충족해야하는 것들이 있습니다. 

다른 많은 프레임워크들이 기본적으로 내장하고 있는 기능들말이죠.. (예를 들어 라우터 기능이라던가)

 

리액트에서 이러한 기능들을 구현하기 위해서는 여러가지 추가적인 라이브러리를 같이 사용해야합니다.

(react-router, react-redux, react-saga 등....) 

그렇기 때문에 React는 프레임워크로 분류되지 않고 라이브러리로 분류됩니다.

 

react 공식사이트 메인 캡쳐

 

 

물론 공식사이트에도 라이브러리로 소개되고 있습니다.^^

 

 

 

 

저는 DB를 공부한 사람이 아닙니다.

포트폴리오 사이트 제작을 하면서 겪었던 것에 대한 기록 글입니다.^^

 

 

 

 

들어가기 전에 잡담.

Sequelize를 통해 db 작업을 한 상태였는데, db의 d자도 모르다보니 

매번 정적인 데이터를 손으로 삽입하고는 했습니다.

(명령어를 치거나, 워크벤치 들어가서 작업하거나, 하다하다 안되서 어드민을 만들어서 데이터를 입력해서 db로 저장했습니다.)

근데 이게 db를 지워야하는 경우가 생기고, 배포 후에 운영db에 또 똑같은 일을 작업해야하고...

끝이 없는 이 작업 속에서 미치겠네라고만 생각했는데, (검색해볼 정도는 아니었나 ㅋ;;;;;)

 

여튼 그러다가 우연히 (Sequelize를 통해 작업한) back 폴더 안에서 seeders라는 폴더를 발견했고,

내가 만든 적도 없는데? 이게 뭥ㅈㅣ? 하다가 검색을 통해 알게되었습니다. 

seeders 폴더

Sequelize를 통해 더미데이터를 넣을 수 있다는 것을!!!!!!!!

자 매뉴얼을 참고하거나 아래 블로그 글을 일거보세요(전 처음부터 적지 않기 때문에)

 

매뉴얼

sequelize.org/master/manual/migrations.html

 

참고

any-ting.tistory.com/53

 

[Node.js] Sequelize Seeders 사용법

- 개요 안녕하세요. 이번 시간에는 Sequelize에 Seeders라는 기술에 대해 알아보겠습니다. 우리는 어떤 기능 개발을 하다 보면 테스트 데이터가 필요할 때가 있습니다. 필요할 때마다 우리는 데이터

any-ting.tistory.com

 

 

 

Sequelize Seed

만약, 모르고 seeders 폴더를 삭제했다면 아래 명령어로 init 하세요.

npx sequelize init:seeders 

 

 

 

DB 생성

- model 작업 후 db 생성 후의 상태를 전제로 합니다.

- seed를 통해 create하면서 진행할 수도 있는 것 같은데, 이러한 경우라면 매뉴얼을 참고하세요.

(model 작업 후 npx sequelize db:create를 통해 db 생성까지 할 수 있습니다.)

 

 

 

Migrate 하기 

npx sequelize-cli db:migrate

// [D] 가장 최근 migration 돌리기(취소)
npx sequelize-cli db:migrate:undo

 

 

 

Seeder 파일 만들기

파일명에 본인이 생성할 파일 명을 적어주세요.

npx sequelize seed:generate --name 파일명

 

예시

catchmind 데이터를 관리할 것이어서 catchmind를 파일명으로 지정했습니다.

npx sequelize seed:generate --name catchmind

seeder 만들기 결과

명령어를 통해 파일이 생성되는데, 앞에 생성한 날짜?와 같은 숫자들이 적힌채로 생성됩니다.

 

 

 

seeders 파일 내용 작성

파일로 들어가보면 코드들이 작성되어있습니다.

up은 실행 시 seeder를 수행할때 실행되는 로직이고 down은 실행 취소 시 실행되는 로직입니다.

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    /**
     * Add seed commands here.
     *
     * Example:
     * await queryInterface.bulkInsert('People', [{
     *   name: 'John Doe',
     *   isBetaMember: false
     * }], {});
    */
  },

  down: async (queryInterface, Sequelize) => {
    /**
     * Add commands to revert seed here.
     *
     * Example:
     * await queryInterface.bulkDelete('People', null, {});
     */
  }
};

 

예시

컬럼이나, 데이터 타입 같은 것들을 안 맞추면 실패합니다.

string으로 넣어야하는데 실수로 json으로 넣었더니 fail이 되었습니다.

이때는 터미널에서 알려줍니다.

 

[데이터베이스]

db를 테이블 캡쳐를 보면, 저에게 필요한 것은 id, question, correct, incorrect 네가지인 것 같습니다.

id는 자동으로 증가해서 추가하지 않아도 되지만, 문제 번호로써 그냥 추가했습니다.

만약 id를 작업하지 않으면 자동으로 삽입이 됩니다만, undo후 seed를 반복하면 0로 reset되는 것이아니라 계속 증가하는 번호로 삽입됩니다. (저는 reset하는 것을 찾지 못했습니다 ㅜ)

catchmind db 캡쳐

 

[models/catchMind.js]

모델에서 데이터 타입을 다시한 번 확인해봤습니다.

const DataTypes = require('sequelize');
const { Model } = DataTypes;

module.exports = class CatchMind extends Model {
    static init(sequelize) {
        return super.init({
            question: {
                type: DataTypes.TEXT,
                allowNull: false, 
            },
            correct: {
                type: DataTypes.STRING(100),
                allowNull: false,
            },
            incorrect: {
                type: DataTypes.TEXT,
                allowNull: false, 
            },
        }, {
            modelName: "CatchMind", 
            tableName: "CatchMind", 
            timestamps: false,
            charset: 'utf8mb4', 
            collate: 'utf8mb4_general_ci',
            sequelize,
        });
    }

    static associate(db) {}
};

 

[seeders/XXXXXXXXXXXXXX-catchmind.js]

'use strict';

module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface.bulkInsert('catchmind', [
            {
            	id: '1',
                question: 'https://okayoon-bucket.s3.ap-northeast-2.amazonaws.com/game/catchmind/quiz/img_quiz00.png',
                correct: '가로수',
                incorrect: '["공","장","소","궁","한","이","야","기","잼","난","사","건"]',
            },
            {
            	id: '2',
                question: 'https://okayoon-bucket.s3.ap-northeast-2.amazonaws.com/game/catchmind/quiz/img_quiz01.png',
                correct: '견인차',
                incorrect: '["강","초","숭","구","리","당","하","늘","개","퍼","풍","사"]',
            },
            {
            	id: '3',
                question: 'https://okayoon-bucket.s3.ap-northeast-2.amazonaws.com/game/catchmind/quiz/img_quiz02.png',
                correct: '도시',
                incorrect: '["강","초","숭","구","리","당","기","잼","난","사","수","김"]',
            },
        ], {});
    },

    down: async (queryInterface, Sequelize) => {
        await queryInterface.bulkDelete('catchmind', null, {});
    }
};

up

- await queryInterface.bulkInsert('테이블명', [{}] 을 통해 테이블 명을 적어줍니다.

- models에서 지정한 type에 맞춰 데이터를 넣어줍니다.

 

down

- await queryInterface.bulkDelete('테이블명', [{}] 을 통해 테이블 명을 적어줍니다.

- 저렇게 쓰면 전체 초기화 됩니다.

 

 

 

Seed 실행

위에 작업을 모두 마쳤다면 실행해보겠습니다.

seed 명령어를 입력하면 데이터가 여러번 중복해서 들어갈 수 있습니다.

 

 

전체 파일 seed 실행

npx sequelize-cli db:seed:all

 

 

단일 파일 seed 실행

파일명에 날짜까지 다 입력해줘야합니다.

npx sequelize db:seed --seed 파일명

// [D] 예시
// npx sequelize db:seed --seed 20210406123050-catchmind.js

 

결과

seed 실행 후 결과 창

 

 

그 외 명령어 입니다.

 

 

 

저는 외래키도 없고 단순한 테이블에 하는 작업이어서 어려움이 없었지만, 복잡할 수록 작업이 복잡해지니,

꼭 매뉴얼을 확인하시길 바랍니다.

 

 

+ Recent posts