기본 콘텐츠로 건너뛰기

프레임워크를 사용하면서 주의점.

  프레임워크/라이브러리가가 발전함에 따라, 대부분의 애니메이션 처리들은 다른 코드에 의존하며 제작하게 되었다. 대략 8년전만 해도.... 애니메이션의 처리를 정밀하게 처리하기 위하여, requestAnimationFrame을 이용하긴 하였다.  requestAnimationFrame에 대해서 잠깐 설명하자면, 브라우저의 경우, 1초에 최대 60프레임을 동작 시킬수 있다. 각 프레임이 렌더링이 되고나서 호출이 되게 하는 부분이라고 생각하면 될 것이다. 즉 모든 requestAnimationFrame을 통하여 60번을 실행하게 되면, 최소 1초이내에 60회가 실행 된다고 보면되지만... 요청하는 내용과 기기의 사양에 따라, 1초보다 훨씬 긴 시간이 될 수 있다.  그 시절 requestAnimationFrame을 이용하여, 구현 할 수 밖에 없었던 것도 있긴하다. 라떼 이야기이긴 하지만, 어쨋든 우리나라에는 IE가 있었기 때문에, css에 의존한 애니메이션동작을 한게가 있었다. 하지만, 지금은 어떤 서비스가 IE를 지원을 할까? 마이크로소프트 공식 홈페이지도 IE를 지원하지 않을 것 같다.  프레임워크/라이브러리 발전에 따라 requestAnimationFrame을 사용할 수도 없는 환경이 되었다. 프레임워크의 경우 내 코드를 실행하는 주체는 프레임워크이고, 그 사이에 너무나 많은 코드들을 수행한다. 즉 프레임워크 외적의 무언가를 사용하여, 값을 변경하는 것은 공유자원에 여러 소비자들이 사용하는 동시성문제 수준의 오류가 발생 할 수도 있다.  가장 간단한 것은 다음과 같은 문제이다. <script setup > import { ref } from 'vue' const title = ref( 'title' ) const foo = function () { const $input = document . querySelector ( '#inputTest' ) $input.value = ...

정규표현식 g 플래그가 무엇일까?

  부끄러운 이야기이지만, 정규표현식을 공부를 한 적이 없다. 무슨말인가 하면, 그냥 인터넷에 전화번호 정규 표현식이라고 검색만 하고, 이메일 정규표현식이라고 검색만 해보고 사용을 해왔다.  뭐 그것이 나쁘다고 하는 소리도 아니고, 앞으로는 정규표현식을 매번 창조 할 것이라고 말하는 것도 아니다. 인류는 바퀴를 한 번만 발명 하였다.  오늘 이야기 할 이야기는 g 플래그이다. const aRegx = / a /g ; console . log ( aRegx . test ( 'a' )) ; // true console . log ( aRegx . test ( 'a' )) ; // false 단적인 예로 위의 코드가 true, false로 값이 나온다라는 걸 알고 있다면, 딱히 해당 포스팅을 굳이 볼 필요는 없을 것 같당... 자 위와 같은 상황이 왜 나오게 되는 걸까? g 플래그와 결과값 g 플 래그는 정규 표현식에서 모든 패턴 일치 를 찾는 데 사용됩니다. 코드 예시에서: aRegx 는  /a/g  정규 표현식을 사용합니다.  이는 문자열 내에서 모든 "a"를 찾도록 설정됩니다. 첫 번째  test호출은 "a" 문자열에서 첫 번째 "a"를 찾고  true 를 반환합니다. 두 번째   test호출은  이전 검색이 끝난 위치 에서 검색을 시작합니다.  즉,  첫 번째 "a" 이후부터 검색합니다. "a" 문자열에는  "a"가 하나만 존재 하기 때문에 두 번째 호출은 더 이상 일치하는 문자를 찾지 못하고, false 를 반환합니다. 결론적으로: g 플래그는 모든 일치를 찾도록 합니다. 이전 검색이 끝난 위치( lastIndex )에서 다음 검색을 시작합니다. 참고: lastIndex 속성을 사용하여 이전 검색의 마지막 위치를 직접 확인하거나 조작할 수 있습니다. g 플래그 없이 사용하면 첫 번째 일치만 찾고 검색을 종료합니다.

else 사용하지 않기(?)

 자 일단 if ~ else를 사용하는 것이 나쁘다고 말하고 싶은 생각은 추호도 없다. 하지만, 뇌에서 그냥 흘러나오는 방식대로만 작성하는 것은 그렇게 좋지 않은 코드라고 생각하기 때문에 작성을 해본다.  else를 사용하지 않아도 되는 상황을 좀 생각해보도록 하자.  재밌는 것을 가져왔다.  혼인 신고가 가능한 나이에 대한 것이다.  남자는 만 18세, 여자는 만 16세에 달해야 하며, 만 20세 미만의 미성년자는 부모의 동의를 얻어야 한다.  자 우리가 프로그래밍 해볼 것은 이거다.  1. 16세 미만이면 결혼 불가능  2. 16세 ~ 18세 미만이면 여자라면 부모 동의를 받은 경우 결혼 가능.  3. 20세 미만이면 부모 동의를 받은 경우 결혼 가능.  4. 20세 이상이면 부모 동의없이 결혼 가능. function canIWedding (person) { if (person?.age) { if (person. age < 16 ) { console. log ( '한국에서 결혼 불가' ) } else if (person. age < 18 ) { console. log ( '여자라면 부모 동의 시 가능' ) } else if (person. age < 20 ) { console. log ( '부모 동의 시 가능' ) } else { console. log ( '결혼가능' ) } } else { console. log ( '출생신고 필요.' ) } }  뭐 일단 동의하고 시작할 것이 있다. 딱히 로직이 어렵지는 않다.  하지만 위의 로직을 그대로 들여다 보도록 하자. 말 그대로 그대로 말이다.  자 21세의 경우라고 생각을 해도록 하...

== 한번 더 보기

  ==을 이야기하려면 글을 몇개를 작성해도 끝이 없을 것 같다. 그 만큼 사용하기 까다로우며, 몇 가지 규칙들은 꽤나 많은 ===을 대신 할 수 있는 장점이 있다.  간단하게 null을 이용한, undefined, null 체크가 있다. if ( null == null && null == undefined ) { console . log ( 'A == null 은 null 과 undefined 를 체크 할 수 있습니다 .' ) }  위의 코드를 ===를 이용하여 체크하려면, if ( null === null || undefined === undefined ) { console . log ( 'A === null 은 null 만 체크가능 하여 , undefined 를 체크 하기 위해서는 길이가 길어집니다 .' ) } 하지만 ==는 아래와 같은 문제점이 있다. if ( [] == false ) { console . log ( '[] 는 false 입니다 .' ) } if ( [] == 0 ) { console . log ( '[] 는 0 입니다 .' ) } if ( [] == '0' ) { console . log ( '[] 는 \' 0 \' 이 아닙니다 .' ) } if ( 0 == '0' ) { console . log ( '0 은 \' 0 \' 입니다 .' ) } [] == 0이고, 0 == '0'이지만, [] == '0'이 아니게 된다. 삼단논법이 박살나는 순간이다. 참고로 []는 ''이다.... if ( [] == '' ) { console . log ( '[] 는 \'\' 입니다 .' ) } 자 그러면, 왜 []는 ''인지 생각을 해볼 필요...

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 ="...