기본 콘텐츠로 건너뛰기

Promise.race

  Promise race는 promise끼리 경주를 시킨다고 보면 될 것 같다. 같은 기능의 api를 중복 호출 하는 경우 const delay = (ms) => new Promise ((resolve) => setTimeout (resolve, ms)); async function searchApiv1 () { await delay ( Math . random () * 5000 ); return 'searchApiv1' } async function searchApiv2 () { await delay ( Math . random () * 5000 ); return 'searchApiv2' } const res = await Promise . race ([ searchApiv1 (), searchApiv2 ()]) console . log ( res )  자 위의 코드를 잠깐만 살펴보자, searchApiv1, searchApiv2은 각각 5초이내에 완료가 되는 api라고 보면 된다. 둘 중 하나의 api의 결과만 필요한 경우, 위처럼 작성하면 된다.  뭐 물론 위와 같은 코드를 짤만한 상황이 그렇게 많지는 않을 것이다. 조금 현실적인 예제를 보도록 하자. 클라이언트 에서의 api타임아웃 구현 const delay = (ms) => new Promise ((resolve) => setTimeout (resolve, ms)); async function searchApi () { await delay ( Math . random () * 5000 ); return 'searchApiv1' } async function requestTimeout (ms) { await delay (ms) throw 'request time out' } try { const res = await Promise . race ([ search...

setTimeout, setInterval을 이용한 호출 스케줄링

 setTimeout: 일정 시간이후에 함수를 실행 시켜준다.  setInterval: 일정 시간마다 함수를 실행 시켜준다.  자 생각을 해보자, 특정 시간마다 alert을 띄워주는 함수이다.  특정 시간마다라고 생각해보면, setInterval을 생각 할 수 있다. setInterval (() => { alert ( 'called' ) }, 1000 )  자 이렇게 작성 하게되면 어떤 이슈가 있을까? 여기서 문제는 alert이 띄워진 상태에서도 시간이 지나고, 1초마다 콜백 실행이 태스크큐에 쌓인다는 것이 문제이다.  그러면 어떻게 해야 할까? function setIntervalTimeout (cb, ms) { return setTimeout (() => { cb(); return setIntervalTimeout (cb, ms) }, ms); } setIntervalTimeout (() => alert ( 1 ), 1000 )  위처럼 사용 하면, interval 처럼 사용 하면서, alert이 종료된 이후에 스케쥴링을 등록을 하기 때문에, alert이 종료 된 이후에 스케쥴을 등록하게 되어, alert이 중첩실행 되지 않게 수정이 가능하다.  하지만 위에서 문제는... clearTimeout이 불가능 하다는 것이다. 자 그러면 어떻게 해야 할까? function setIntervalTimeout (cb, ms) { const ret = {} ret . timeoutSeq = 0 ; ret . timeoutSeq = setTimeout ( function run () { cb(); ret . timeoutSeq = setTimeout ( run , ms) }, ms); return ret } const test = setIntervalTimeout (() =...

함수 정의 어떤기준으로 할까?

 함수를 만들 때, 대부분의 사람들이 고민을 하게 된다. 이 정도로 짧은 라인일 뿐인데 혹은 한번밖에 쓰이지 않는 로직인데, 함수로 정의해야 할까?  이런 고민을 하는 이유는 프로그래밍을 배우면서, 함수에 대한 정의를 배우기 때문(?)일 것 같다.  - 함수(function), 서브루틴(subroutine), 루틴(routine), 메서드(method), 프로시저(procedure)는 소프트웨어에서 특정 동작을 수행하는 일정 코드 부분이다. 즉, ' 특정한 작업을 위해 재활용할 수 있도록 구현한 코드 블록 '을 의미한다.  재활용할 수 있도록 구현한 코드 블록. 솔직히 나는 이 재활용이란 단어를 왜 넣었는지, 이해가 되지 않는다. 재사용도 아니고... 재활용이라니...  한국어가 아닌 영어로도 보자.  - Functions may be defined within programs, or separately in libraries that can be used by many programs. In different programming languages, a function may be called a routine, subprogram, subroutine, or procedure; in object-oriented programming (OOP), it may be called a method. Technically, these terms all have different definitions, and the nomenclature varies from language to language. The generic umbrella term callable unit is sometimes used.  단지 실행 가능한 단위일 뿐이다. recylce이라던지, reuse라던지 우리가 아는 단어가 없다.  자 그러면 잠깐 아래의 코드를 잠깐만 보도록 하자. async function updateEm...

continue, break, label 사용해야 할까?

 반복문을 사용하다보면, continue, break를 사용해야 하는 경우가 있다. break의 개념은 순회함수에서도 가끔 사용 되는 경우가 있는데, 아래와 같은 경우이다. let res = 1 ; for ( let i = - 8 ; i < 20 ; i++) { res *= i ; if (! res ) break; } res = 1 ; [ 1 , 2 , 4 , 5 , 2 , 3 , 1 , 0 , 2 , 3 , 1 ]. every (i => { return res *= i ; }) 개인적으로는 싫어하는 방식이지만.. every와 some의 경우 return을 이용하여, break처럼 사용할 수 있다.  일반적으로는 label을 사용해본 경험이 있는가? 웬만하면, c언어에서 이런 문법도 있어요~ 수준으로 소개를 할 뿐 스파게티 소스가 되기 때문에 label을 사용한 경험은 웬만해서는 없을 것이다.  continue와 label을 합친 방식은 continue가 순회문에서만 사용가능 하기 때문에, 큰 의미는 없으나, label과 break를 합친 방식은 사용하려면 해볼 수 는 있다.  break와 label을 합친 빠른리턴, function foo (str) { if ( typeof str !== 'string' ) return; // 추가적인 로직 console . log ( '실행되지 않음' ) ; } const str = null; bar: { if ( typeof str !== 'string' ) break bar ; // 추가적인 로직 console . log ( '실행되지 않음' ) ; } console . log ( '여기는 실행 된다.' ) ;  함수라면, 더이상 실행 되지 않아야 하는 구간에서는 return;을 사용 하여, 실행을 중지 할 수 있지만, 평가 중 부분만 건너뛰어야한다면, 위처럼 break와 lebel을 사용하여, 건너뛰는 것...

Document PIP(Picture in Picture) 기능

  PIP기능의 경우, 안드로이드 사용자라면, 웬만하면 사용해보았을 것이다. 별건 아니고...  유튜브같이 영상 매체를 실행중에, 홈화면으로 진입하게 되면, 위와 같이 플로팅UI를 사용하여, 영상을 계속적으로 볼 수 있게 지원해주는 기능이다.  지금까지는 위처럼 영상에서만 가능하였지만, 현재 실험적기능으로 문서를 플로팅 처리하는 것이 생겼다.  하지만, 아쉽게도... PC기준으로, 크롬, 엣지, 오페라 정도만 지원을 하고 있다. 하지만, 이정도로만 해도, 의미는 있다. 어드민 페이지를 구현을 하다보면, 스크롤이 길게 생기는 경우가 있고, 값을 확인하여, 결과값을 입력해야 하는 경우같은 경우도 있기 때문에, 부분적으로 플로팅 UI를 지원하는 것은 앞으로 꽤나 큰의미를 가질 수 있다.  간단하게 코드로 작성해보자. <!doctype html > <html class ="no-js" lang ="" > <head> <meta charset ="utf-8" > </head> <body> <table id ="contents" > <tr> <th> 이름 </th> <th> 나이 </th> <th> 성별 </th> </tr> <tr> <td> 테스트 </td> <td> 20 </td> <td> 남자 </td> </tr> <tr> <td> 테스트2 </td> <td> 30 </td> <td> 여자 </td> </tr> </table> <button onclick =...

undefined 사용해도 될까?

 자, 일단 undefined에 대한 사적적의미를 살펴보자. "한정되지 않은, 확실하지 않은"이라는 뜻이다. 일단 defined의 반대의 의미니 defined뜻도 한번 알아보자. "정의된"이라는 뜻이란다.  단 이번 포스팅에서는 undefined는 "정의되지 않은"으로 해석을 진행 하려고 한다.  (사실 정의하다. 라는 말은 함수에서나 사용 하는 단어이니, 다른 개발자와 의사소통할 땐, 주의해야한다.)  기본적으로 우리 자바스크립트 개발자가 설명하는, null과 undefined의 사용방식의 차이를 생각해보도록 하자. let foo = null ; let bar ;  위와 같이 선언을 한 경우, foo의 경우에는 의도적으로 null값을 넣어, 아직 할당 되지 않은 상태를 표현한다. bar의 경우에도 모든 변수의 초기값은 undefined로, 정의 되지 않은 상태를 표현한다. 자 그럼 다음 코드를 보자. const obj = { a : null } console . log ( obj . a ) console . log ( obj . b )  우리는 obj.a의 값은 null이고, obj.b의 값은 undefined라고 생각 하게 된다. 자 여기서 이상한 말이 생겼다. obj.b의 값이 undefined라고 생각하게 된다.  자 이 말이 왜 어색 할까? undefined는 정의가 되지 않았다라는 뜻 아닌가? const obj = { a : null , b : undefined }  실제로 위와 같이 작성해야 우리는 obj.b의 값이 undefined라고 말을 해야 하지 않은가? 여기서 undefined를 사용해서는 안되는 이유를 하나 이야기 해보자.  obj.b의 값이 undefined에요.  위와 같은 말을 하였을 때, obj.b의 값이 undefind라는 말일까? obj.b가 정의되지 않은 상태라는 것을 말하는 것일까?  키의 순회 const o...

단일 진실 공급원(Single Source Of Truth)

 Single Source Of Truth 백엔드 개발자라면, 자주 들어보았을 것이고, 아쉽게도 프런트엔드만 개발했다면 들어 기회가 별로 없다.  하지만, 대부분의 개발자들이 지키고 있을 원칙이다. 정보 시스템 설계 및 이론에서, 단일 진실 공급원(영어: single source of truth, SSOT)은 정보 모형과 관련된 데이터 스키마를 모든 데이터 요소를 한 곳에서만 제어 또는 편집하도록 조직하는 관례를 이른다.  위의 말은 되게 어려우니, 간단하게 알아보도록 하자. A B SUM 1 2 3 2 3 5 3 4 6  자 위와 같은 데이터가 있다고 하자. 빨간 라인이 일단 잘 못 되었다는 것을 느낄 것이다. [{a:1, b:2, sum:5}, {a:2, b:3, sum:5}, {a:3, b:4, sum:6}]  이런 문제가 왜 생기는 것일까? SUM은 A, B의 파생 데이터지만, 위의 상황에서는 A, B의 값을 참고해서, 직접 계산한 값을 SUM의 필드로 관리하고 있는 것이 문제다. => 즉 A, B의 값이 복사 되어 SUM 필드에서 또 관리가 되고 있는 샘이다. ROW A B SUM 1 1 2 =SUM(A:1, B:1) 2 2 3 =SUM(A:2, B:2) 3 3 4 =SUM(A:3, B:3)  자 이 형태는 어떤가? SUM은 이제 A와 B의 참조만 이루어 지고, 결과 값으로 자연스럽게 두 개의 필드의 합이 계산될 것이다.  => A, B의 값이 변경 되는 경우 SUM을 수정할 필요가 없어지기 때문에, SSOT를 잘 지키고 있는 셈이다.  자 실전의 예제를 한번 보도록 하자. <template> <div v-for =" user in userList " :key =" user . userId " > <label> {{ user . name }} <input type ="checkbox" v-model ="...

명명 vs 익명

 익명함수와 명명함수의 성능차이. const test = () => {} console . time ( 'a' ); for ( let i = 0 ; i < 1000000 ; i ++) [ 1 ]. some ( test ) console . timeEnd ( 'a' ); console . time ( 'b' ); for ( let i = 0 ; i < 1000000 ; i ++)[ 1 ]. some (()=>{}) console . timeEnd ( 'b' ); 자 일단 위의 코드를 보자. 어떤게 빠를까? 사실 이 코드를 작성하면서 a가 더 빠르겟지 라는 별생각 없이 작성하기는 하였다. 실제로는 b가 더 빠른 것이 확인 되었다. a: 10.313232421875 ms b: 2.833251953125 ms 위와 같은 결과가 나오자, 명명 함수를 참조하는 데에 오버헤드가 발생할 것이라 생각했다. 하지만, b의 경우 매번 새로운 함수를 생성하고 있지 않은가?  일단 이것이 착시이긴 하다. b의 경우 "() => {}"를 매번 생성하는 것이 아닌, 메모리에 생성 후 참조 하게 된다. 즉 생성은 한번만 하게 된다. 물론 명명함수도 메모리에 저장될 것이다. 하지만, 명명함수의 경우 "이름 => 참조 메모리" 단계가 포함이 되어있다. const test = function () {} const foo = () => {} console . time ( 'a' ); for ( let i = 0 ; i < 10000000 ; i ++) test ( foo ) console . timeEnd ( 'a' ); console . time ( 'b' ); for ( let i = 0 ; i < 10000000 ; i ++) test (() => {}) console . timeEnd ( 'b...

코드에 의미 담기 - 1

   지난번 "무색의 초록 개념들이 격렬하게 잔다."라는 문장을 빗대어, 코드에 의미를 담는 것이 중요하다.라는 이야기를 하였다.  그럼, 코드에 의미를 어떻게 담아볼 수 있을까? 간단하게 다섯가지를 한 번 소개 해보겠다. 1. 변수명 잘 짓기 const boardList = { count : 5 , list : [{ boardId : 1 , title : 'test' , contents : '안녕하세요.' } , { boardId : 2 , title : 'test' , contents : '안녕하세요.' } , { boardId : 3 , title : 'test' , contents : '안녕하세요.' } , { boardId : 4 , title : 'test' , contents : '안녕하세요.' } , { boardId : 5 , title : 'test' , contents : '안녕하세요.' }] }  자 위의 코드가 무엇이 잘못 되었을까? boardList  list라는 단어를 사용 하였지만, boardList는 Object이다. 우리가 list라고 말할 수 있는 데이터 타입은 순서가 있는 자료구조들을 뜻하기 때문에, key, value 형태의 자료구조인 object에 list라고 명명하는 것은 좋지 않다. 2. 고차 함수 사용 시 주의하기  const nameList = [ { firstName : '길동' , lastName : '홍' } , { firstName : '길은' , lastName : '홍' } , { firstName : '길금' , lastName : '홍' } , { firstName : '길동' ,...

무색의 초록 개념들이 격렬하게 잔다.

  문학을 좋아하는 분들이라면,   Colorless green ideas sleep furiously           - Avram Noam Chomsky   위의 문장을 언젠간 한 번 보았을 것이다. 무슨 말일까?  무색의 초록 개념들이 격렬하게 잔다.  => 무색의 초록? 이미 초록인데 무색이라, 전문가들은 색을 바라보는게 좀 특이하다.       ("The Expert"라는 단편영화에서 보면, 빨간선을 투명잉크와 녹색잉크로 그려달라는 내용이 있었다.)  뭐 일단 잡설은 넘어가고, 위의 문장이 뜻하는 것은 문법에는 맞아도 의미상으로는 통하지 않는 말이 있다는 것을 보여주기 위해 예로 든 문장이다.  개발자들은 작업을 어떻게 하는가?  문제 -> 해결 방안 -> 코드 : 아마도 간단하게 설명하면 이런 순으로 진행을 하지 않을까 생각한다.  커먼한 프로그램을 만드는 경우, 개발자들이 마주할 문제, 해결 방안들은 어느정도 유사한 경우가 많다.  => 만약에 게시판을 만든다고 하면, 필연적으로 글쓰기, 댓글 개발, 추가적으로 카테고리화 파일 업로드 기능 등등.... 예상 가능한 기능들이 있지 않은가?  하지만 코드의 영역으로 가면 어떤가? 서버 사양은 어떻고, 사용자들이 사용할 클라이언트는 어떻고, 이는 크게 서버 버전이나 프로그래밍 언어를 제약사항까지 추가 될 수 있다.  하나의 기능을 만들더라도, 누가 언제 어디서 만드는 지에 따라 코드가 달라질 수 있다. 이런 특성 때문에, 대학교수님은 언젠가 프로그래머는 작가와 같이, 문장 하나하나에 의미를 담을 수 있기 때문에, 예술가 같기도 한다고 하였다.  자 일단 잘못 작성한 코드를 보자. function isNumber () { const number = 'number' ...

빈 배열로 호출하면 안되요. reduce

 예전에 some, every를 빈배열로 실행하면 어떻게 되는지 확인하였다. 추가적으로 reduce를 빈배열로 호출하면 어떻게 되는지 이야기해보고자 한다. [ 1 , 2 , 3 , 4 ]. reduce ((a, b) => a + b) reduce는 위와 같이, 반복적인 작업을 누적 시키고 싶을 때, 사용하곤 한다. const list = [] list . reduce ((a, b) => a + b) // Uncaught TypeError: Reduce of empty array with no initial value 하지만, 빈 배열로 실행을 하게 되면, 위처럼 에러가 발생 하게 된다. 물론 기본값을 설정하게 되면 에러가 발생하지 않는다. const list = [] list . reduce ((a, b) => a + b, 0 ) 왜 이렇게 구현 되어있을까? 23.1.3.24  Array.prototype.reduce (  callbackfn  [ ,  initialValue  ] )  4번 조건을 보게 되면 알 수 있다. 일단 4번 조건 까지만, 구현 해보자. Object . defineProperty ( Array . prototype , "reduceImpl" , { value : function (callback) { // 1. Let O be ? ToObject(this value). const o = Object ( this ) // 2. Let len be ? LengthOfArrayLike(O). const len = o . length || 0 // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. if ( typeof callback !== 'function' ) { throw new...

에러 다시보기 1

 혹시 함수를 만들면서 return null을 해본 사람이 있을까? 다시 정확히 질문을 바꾸어 보자, 어떤 함수를 실행 했을 때, null이 나오기를 바라면서 함수를 실행해본 사람이 있을까? 나는 타입언어를 배우는 동안 리턴타입의 지정을 Null이라는 클래스(?)로 해본적이 없다. Nullable은 있어도, Null이라는 클래스가 있는 언어가 있는지도 모르겠다.  언젠가, 널 포인터라는 개념을 만든 토니 호어는 "내 10억 달러 짜리 실수"라고 이야기 하였다. 그런 이야기가 나올 당시가, 함수형프로그래밍이 한참 인기가 있을 때, 나한테 까지도 이야기가 들어왔다. nullalbe객체가 있는데, 그걸 사용 하면 코드에서 null체크를 할 필요가 없어서 코드가 짧아지고, 우아한 코드를 만들 수 있어, null을 왜 만든거야? 뭐 상황에 따라 맞는 말이 될수도 있고, 상황에 따라 불편한 상황을 만들 수 있다.  오늘 내가 해볼 말은 조금 null을 사용해도 되지 않을까? return null을 해도 되는 상황이 있지 않을까? 라는 말을 하고 싶다.  만약, 당신이 앞으로 많은 사람들이 사용하게 될 언어의 readFile함수를 만든다고 생각을 해보자.  일단 첫째로, File 클래스를 리턴을 받아야 하고 path를 파라미터로 받게 되는 아래의 형태의 함수가 될 것이다. function readFile (path: String): File {}  문자열 타입으로 파일경로를 받고, File타입을 리턴을 하게 될 것이다. 더, 고민을 해볼꺼리가 남아있겠지만, 가장 간단하게, 따져볼만한 것이, 해당 경로에 파일이 없는 경우는 어떻게 처리 할 것인가?  여기서, 생각해볼만한 것이다. 세가지가 있을 것이다. 1. throw new PathError(path); 그 상황을 에러로 처분하는 방법. 2. return new File(); 그 상황을 빈 파일의 객체를 리턴하는 방법. 3. return null;  각각...