├── README.md └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # FEConf2019 - ES6+ 비동기 프로그래밍과 실전 에러 핸들링 2 | 3 | ## 이미지 가져오기 4 | 5 | ```javascript 6 | const {log, clear} = console; 7 | 8 | const imgs = [ 9 | { name: "HEART", url: "https://s3.marpple.co/files/m2/t3/colored_images/45_1115570_1162087_150x0.png" }, 10 | { name: "6", url: "https://s3.marpple.co/f1/2018/1/1054966_1516076919028_64501_150x0.png"}, 11 | { name: "하트", url: "https://s3.marpple.co/f1/2019/1/1235206_1548918825999_78819_150x0.png" }, 12 | { name: "도넛", url:"https://s3.marpple.co/f1/2019/1/1235206_1548918758054_55883_150x0.png"}, 13 | ]; 14 | 15 | const imgs2 = [ 16 | { name: "HEART", url: "https://s3.marpple.co/files/m2/t3/colored_images/45_1115570_1162087_150x0.png" }, 17 | { name: "6", url: "https://s3.marpple.co/f1/2018/1/1054966_1516076919028_64501_150x0.jpg"}, 18 | { name: "하트", url: "https://s3.marpple.co/f1/2019/1/1235206_1548918825999_78819_150x0.png" }, 19 | { name: "도넛", url:"https://s3.marpple.co/f1/2019/1/1235206_1548918758054_55883_150x0.png"}, 20 | ]; 21 | 22 | const loadImage = url => new Promise((resolve, reject) => { 23 | let img = new Image(); 24 | img.src = url; 25 | // log('이미지로드: ', url); 26 | img.onload = function() { 27 | resolve(img); 28 | }; 29 | img.onerror = function(e) { 30 | reject(e); 31 | }; 32 | return img; 33 | }); 34 | 35 | // loadImage(imgs[0].url).then(img => log(img.height)); 36 | 37 | ``` 38 | 39 | ## 실전 40 | - 이미지들을 불러와서 모든 이미지의 높이를 더한다. 41 | 42 | ```javascript 43 | async function f1() { 44 | try { 45 | let error = null; 46 | const total = await imgs2 47 | .map(async ({url}) => { 48 | if (error) return; 49 | try { 50 | const img = await loadImage(url); 51 | return img.height; 52 | } catch (e) { 53 | log(e); 54 | throw e; 55 | } 56 | }) 57 | .reduce(async (total, height) => await total + await height, 0); 58 | 59 | log(total); 60 | } catch (e) { 61 | log(0); 62 | } 63 | } 64 | // f1(); 65 | ``` 66 | - 위 코드는 에러를 어설프게 핸들링하여 오히려 에러보다 심한 버그가 생긴 코드입니다. 67 | 68 | ## 해결 69 | - Promise, async/await, try/catch 잘 다루기 70 | 71 | ```javascript 72 | function* map(f, iter) { 73 | for (const a of iter) { 74 | yield a instanceof Promise ? a.then(f) : f(a); 75 | } 76 | } 77 | async function reduceAsync(f, acc, iter) { 78 | for await (const a of iter) { 79 | acc = f(acc, a); 80 | } 81 | return acc; 82 | } 83 | 84 | const f2 = imgs => 85 | reduceAsync((a, b) => a + b, 0, 86 | map(img => img.height, 87 | map(({url}) => loadImage(url), imgs))); 88 | 89 | // f2(imgs).catch(_ => 0).then(log); 90 | f2(imgs2).catch(_ => 0).then(log); 91 | ``` 92 | 93 | ## 정리 94 | 95 | - Promise, async/await, try/catch를 정확히 다루는 것이 중요합니다. 96 | - 제너레이터/이터레이터/이터러블을 잘 응용하면 코드의 표현력을 더할 뿐 아니라 에러 핸들링도 더 잘할 수 있습니다. 97 | - 순수 함수에서는 에러가 발생되도록 그냥 두는 것이 더 좋습니다. 98 | - 에러 핸들링 코드는 부수효과를 일으킬 코드 주변에 작성하는 것이 좋습니다. 99 | - 불필요하게 에러 핸들링을 미리 해두는 것은 에러를 숨길 뿐입니다. 100 | - 차라리 에러를 발생시키는게 낫습니다. sentry.io 같은 서비스를 이용하여 발생되는 모든 에러를 볼 수 있도록 하는 것이 고객과 회사를 위하는 더 좋은 해법입니다. 101 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ES6+ 비동기 프로그래밍과 실전 에러 핸들링 6 | 7 | 8 | 9 | 10 | # 이미지 가져오기 11 | 12 | 43 | 44 | ## 실전 45 | - 이미지들을 불러와서 모든 이미지의 높이를 더한다. 46 | 47 | 71 | 72 | - 위 코드는 에러를 어설프게 핸들링하여 오히려 에러보다 심한 버그가 생긴 코드입니다. 73 | 74 | ## 해결 75 | - Promise, async/await, try/catch 잘 다루기 76 | 77 | 98 | 99 | # 정리 100 | 101 | - Promise, async/await, try/catch 를 102 | 정확히 다루는 것이 중요합니다. 103 | 104 | - 제너레이터/이터레이터/이터러블을 잘 응용하면 105 | 코드의 표현력을 더할 뿐 아니라 106 | 에러 핸들링도 더 잘할 수 있습니다. 107 | 108 | - 순수 함수에서는 에러가 발생되도록 그냥 두는 것이 더 좋습니다. 109 | 110 | - 에러 핸들링 코드는 부수효과를 일으킬 코드 주변에 작성하는 것이 좋습니다. 111 | 112 | - 불필요하게 에러 핸들링을 미리 해두는 것은 에러를 숨길 뿐입니다. 113 | 114 | - 차라리 에러를 발생시키는게 낫습니다. 115 | sentry.io 같은 서비스를 이용하여 116 | 발생되는 모든 에러를 볼 수 있도록 하는 것이 117 | 고객과 회사를 위하는 더 좋은 해법입니다. 118 | 119 | 120 | 121 | --------------------------------------------------------------------------------