기본 콘텐츠로 건너뛰기

비동기 코드를 처리 하자

 이번 포스트에서는 비동기처림에 대한 간단한 처리만 해보고 넘어 가고자 한다. callback, promise, async await을 모르는 분만 읽기를 바라며 그저 간단하게 사용법을 소개 하는 포스트이다.  웹 개발뿐만 아니라 네트워크로 통해서 들어오거나 외부 레거시 코드를 실행하는 경우, 즉시 값이 리턴을 받지 않고, 해당 네트워크 혹은 레거시에서 처리후 callback을 통하여 실행 되는 경우가 많다.  이러한 경우를 처리를 해보자. function getDir ( path , callback ) { if ( typeof callback === 'function' ) { setTimeout ( () => { callback( [ 'Documents' , 'Download' , 'Etc' ] ) } , 1000 ) } }  위 처럼 해당 path에 있는 폴더들을 확인 하고 그 폴더들가지로 callback을 호출해주는 코드이다.  우린 위처럼 콜백 함수를 넣어서 순회를 할 수 있다.  예전에 구현해둔 map을 이용해서 적절하게 순회도 가능하다.  자 그렇다면 test 폴더안에서 Etc 폴더를 찾아서 그 안의 폴더인 Donwload 폴더를 찾아보면 어떤 코드가 될까?  위와 같이 표현이 될 수 있다. 그렇다면 점점 더 상세한 폴더가 필요 하게 되면 어떻게 될까?  즉 test/Etc/Download/Download/Download/Download/Download/Download 처럼 말이다.  코드는 점점 안쪽으로 들어가서 코드가 파악하기가 점점 복잡해진다. 위는 그나마 간단한 요구 조건이라서 덜 복잡해보이는 감이 있다.  getDir에다가 Promise를 입혀보자. function getDirPromise ( path ) { return new Promise (resolve => { ...

1000만 개 중에 2개 주세요(게으른 평가)

 요구조건으로 이런것이 왔다고 쳐봅시다.  서비스 개발한 서비스의 사용자의 데이터에서 포인트의 누적을 자신의 가족 수를 곱하고 그 값이 1000점 이상인 사람들 중에서 해당 포인트의 제곱근이 소수점을 버리고 홀 수 인 사람 중에 두사람의 마지막 계산된 포인트를 뽑아달라는 요청이 왔다.  ( 말도 안되는 시나리오지만 아 그렇구나 하고 넘어가자. )  일단 저 2명을 뽑기 위해서 take라는 함수를 구현해봅시다.   const take = ( count , iter ) => { const res = [] for ( const item of iter ) { res. push ( item ) if ( res. length === count ) return res } return res } 잘 동작 합니다. 고객 정보가 없기 때문에 적당히 고객정보를 구현 할 수 있도록 range도 구현을 해봅시다. const range = ( limit ) => { const res = [] let count = 0 while ( count < limit ) { res. push ( count++ ) } return res } 이제 샘플로 사용 할 고객 정보를 임의로 만들 수 있도록 함 수 하나를 만들겠습니다. 위 시나리오상 가족수랑 포인트만 있으면 되겠네요. const genMember = () => { return { family : Math . ceil ( Math . random () * 8 ) , point : Math . ceil ( Math . random () * 8000 ) } } 적당히 만들었습니다. 그러면 이제 1000만명을 만들어서 위의 로직을 돌려보도록 하죠. 저의 PC가 못버티는 관계로... 10만명으로 하겠습니다. const members = go ( range ( 1000000 ) , map ( genMember ) )...

map, filter, reduce (go, curry)

 간단하게 map, filter, reduce를 구현해보자. 1. map은 인자를 두개를 받으며, 첫번째 인자를 받아서 두번째 인자로 평가 후 배열로 리턴해준다. const map = ( iter , func ) => { const ret = [] for ( const item of iter ) { ret. push ( func( item ) ) } return ret }  위와같이 간단하게 짤 수 있다. 2. filter를 구현해보자 map과 두개의 인자를 받으며, 첫번째 인자를 받아서 두번째 인자로 평가 후 값이 있다며 배열로 리턴을 해준다. const filter = ( iter , func ) => { const ret = [] for ( const item of iter ) { if ( func( item ) ) { ret. push ( item ) } } return ret }   3. reduce는 세개의 인자를 받으며, 첫번째 인자를 받아서 두번째 인자로 받은 함수로 평가하며 축적된 값을 리턴을 한다, 이때에 세번째 인자를 초기값으로 이용한다. const reduce = ( iter , func , acc ) => { for ( const item of iter ) { acc = func(acc , item) } return acc }  이와 같이 표현 할 수 있지만, 초기값을 안넣은 경우에는 iter의 첫번째 값을 초기값으로 사용하게 변경 해보자. const reduce = ( ...args ) => { let iter = args[ 0 ] const func = args[ 1 ] let acc = args[ 2 ] if ( args. length < 3 ) { iter = iter[ Symbol . iterator ]() acc = iter. next (). value } ...

for of (feat.iterable)

 ES6부터 새로 생겨난 for of에 대해서 궁금증이 생겨서 학습안 내용을 포스트에 남깁니다. const arr = [ 1 , 2 , 3 , 4 ] for ( const value of arr ) { console . log ( 'value' , value ) } const set = new Set ([ 1 , 2 , 3 , 4 ]) for ( const value of set ) { console . log ( 'value' , value ) } const obj = { 0 : 1 , 1 : 2 , 2 : 3 , 3 : 4 } for ( const value of obj ) { console . log ( 'value' , value ) } Array, Set은 for of 문장으로 반복이 되지만, Object는 반복이 되지 않는가? obj is not iterable 인데, 반복할 수 없다 정도록 해석이 가능 할 것 같다. for of구문을 확인해보면 아래와 같다. iterable이 무엇인가? 간단하게 말하면 iterator를 생성할 수 있는 모든객체를 말 할 수 있다. 그러면 iterator는 무엇인가? 반복자를 말한다. 저 단어는 많은 개발자들이 많이 들어 보셧을 것이기 때문에 이하 생략한다. 여기서 더 중요한것은 for of는 무엇을 반복자로 받아 들이는가? 이다. 이에 대한 내용은 ES6에 추가된  protocol인   iterable protocol 과 iterator protocol을 확인 할 필요가 있다. 이 기준에만 충족을 한다면 자바스크립트의 for of에 적용 할 수 있다. protocol 두가지는 아주 심플하다. iterable protocol: 내용을 살펴 보면 Object 혹은 prototype chain 의 오브젝트 중 하나가 Symbol.iterator key의 속성을 가지며 값이  iterator protocol을 충족 시킬수 있는 값을...

코르도바 공유하기

 코르도바 플랫폼으로 작성 된 애플리케이션에서 외부 앱으로 공유하기를 만들어야 해서 찾아 보았습니다.    https://developer.mozilla.org/ko/docs/Web/API/Navigator/share  이거 쓰면 되겟네 생각하고 개발을 해버렸습니다. 하지만..... Browser compatibility : Android Webvie not Support...  지원을 안하더군요.. 네 안됩니다. 그래서 찾아보니  https://www.npmjs.com/package/cordova-plugin-web-share  이런 것이 있더라구요.  promise 기반이고으로 되어있어서 사용하기가 편하더라구요.  하지만... 이미지를 외부앱으로 공유해야 된다네요? 그래서 되나 해서 해봤는데.... 네, 텍스트만 잘 가더라구요. 소스를 열어서 보니, 이미지는 아직 지원이 안 되더 군요..  그래서 간단하게 만들어서 공유 합니다. https://github.com/sejinjja/cordova-plugin-shareutil  위와 같이 잘 되구요. 레파지토리 가서 보면 사용법은 나와있습니다. 수고요.  아!!! 안드로이드와 아이폰 지원 합니다.

Chart js와 amchart 비교

Chart js 특징은 위의 그림으로 대체 할 수 있을 듯 하다. 오픈 소스이고, 기본으로 제공하는 차트 종류가 8가지 Canv a s를 이용해서 차트를 그리고, 반응형을 지원한다. amchart amchart는 기본적으로 유료이며, 기본으로 제공하는 차트 종류가 기본적인 차트 + 주식 처럼 보이는 차트 + 지도에 관련된 차트(?) 까지 하면, 기본 제공 하는 종류가 20개 내외 이려나, 일일이 세기에는 양이 좀 많아 보인다. 렌더링은 svg를 통하여 그려지고, 당연 반응형도 지원이 된다. 그러면, 이 둘중에 어떤것이 내 프로젝트에 적합 하냐는 것이 문제이다. 일단, 주식 처럼 보이는 차트나 지도에 관련된 차트(?)가 필요하면, amchart를 선택해야 되는 것은 맞다. 그건 당연한 것이니 빼고 얘기 해보자! 여러 종류의 차트가 필요하다면, 일단은 amchart를 염두해 두는 것이 좋다. 돈 낸 만큼은 하는 듯 하다. 하지만, 기본적인 막대 그래프, 도넛 차트 등, 아주 기본적인 차트들인데, Chart js도 amchart도 그러한 차트가 없을 때가 문제가 된다. 그렇다면, 조금이라도 커스텀이 용이한 것을 찾는 것이 좋을 것이다.  일단 amchart에서 custom이라고 검색 하였을 때, 검색 결과가 61가지가 나온다. 차트의 종류도 많고, 각 차트마다 들어가는 속성이 매우 많기 때문에, 웬만한 내용들은 속성 값을 어떻게 주느냐에 따라서 변경이 가능 하게 된다. 커스텀의 예를 들면, 기본적으로 도넛 파이의 형태를 띄면서, 화살표로 목표를 표시해주는 차트가 필요하다고 생각 해보자. 이것은 amchart로 만든 그래프이고 이것은 chart js로 만든 그래프이다. 모양이 살짝 다르긴 하지만, 완벽하게 똑같이 구현 할 수도 있다. amchart로 만든 그래프의 경우, 저것은 도넛그래프가 아닌 guage 그래프이다. 원래 게이지 그래프는 이와 같...

javascript 압축 파일 다운로드

이번에는 전 게시글의 응용판? 이라고 해야하나....? 어쨋든! 우리는 각각의 파일들을 다운로드 해보았다. 그런데 생각보다 귀찮음?을 느꼇을 것이다. 파일을 각각 다운 받아야 한다는 현실때문에! 그래 파일 두개야 뭐 그렇다 치지... 하지만, 개발자도 사용자도 게으름뱅이이다. 자 결국, 우리가 해야 하는 것은 파일을 한 번에 둘다! 다운 받는 것이다. 물론, 클릭 한번에 여러개의 함수를 엮어서 다운받게 하면 되지만! 크롬에서 자주 봤듯이, 여러개의 파일을 다운로드를 시도하면 <- 여러개의 파일을 다운로드 합니다. 허용 합니까? 하고 물어보는 것을 볼 수 있다. 게다가 다운로드 한 파일들을 찾기도 귀찮다는 것. 자 해결책을 제시해보자면, https://github.com/Stuk/jszip 클라이언트 단에서 파일을 zip파일로 압축을 할 수가 있다! 필요한 작업은 아래와 같다. 0. 데이터 준비 1. BLOB(binary large object)를 만든다. 2. Blob을 URL.createObjectURL을 사용하여, 해당 binary의 주소를 생성. 3. 다운로드가 필요한 파일들을 Zip 객체에 셋팅! 4. a태그를 이용하여, 해당 url 셋팅 하고, 다운로드. 전 게시물과 별로 달라진게 없네... 자 그럼 샘플! 샘플을 보자! http://embed.plnkr.co/NMprnRxqYG0fkHa2J55D/ var util = {} function fixBinary(bin) { //binary to arrayBuffer var length = bin.length var buf = new ArrayBuffer(length) var arr = new Uint8Array(buf) for (var i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i) } return buf } window.onload = function() { ...

javascript 파일 다운로드

 개발을 하다보면, 클라이언트에 데이터가 있어서, 해당 내용을 파일로 다운로드 해야 하는 경우가 있다. 이번 포스트에서 서버와 상호 작용 없이, 간단하게 캔버스에 있는 이미지와 csv를 다운로드 하게 하는 내용을 작성하겠다.  필요한 작업은 아래와 같다. https://developer.mozilla.org/ko/docs/Web/API/Blob 0. 데이터 준비 1. BLOB(binary large object)를 만든다. 2. Blob을 URL.createObjectURL을 사용하여, 해당 binary의 주소를 생성. 3. a태그를 이용하여, 해당 url 셋팅 하고, 다운로드.  끝이네... 간단하네.. 일단 코드! 코드를 확인 하자.  간단하게, csv파일을 다운로드 하는 것과, canvas의 이미지를 다운로드 해보자.  샘플입니다. http://plnkr.co/edit/GZNEhOO99vgICgo9DZjJ?p=preview var util = {} function fixBinary(bin) { //binary to arrayBuffer var length = bin.length var buf = new ArrayBuffer(length) var arr = new Uint8Array(buf) for (var i = 0; i 3000) width.value = "3000" if (+height.value > 3000) height.value = "3000" if (+width.value 위의 코드를 보면, 결국에는 util.saveAs 핵심이다. 나머지 코드는 뭐... 테스트용 코드나, 이미지에서 binary 뽑아내는 코드들이니 설명은 패스. util.saveAs 동작을 보면. 1. A태그를 head에 생성. ( 한 이유는 말그대로 body가 없는 경우를 피하기 위해서? 라곤 했지만... 헤드가 없는 경우는? 이렇거나, 바디...