Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Minimum Hands-on Node.js / minimum handson nodejs
Daiki Kuriyama
November 29, 2019
Programming
18
4k
Minimum Hands-on Node.js / minimum handson nodejs
Daiki Kuriyama
November 29, 2019
Tweet
Share
More Decks by Daiki Kuriyama
See All by Daiki Kuriyama
Callback to Promise and beyond
ajido
12
28k
Other Decks in Programming
See All in Programming
Refactor with using `available` and `deprecated`
417_72ki
3
380
監視せなあかんし、五大紙だけにオオカミってな🐺🐺🐺🐺🐺
sadnessojisan
2
1.4k
社会人 20 年目エンジニア、発信で技術学びなおしてる話
e99h2121
1
140
AWSとCPUのムフフな関係
cmdemura
0
460
Amazon QuickSightのアップデート -re:Invent 2022の復習&2022年ハイライト-
shogo452
0
210
爆速の日経電子版開発の今
shinyaigeek
1
540
Quarto Tips for Academic Presentation
nicetak
0
910
Excelの助けを借りて楽にシナリオを作ろう
rpa_niiyama
0
270
23年のJavaトレンドは?Quarkusで理解するコンテナネイティブJava
tatsuya1bm
1
120
ポケモンで学ぶiOS 16弾丸ツアー 🚅
giginet
PRO
1
610
10年以上続くプロダクトの フロントエンド刷新プロジェクトのふりかえり
yotahada3
2
320
Milestoner
bkuhlmann
1
240
Featured
See All Featured
A Philosophy of Restraint
colly
193
15k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
349
27k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
236
1.1M
How to Ace a Technical Interview
jacobian
270
21k
How New CSS Is Changing Everything About Graphic Design on the Web
jensimmons
214
12k
Building a Scalable Design System with Sketch
lauravandoore
451
31k
Designing for humans not robots
tammielis
245
24k
Infographics Made Easy
chrislema
235
17k
GitHub's CSS Performance
jonrohan
1020
430k
A better future with KSS
kneath
230
16k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
15
1.2k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
101
6.2k
Transcript
.JOJNVN)BOETPO/PEFKT ձ 3PPN# ࣌ 201912݄01 14:15ʙ16:00 ్த15ͷٳܜΛڬΈ·͢ ϋογϡλά #jsconfjp_b εϐʔΧʔ
ɹɹɹ܀ࢁଠرʢ!"KJEPʣ ɹɹɹϠϑʔגࣜձࣾ›/PEFKTࠇଳ
.*/*.6.)"/%40//0%&+4 / 53 ௌߨରऀ▶︎+BWB4DSJQUͳΒগ͠Θ͔Δ͚ΕͲ/PEFKT͍·ͻͱͭͱ͍͏ํ ಘΒΕΔ▶︎ࠓ͙͑͢Δ/PEFKTͷجૅࣝ ͜ͷࢿྉͷϦϯΫ https://speakerdeck.com/ajido/minimum-handson-nodejs ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣
bit.ly/2XWSQQK εΫϦϓτϦϯΫ https://github.com/ajido/nodejs-handson ϋϯζΦϯதʹ্هϦϯΫϖʔδΛར༻͠·͢ɻࣄલʹ֬͝ೝ͍ͩ͘͞ ! 2
+BWB4DSJQU &4 &4ʙ 5ZQF4DSJQU ֶशϚοϓ ηΩϡΞϓϩάϥϛϯά / 53 04 104*9
8)"58("1* %0. FUD 'SPOUFOE 'SBNFXPSLT 8FC 'SBNFXPSLT 1BB4 $BB4 'BB4 /PEFKT$PSF"1* )551)5514 5$1*1 ˔ࠓճͷϋϯζΦϯ༰ 5PPMT %# 5FTU -PHFUD ! 3
جૅ Ԡ༻ ‣ Πϯετʔϧ 5 ‣ ϑϩʔ੍ޚ 38 ‣ Ϟδϡʔϧཧ
11 ‣ ඇಉظؔ 42 ‣ ಛ 16 ‣ σόοά ‣ σβΠϯύλʔϯ 21 ‣ Ϟδϡʔϧͷ࡞ ‣ ίʔϧόοΫ 23 ‣ ϓϩϑΝΠϦϯά ‣ Πϕϯτۦಈ 31 ‣ ϑϨʔϜϫʔΫͱπʔϧ ‣ ಉظॲཧ 35
Πϯετʔϧ OPEFKTPSH͔ΒΠϯετʔϧ͠·͢ɻ-54ͱ$VSSFOUͷ͏ͪɺظؒͷϝϯςφϯ ε͕อূ͞ΕɺՄೳͳݶΓޓੑ͕ҡ࣋͞ΕΔ-54όʔδϣϯΛબ͍ͯͩ͘͠͞ɻ ฐࣾͰιʔείʔυϏϧυͯ͠31.ύο έʔδʹ͍ͯ͠·͢ɻͦͷࡍύοέʔδϨ δετϦΛࣾʹ͚ͯηΩϡϦςΟରࡦ ͕ߦ͑ΔΑ͏ʹ͍ͯ͠·͢ɻ -54όʔδϣϯΛબ IUUQTOPEFKTPSH -54
ۮ ϲ݄ $VSSFOU ح ϲ݄ ! 5 / 53
දࣔͰ͖ͨΒɺ ԋशϦϯΫͷϖʔδΛ։͘ ʮग़ܽΛೖྗ͢ΔʯΛԡ͢ ࠓճԋशςετͳͷͰʮԋशςετʯͷ߲Λº͔Β⚪ʹมߋ͢Δ ʮೖྗ͢ΔʯΛԡͯ͠ɺԋशΛྃ͢Δ
λʔϛφϧͰ/PEFKTͷόʔδϣϯΛද͍ࣔͯͩ͘͠͞ɻ $ node -v v12.13.1 ԋशςετ ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣ bit.ly/2XWSQQK ͜ͷࢿྉͷϦϯΫ https://speakerdeck.com/ajido/minimum-handson-nodejs ! 6 / 53
ඪ४Ϟδϡʔϧʢ$PSF"1*ʣ /PEFKT(PPHMF$ISPNFʹ࠾༻͞Ε͍ͯΔ7+BWB4DSJQUΤϯδϯͱɺඪ४ͷ +BWB4DSJQUʹͳ͍֤छ࣮͕Έ߹ΘͤΒΕͨ+BWB4DSJQUͷ࣮ߦڥͰ͢ɻ const fs = require(‘fs') fs.readFile(__filename, (err, data)
=> { console.log(data) }) ͜͜Ͱͷඪ४Ϟδϡʔϧͱɺ/PEFKTʹΈࠐ·Εͨʮඪ४ͷ+BWB4DSJQUʹͳ͍ ֤छ࣮ʯͷ͜ͱΛࢦ͠·͢ɻ __filenameࣗͷεΫϦϓτ ϑΝΠϧͷઈରύεͰ͢ɻ ! 7 / 53
ඪ४Ϟδϡʔϧʢ$PSF"1*ʣ fs ϑΝΠϧΛ࡞ɾআ͢Δ path ϑΝΠϧύεɾσΟϨΫτϦύεΛѻ͏ http )551αʔόɾΫϥΠΞϯτΛ࣮͢Δ crypto ϋογϡɾ҉߸ɾॺ໊ɾݕূͳͲͷ҉߸ػೳΛѻ͏ util
ϢʔςΟϦςΟϞδϡʔϧ querystring 63-ΫΤϦจࣈྻΛύʔε͢Δ os $16ͷϗετ໊ͳͲͷ04ؔ࿈ใΛࢀর͢Δ child_process ࢠϓϩηεΛ࡞͢Δ cluster αʔόΛϚϧνϓϩηεԽ͢Δ assert มͷ༰ॲཧͷԠΛνΣοΫ͢Δ ΧςΰϦ جຊతͰଞʹґଘੑͷͳ͍"1* Events, Modules, Buffer, Stream ΧςΰϦ /PEFݻ༗ͷͷͰຊମͷಈ࡞ʹؔ࿈͢Δ"1* Timers, Process, Console ΧςΰϦ 04ͷػೳଞͷϥΠϒϥϦͱؔ࿈͢Δ"1* File System, Net, UDP/Datagram, TLS/SSL, Child Processes ΧςΰϦ ΞϓϦέʔγϣϯ͚ͷԠ༻"1* HTTP, HTTPS, Cluster IUUQTOPEFKTPSHEJTUMBUFTUEPDTBQJEPDVNFOUBUJPOIUNM ֤छඪ४Ϟδϡʔϧͱͦͷ༻్ͷҰྫ جఈΦϒδΣΫτผʹΧςΰϥΠζͨ͠ਤɻ ΧςΰϦ͔Βॱʹֶश͢Δ͜ͱͰɺΑΓཧղ͕ਂ·Γ·͢ ! 8 / 53
3&1- /PEFKTͷରతΠϯλʔϑΣʔεͰ͢ɻ3&1-ʢ3FBE&WBM1SJOU-PPQʣڥͰ ඪ४Ϟδϡʔϧ͕ࣗಈతʹϩʔυ͞ΕΔͨΊɺͦΕΒΛಡΈࠐΉ͜ͱͳ͘ѻ͑·͢ɻ $ node > /^\d+$/.test(‘1024’) true // requireすることなく標準モジュールを呼び出せます
> os.hostname() ‘MAC-Z-941.local’ > .exit ίʔυͷ͍͢ݕূʹཱͪ·͢ɻԋशதੋඇ׆༻ͯ͠Έ͍ͯͩ͘͞ɻ 3&1-ͷऴྃ<Ctrl>-D ΛૹΔ͔ .exit ͱೖྗ͍ͯͩ͘͠͞ɻ ͦͷଞίϚϯυ.helpΛࢀর ! 9 / 53
ࣗͷͷ$16ίΞͷΛɺඪ४Ϟδϡʔϧͱ3&1-Λͬͯද͍ࣔͯͩ͘͠͞ɻ $ node > 䡧䡧䡧䡧䡧䡧䡧䡧䡧 [ { model: 'Intel(R)
Core(TM) i5-5287U CPU @ 2.90GHz', speed: 2900, times: { user: 78882290, nice: 0, sys: 63998990, idle: 611174200, irq: 0 } }, ... ] > 䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧䡧 4 ԋश ͜ͷࢿྉͷϦϯΫ https://speakerdeck.com/ajido/minimum-handson-nodejs ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣ bit.ly/2XWSQQK εΫϦϓτϦϯΫ https://github.com/ajido/nodejs-handson 3&1-ͷऴྃ<Ctrl>-D ΛૹΔ͔ .exit ͱೖྗ͍ͯͩ͘͠͞ɻ ͦͷଞίϚϯυ.helpΛࢀর ! 10 / 53
جૅ›Ϟδϡʔϧཧ
OQN OQN /PEF1BDLBHF.BOBHFS OQN *ODʹΑΓཧɾఏڙ͞Ε͍ͯΔ/PEFKTΈ ࠐΈͷύοέʔδཧγεςϜͰ͢ɻੈքத͔Βར༻͞ΕΔதԝϨδετϦͷOQNKTDPNʹ ଟͷϞδϡʔϧ͕ެ։͞Ε͍ͯ·͢ɻ ༰ όʔδϣϯཧ node_modules
Ϟδϡʔϧͷ࣮ମɾιʔείʔυ package-lock.json Πϯετʔϧ͞ΕͨϞδϡʔϧͷπϦʔใ ✔ package.json ύοέʔδͷϝλσʔλ ϓϩδΣΫτʹґଘ͢ΔϞδϡʔϧͷཧσʔλͳͲ ✔ ۮൃతͳύοέʔδͷެ։Λ͙ͨΊʹ package.jsonʹprivate:trueΛهͯ͠ ͍ͩ͘͞ɻ ͜ͷΦϓγϣϯΛ༗ޮʹ͢Δ͜ͱͰɺຊདྷ package.jsonʹهड़͠ͳ͚ΕͳΒͳ͍֤छ ใΛলུ͢Δ͜ͱͰ͖·͢ɻ package-lock.json͕͋Εnode_modules σΟϨΫτϦ෮ݩͰ͖·͢ɻnode_modules όʔδϣϯཧͷର͔Β֎͍ͯͩ͘͠͞ɻ ! 12 / 53 // プロジェクトを新規作成する $ npm init $ npm install request $ ls ├── node_modules ├── package.json └── package-lock.json
npminitίϚϯυͰpackage.jsonΛ࡞ͨ͋͠ͱrequestϞδϡʔϧΛΠϯε τʔϧ͍ͯͩ͘͠͞ɻͦͷޙrequestϞδϡʔϧΛͬͯ)551ϦΫΤετΛૹΓɺ εςʔλείʔυΛද͍ࣔͯͩ͘͠͞ɻ const request = require('request') request('https://www.yahoo.co.jp', (err,
res, body) => { console.log(res.statusCode) }) ԋश ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣ bit.ly/2XWSQQK εΫϦϓτϦϯΫ https://github.com/ajido/nodejs-handson $ npm init $ npm install request ! 13 / 53
ηϚϯςΟοΫόʔδϣχϯά ."+03 ޙํޓੑΛࣦ͏ͱ͖ʹΠϯΫϦϝϯτ͞ΕΔ ͦͷࡍ.*/03ͱ1"5$)Λʹ͢Δ .*/03 ޙํޓੑ͕͋ΓɺػೳΛՃͨ͠ͱ͖ʹΠϯΫϦϝϯτ͞ΕΔ ͦͷࡍ1"5$)Λʹ͢Δ 1"5$) ޙํޓੑ͕͋ΓɺόάΛमਖ਼ͨ͠ͱ͖ʹΠϯΫϦϝϯτ͞ΕΔ ?
."+03.*/031"5$) ?ه߸ύοέʔδͷόʔδϣϯൣғΛࢦఆ͓ͯ͠Γɺࠨଆͷ Ͱͳ͍Λݻఆ͢Δ͜ͱΛද͍ͯ͠·͢ɻ͜Εഁյతͳ มߋΛආ͚ͨ߹ཧతͳΞοϓσʔτΛߦ͏͜ͱΛҙຯ͠·͢ɻ OQNύοέʔδ͜ͷ༷ ʹ४ڌͨ͠όʔδϣϯཧ͕ ਪ͞Ε͍ͯ·͢ɻ ύοέʔδར༻ऀجຊతʹ ηϚϯςΟοΫόʔδϣχ ϯάΛ೦಄ʹύοέʔδΛ ཧ͍ͯͩ͘͠͞ɻ ! 14 / 53
ϞδϡʔϧཧϫʔΫϑϩʔ $ npm init // 必要なら private: true を追加 $
npm install <name> // ツリー情報から node_modules を再構築 $ npm ci $ npm audit $ npm audit fix $ npm outdated $ npm update <name> / npm install <name>@<version> ϓϩδΣΫτΛ৽ن࡞͢Δ߹ طଘͷϓϩδΣΫτʹՃΘΔ߹ ੬ऑੑνΣοΫ ύοέʔδͷߋ৽νΣοΫɾՃ ! 15 / 53
جૅ›ಛ
ಛͱҙ /PEFKTͷαʔόʔγϯάϧϓϩηεɾγϯάϧεϨουͰେྔͷϦΫΤετΛॲཧ͠·͢ɻ͜ ͷ؍͔Βɺ·ͣ04ͷϓϩηε͋ͨΓͷϑΝΠϧσΟεΫϦϓλͷ੍ݶʹҙ͍ͯͩ͘͠͞ɻ # 初期値では明らかに足りません $ ulimit -n 1024 …
[Service] LimitNOFILE=65536 ॳظͷ··ϓϩμΫγϣϯڥͰϦΫΤετΛड͚͚ͯ͠·͏ͱɺߴ͍τϥϑΟοΫΛॲཧ ࢝͠ΊͨࡍʹToo many open filesʹΑΔϓϩηεμϯ͕΄΅࣮֬ʹൃੜ͠·͢ɻ $ ulimit -n 65536 $ ulimit -n 65536 ulimit -nʹΑΔ੍ݶͷ্ॻ͖ TZTUFNEʹΑΔ੍ݶͷઃఆ ัଊϚϧνίΞ͕׆༻Ͱ͖ΔڥͰҰൠ తʹclusterϞδϡʔϧΛͬͯϚϧνϓ ϩηεԽ͠·͢ɻ ! 17 / 53
Πϕϯτϧʔϓ /PEFKT͕େྔͷτϥϑΟοΫΛॲཧ͠ଓ͚ΔڥΛҡ࣋͢ΔͨΊʹɺΠϕϯτϧʔϓΛՄೳ ͳݶΓࢭΊͣʹӡ༻͢Δ͜ͱ͕ͬͱॏཁͰ͢ɻ͜ͷΠϕϯτϧʔϓ͕ͳʹ͔Λઆ໌͢Δલ ʹɺ·ͣΠϕϯτϧʔϓ͕؆୯ʹࢭ·ͬͯ͠·͏࣮ྫΛྻڍ͠·͢ɻ ϑΝΠϧωοτϫʔΫॲཧΛΘͳ͍$16Λ࣌ؒ༗͠ଓ͚Δॲཧͱɺػ࣌ؒͷ͍ಉظతͳ "1*Λར༻͢Δ͜ͱͰɺΠϕϯτϧʔϓக໋తͳ·Ͱʹఀࢭ͠·͢ɻ ͋Γ͕ͪ ΠϕϯτϧʔϓΛ࣌ؒఀࢭͤ͞Δ࣮ͷҰྫ ⚠⚠⚠ ඦ,#Ҏ্ͷڊେͳ+40/σʔλΛॲཧ͢Δ
⚠⚠ GTϞδϡʔϧͷಉظؔΛ͏ ⚠ ϧʔϓΛճ͠ଓ͚Δ ܦݧ্ɺڊେͳ+40/ͷύʔεʹΑΔ ύϑΥʔϚϯεྼԽ͕ඇৗʹଟ͍ɻ ! 18 / 53
Πϕϯτϧʔϓ const http = require('http') http.createServer((req, res) => { //
この部分の記述次第でパフォーマンスが劇的に変化する res.end() }).listen(8080) Πϕϯτϧʔϓ/PEFKTʹ͓͚Δ಄ͷΑ͏ͳͷͰɺ༩͑ΒΕ໋ͨྩΛॱ࣮࣍ߦ͢ ΔίΞͰ͢ɻ͜ΕΛҰఀࢭͤ͞ͳ͍ͱ͍͏͜ͱෆՄೳͰ͕͢ɺఀࢭ࣌ؒΛஅଓత͔ ͭ࠷খݶʹ͑ଓ͚Δ͜ͱͰɺ/PEFKTεϜʔζʹϦΫΤετΛॲཧ͠ଓ͚Δ͜ͱ͕ Ͱ͖·͢ɻ $ vegeta attack -duration=10s -rate=0 -max-workers=100 ॲཧͷ༰ 314 ͳ͠ JSON.parse 20KB JSON.parse 500KB fs.readFile 1MB fs.readFileSync 1MB forEach Loop 100 forEach Loop 100,000 ! 19 / 53
+40/σʔλͷ࠷దͳαΠζʁ ୯७ͳߏͷ+40/σʔλΛύʔεͨ͠ͱ͖ͷΠϕϯτϧʔϓͷఀࢭ࣌ؒ 0ms 50ms 100ms 150ms 200ms 100KB 300KB 500KB
700KB 900KB 2M 4M 6M 8M 10M 30M 50M ࠷దͳ༩͑ΒΕΔσʔλΞϓϦέʔγϣϯʹԠ࣮ͨ͡ࢪࢼݧʹΑׂͬͯΓग़͖͢Ͱ͕͢ɺ ҆ͱͯ͠ʮʢΑ΄Ͳେ͖ͯ͘ʣ࠷େ.ʹऩ·Δʯ͜ͱΛ೦಄ʹʮ࣌ؒܦաγεςϜͷʹ ͍+40/ͷαΠζ͕ංେԽ͠ͳ͍ʯ͜ͱͱʮϚϧνϓϩηεԽ͢Δʯ͜ͱʹཹҙ͍ͯͩ͘͠͞ɻ ! 20 / 53 ‑ڐ༰ൣғ ‑ݶք
σβΠϯύλʔϯ
σβΠϯύλʔϯ /PEFKTΠϕϯτϧʔϓΛఀࢭͤ͞ΔՄೳੑ͕͋Δॲཧͷେ෦Λඇಉظॲཧͱ͢Δ ͜ͱͰɺޮతʹτϥϑΟοΫΛॲཧ͠·͢ɻ͜ͷಛੑʹج͍ͨ/PEFKTͷಛత͔ͭ جૅతͳೋͭͷσβΠϯύλʔϯΛֶͼ·͢ɻ ! 22 / 53
σβΠϯύλʔϯ›ίʔϧόοΫ
ίʔϧόοΫ ԼهͲͪΒϑΝΠϧΛಡΈࠐΈग़ྗ͍ͯ͠·͢ɻϑΝΠϧͷಡΈࠐΈʹfs.readFileSyncΛར ༻ͨ͠߹ಉظతͳॲཧͱͳΓɺಡΈࠐΈྃ·ͰΠϕϯτϧʔϓΛࢭΊͯ͠·͍·͕͢ɺ fs.readFileΛར༻͢ΔͱඇಉظతͳॲཧͱͳΓɺಡΈࠐΈྃ·ͰͷؒɺଞͷॲཧʹϦιʔεΛ ׂΓͯΔ͜ͱ͕Ͱ͖·͢ɻ // 非同期 … 読み込み中イベントループが停止しない。完了後にコールバック関数が呼び出される const
fs = require(‘fs') fs.readFile(__filename, (err, data) => { console.log(data.toString()) }) // 同期 … ファイル読み込み中イベントループが停止する const fs = require(‘fs') const data = fs.readFileSync(__filename).toString() console.log(data) ! 24 / 53
ίʔϧόοΫͷ׳ྫ ίʔϧόοΫؔجຊతʹෳճݺͼग़͞ΕΔ͜ͱ͋Γ·ͤΜɻྫ֎͋Γ·͕͢ɺඇ ಉظॲཧͷྃޙʹҰ͚ͩݺͼग़͞Ε·͢ɻͦͯ͠ݺͼग़͞ΕͨίʔϧόοΫؔͷୈҰ Ҿʹɺॲཧ͕ޭ͔ͨ͠Ͳ͏͔Λද͢ΤϥʔΦϒδΣΫτ͕ฦΓ·͢ɻ ίʔϧόοΫύλʔϯͷ׳ྫ "1*ͷ࠷ޙͷҾ͕ίʔϧόοΫؔ fs.readFile(path[, options], callback) ॲཧͷྃޙʹίʔϧόοΫ͕ؔҰ͚ͩݺͼग़͞ΕΔ
ݺͼग़͞ΕͨίʔϧόοΫؔͷୈҰҾ͕ඇಉظॲཧͷࣦഊΛද͢ΤϥʔΦϒδΣΫτ fs.readFile(__filename, (err, data) => { console.log(data.toString()) }) ! 25 / 53
ίʔϧόοΫͷΤϥʔϋϯυϦϯά ίʔϧόοΫؔͷୈҰҾ͕ΤϥʔΦϒδΣΫτͰ͢ɻΤϥʔϋϯυϦϯάୈҰҾ ͷΤϥʔΦϒδΣΫτͷOVMMνΣοΫΛߦ͍ɺOVMMͰͳ͍߹ΤϥʔΛॲཧͯ͘͠ ͍ͩ͞ɻ const fs = require('fs') fs.readFile(__filename, (err,
data) => { if (err) { console.error(err) return } console.log(data) }) Τϥʔͷதʹແࢹ͢ΔʢʹϋϯυϦϯά ͠ͳ͍ʣ͜ͱͰϓϩηε͕Ϋϥογϡͯ͠ ͠·͏ͷଘࡏ͠·͕͢ɺίʔϧόοΫ ୈҰҾͷΤϥʔແࢹͯ͠ϓϩηε͕ Ϋϥογϡ͢Δ͜ͱ͋Γ·ͤΜɻ ! 26 / 53
ίʔϧόοΫͷΑ͋͘Δࣦഊྫ returnͷॻ͖Ε // 誤 const fs = require('fs') fs.readFile(__filename, (err,
data) => { if (err) console.error(err) console.log(data) }) // 正 const fs = require('fs'); fs.readFile(__filename, (err, data) => { if (err) return console.error(err) console.log(data) }) ! 27 / 53 ҟৗܥͷॲཧͷ͋ͱਖ਼ৗܥͷॲཧ ͬͯ͠·͍·͢ɻ
ίʔϧόοΫͷΑ͋͘Δࣦഊྫ try/catchΛͬͯඇಉظॲཧͷΤϥʔΛั·͑Δ // 誤 const fs = require('fs') try {
fs.readFile(__filename, (err, data) => { console.log(data) }) } catch (err) { console.error(err) } // 正 const fs = require('fs') fs.readFile(__filename, (err, data) => { if (err) return console.error(err) console.log(data) }) ͨͩ͠ඇಉظॲཧͷલஈ֊ͷΤϥʔ͜ͷtry/catchʹΑͬͯิͰ͖·͢ɻ ͦͷͨΊ͜ͷɹ try/catchݫີʹඞཁͱݴ͑Δ͜ͱʹҙ͍ͯͩ͘͠͞ɻ ! 28 / 53
ίʔϧόοΫͷΑ͋͘Δࣦഊྫ ඇಉظॲཧͷಉظతͳϧʔϓ // 誤 const fs = require('fs') for (let
i = 0; i < 100; i++) { fs.appendFile('./data.txt', i + ',', (err) => { }) } // 0,3,4,5,6,7,8,9,10,11,12,20,21,1,2,28,3,4,5,6,7,8... // 再帰処理による対処の一例(必ずしも正解というわけではありません) const write = (i) => { if (i === 100) return fs.appendFile('./data.txt', i + ',', (err) => { write(++i) }) } write(0) 0-99ͷΛॱʹϑΝΠϧʹॻ͖ࠐΉ͜ͱΛҙ ਤͯ͠ϧʔϓ͍ͯ͠·͕͢ɺ࣮ࡍʮ΄΅ಉ࣌ʹ 0-99ͷΛϑΝΠϧʹॻ͖ࠐΉʯॲཧʹͳͬ ͍ͯ·͢ɻ͜ͷͨΊ݁Ռॱෆಉͳͷฒͼʹ ͳΓ·͢ɻ ! 29 / 53
σβΠϯύλʔϯ›Πϕϯτۦಈ
Πϕϯτۦಈ ඇಉظॲཧͱͷੑ͕ߴ͍͏ͻͱͭͷσβΠϯύ λʔϯ͕ΠϕϯτۦಈͰ͢ɻ/PEFKTͷΠϕϯτۦ ಈύλʔϯEventEmitterͱ͍͏جఈΫϥεΛ ҙͷΦϒδΣΫτʹܧঝͤ͞Δ͜ͱͰ࣮͠·͢ɻ const Redis = require('ioredis') const
redis = new Redis() const stream = redis.scanStream({ match: '*', count: 100 }) // 約100件のキーを読み込むごとに呼び出される stream.on('data', (keys) => { for (const key of keys) { console.log(key) } }) // 全てのキーを走査した後に呼び出される stream.on('end', () => { console.log(‘end') }) ,74ʹଓͯ͠ΩʔͷҰཡΛྻڍ͢ΔΠϕϯτۦಈܕͷίʔυ EventEmitter Λܧঝͨ͠ ΠϕϯτۦಈܕͷΦϒδΣΫτ ίʔϧόοΫͱͷҧ͍ ॲཧͷྃʹݶΒͣɺॲཧͷ్தɾ։࢝ɾऴྃͳͲɺ ঢ়ଶͷมԽΛද༷͢ʑͳλΠϛϯάͰॲཧΛڬΈࠐΉ͜ͱ͕Ͱ͖Δ ঢ়ଶͷมԽΛද͢ʮΠϕϯτʯԿ܁Γฦ͠ൃੜ͠ɺ ͦͷʹରԠ͢ΔϦεφʔ͕ؔݺͼग़͞ΕΔ ,74ʹ͑Εͳ͍ྔͷΩʔ͕ଘࡏ͍ͯͨ͠ͱͯ͠ɺ݅୯ҐͰॲཧ ͍ͯ͠ΔͨΊɺϝϞϦΛѹഭ͢Δ͜ͱͳ͘ɺΠϕϯτϧʔϓΛ࣌ؒఀࢭ͞ ͤΔ͜ͱ͋Γ·ͤΜɻ ! 31 / 53
ΠϕϯτۦಈͷΤϥʔϋϯυϦϯά ΠϕϯτۦಈܕͷΠϯλʔϑΣʔεΛ࣋ͬͨΦϒδΣ ΫτͷΤϥʔΠϕϯτʹϦεφʔؔΛՃ͠·͢ɻ const Redis = require('ioredis') const redis =
new Redis() const stream = redis.scanStream({ match: '*', count: 100 }) // 約100件のキーを読み込むごとに呼び出される stream.on('data', (keys) => { for (const key of keys) { console.log(key) } }) // 全てのキーを走査した後に呼び出される stream.on('end', () => { console.log(‘end') }) // 何かしらエラーが発生した時に呼び出される stream.on('error', (err) => { console.error(err) }) ΠϕϯτۦಈܕͷΦϒδΣΫτΛݟ͚Δώϯτ ˞ඞཱͣ͢͠Δ݅Ͱ͋Γ·ͤΜ υΩϡϝϯτʹൃੜ͢ΔΠϕϯτ͕هࡌ͞Ε͍ͯΔ .onϝιου͕ଘࡏ͢Δ streamͱ͍͏໊শ͕ΘΕ͍ͯΔ ΦϒδΣΫτ͕Πϕϯτۦಈܕ͔Ͳ͏͔ɺओʹυΩϡϝϯτ͔Βஅ͠· ͢ɻͦͯ͠ΠϕϯτۦಈܕͷΠϯλʔϑΣʔεͰ͋ͬͨ߹on(error) ΛͬͯΤϥʔॲཧΛՃ͍ͯͩ͘͠͞ɻ emitter.on('error', (err) => { console.error(err) }) ! 32 / 53
ΠϕϯτۦಈͷΑ͋͘Δࣦഊྫ on('error')ͷϋϯυϦϯά࿙ΕͱͦΕʹ͏ϓϩηεͷΫϥογϡ // 誤 const fs = require('fs') const rs
= fs.createReadStream(__filename) rs.on('data', (data) => { console.log(data) }) // 正 const fs = require('fs') const rs = fs.createReadStream(__filename) rs.on('data', (data) => { console.log(data) }) rs.on('error', (err) => { console.error(err) }) ΠϕϯτۦಈܕͷΤϥʔϋϯυϦϯά୭͕Ε͕ͪͰ͢ɻϋϯυϦϯάΛΕΔͱΤϥʔ ൃੜ࣌ʹϓϩηε͕Ϋϥογϡͯ͠͠·͏ͨΊɺࡉ৺ͷҙΛ͏ඞཁ͕͋Γ·͢ɻ ! 33 / 53
ಉظॲཧ
ಉظॲཧͱඇಉظॲཧΛݟ͚Δʹʁ const data = Buffer.alloc(1024 * 1024 * 1024) data.forEach((value)
=> { console.log(value) }) ͜Ε·Ͱඇಉظॲཧʹదͨ͠σβΠϯύλʔϯͱɺͦΕʹରԠ͢ΔΤϥʔϋϯυϦϯάΛղઆ ͠·͕ͨ͠ɺ࠷ޙʹಉظॲཧʹ͍ͭͯհ͠·͢ɻ·ͣಉظॲཧͱඇಉظॲཧΛݟ͚Δํ๏ Ͱ͕͢ɺද໘తͳใ͔Β࣮֬ʹஅ͢Δํ๏͋Γ·ͤΜɻͰ͕͢ҎԼʹώϯτͱͳΔใ Λྻڍ͠·͢ɻ ඇಉظॲཧΛݟ͚Δώϯτ˞ඞཱͣ͢͠Δ݅Ͱ͋Γ·ͤΜ ωοτϫʔΫ·ͨϑΝΠϧΛѻ͏ "1*ͷ࠷ޙͷҾ͕callbackͰ͋Γɺ"1*ͷ໊শʹSync͕͍͍ͯͳ͍ 1SPNJTFΦϒδΣΫτΛฦ͢ ! 35 / 53 ίʔϧόοΫؔΛड͚औΔ"1*Ͱ͕͢ ಉظॲཧͰ͢ɻίʔϧόοΫʹඇಉظॲ ཧͱ͍͏Θ͚Ͱ͋Γ·ͤΜ
ಉظॲཧͷΤϥʔϋϯυϦϯά ಉظॲཧ্͔ΒॱʹίʔυΛ࣮ߦͯ͠ɺ࣮ߦதͷॲཧ͕ྃ͢Δ·Ͱ࣍ͷॲཧͷ։࢝ ΛϒϩοΫ͢ΔҰൠతͰײతͳૢ࡞Ͱ͢ɻ͜ͷಉظॲཧͷΤϥʔϋϯυϦϯάɺಉ ظॲཧΛtry/catchͰғ͏͜ͱʹΑͬͯߦ͍·͢ɻ try { // JSON.parseの例外処理は特に忘れがちなので注意してください const data
= JSON.parse('invalid_json') } catch (err) { console.error(err) } try { const data = fs.readFileSync('invalid_path') } catch (err) { console.error(err) } fs.readFileSyncthrownewError()try/ catchΛͬͯΤϥʔΛॲཧ͠·͢ɻಉظॲཧͷΤϥʔ ϋϯυϦϯά͕࿙Ε͍ͯΔͱϓϩηε͕Ϋϥογϡ͢Δͨ Ίɺेʹҙ͍ͯͩ͘͠͞ɻ ! 36 / 53
νΣοΫϙΠϯτ ‣ /PEFKT-54όʔδϣϯΛར༻͢Δ ‣ Ϟδϡʔϧͷར༻ͱཧํ๏Λཧղ͢Δ ‣ ඇಉظॲཧΛۦͯ͠Πϕϯτϧʔϓͷఀࢭ࣌ؒΛ࠷খݶʹ͑Δ ‣ ίʔϧόοΫͱΠϕϯτۦಈͷσβΠϯΛཧղ͢Δ ‣
ίʔϧόοΫͱΠϕϯτۦಈͷΤϥʔϋϯυϦϯάํ๏Λཧղ͢Δ ‣ ಉظॲཧͷΤϥʔϋϯυϦϯάํ๏Λཧղ͢Δ ઃܭύλʔϯ ΤϥʔϋϯυϦϯά Ϋϥογϡ ඇಉظॲཧ $BMMCBDL if (err) &WFOU&NJUUFS emitter.on(‘error') ✔ ಉظॲཧ try/catch ✔ ! 37 / 53
ϑϩʔ੍ޚ
ϑϩʔ੍ޚ app.get(‘/upload', (req, res) => { // 1. データベースに問い合わせてユーザー情報を取得する非同期処理 //
2. オブジェクトストレージにファイルをアップロードする非同期処理 // 3. データベースにメタ情報を保存する非同期処理 res.status(200).end(data) } 8FC"1*ͷ։ൃͰԼهͷΑ͏ʹྻͷॲཧʢલͷॲཧ͕ऴ͔ྃͯ͠Β࣍ͷॲཧΛߦ͏ʣΛه ड़͢Δ͜ͱ͕΄ͱΜͲͰ͕͢ɺඇಉظॲཧͱྻॲཧͷ૬ੑ࠷ѱͰ͢ɻ͔͠͠ݱࡏͰ ྻॲཧͷهड़Λվળ͢ΔݴޠϨϕϧͷ༷͕උΘ͍ͬͯ·͢ɻ ! 39 / 53
ϑϩʔ੍ޚֶशͷྲྀΕ ֶशॱ ઃܭύλʔϯ ޓੑ ϑϩʔ੍ޚ ετϦʔϜॲཧ هड़ྔ $BMMCBDL ✔
&WFOU&NJUUFS ✔ 1SPNJTF ✔ ✔ BTZODBXBJU ✔ ✔ ✔ جૅͷσβΠϯύλʔϯʹΑΔϑϩʔ੍ޚΛɺΑΓ্Ґͷϑϩʔ੍ޚʹม͢Δ͜ͱͰֶशΛਐ Ί͍͖ͯ·͢ɻࠓճதؒͰ͋ΔPromiseΛεΩοϓͯ͠ɺ࠷ऴతͳணͰ͋Δasync/ awaitΛղઆ͠·͢ɻ ! 40 / 53 ֤ઃܭύλʔϯͷ্ҐޓͰ͋Δasync/awaitΛղઆ͠·͢ɻ
ίʔϧόοΫʹΑΔϑϩʔ੍ޚ ίʔϧόοΫΛͬͨϑϩʔ੍ޚ༰қʹཧղͰ͖ΔγϯϓϧͳΈͰ͋Γ·͢ ͕ɺॲཧͷ༰࣍ୈͰਂ͍ωετͱ࠶ىॲཧʹΑΓɺෳࡶ͕͞૿͠ՄಡੑͷѱԽͱه ड़ྔͷංେԽʹܨ͕Γ·͢ɻ // 再帰処理による非同期処理のループ const fs = require('fs')
const write = (i) => { if (i === 100) return fs.appendFile('./data.txt', `${i},`, (err) => { write(++i) }) } write(0) ϑΝΠϧͷॻ͖ࠐΈ͕ྃͨ͋͠ͱ࣍ͷॲཧΛ։࢝͢Δ ͱ͍͏ྻॲཧͰ͕͢ɺඇಉظॲཧͷͨΊϑΝΠϧॻ͖ࠐ ΈྃͷίʔϧόοΫΛىʹ࠶ؼॲཧ͍ͯ͠·͢ɻ ! 41 / 53
ϑϩʔ੍ޚ›ඇಉظؔ
BTZODBXBJU const fs = require('fs').promises const main = async ()
=> { for (let i = 0; i < 100; i++) { await fs.appendFile('./data.txt', `${i},`) } } main() const fs = require('fs') const write = (i) => { if (i === 100) return fs.appendFile('./data.txt', `${i},`, (err) => { write(++i) }) } write(0) ίʔϧόοΫͷ࠶ؼॲཧΛasync/awaitʹม͠·͢ɻasync/awaitʹΑͬͯίʔ υελΠϧҰൠతͳಉظॲཧʹ͍ۙߏʹมԽ͠·͢ɻͰ͕͢ඇಉظॲཧͷϝϦοτ ଛͳΘΕ͓ͯΒͣɺॲཧͷ࣮ߦதଞͷॲཧʹϦιʔεΛׂΓͯΔ͜ͱ͕Ͱ͖·͢ɻ $BMMCBDL BTZODBXBJU const data = await func()ͷΑ͏ʹඇ ಉظॲཧͷฦΓΛड͚औΔ͜ͱͰ͖·͢ɻ ! 43 / 53
BTZODBXBJU const fs = require('fs').promises const main = async ()
=> { for (let i = 0; i < 100; i++) { await fs.appendFile('./data.txt', `${i},`) } } main() asyncfunctionએݴʹΑͬͯඇಉظؔʢ"TZOD'VOUJPOʣΛఆٛ͠·͢ʢ⁞ʣɻඇಉ ظؔͷ෦ͰawaitʹΑͬͯඇಉظॲཧͷྃΛػͰ͖·͢ʢ ʣɻ Promise4USVDUVSFEͳίʔϧόοΫͰ͢ɻ /PEFKTͷҰ෦ͷඪ४Ϟδϡʔϧ.promises Λ༩͢Δ͜ͱͰίʔϧόοΫͱಉ໊͡લͷ 1SPNJTF"1*Λฦ͠·͢ʢʣɻ ௨ৗͷίʔϧόοΫ"1*ͰawaitʹΑͬͯॲཧͷྃΛػͤ͞Δ͜ͱ͕Ͱ͖·ͤΜɻ awaitʹ͢ඇಉظॲཧಛఆͷϧʔϧʹैͬͨΦϒδΣΫτͰ͋Δඞཁ͕͋Γ·͢ɻ ⁞ ! 44 / 53
ԼهίʔϧόοΫύλʔϯͷ࠶ؼॲཧΛasync/awaitΛͬͨॲཧʹม͍ͯͩ͘͠͞ɻ ԋश const fs = require('fs') const write =
(i) => { if (i === 100) return fs.appendFile('./data.txt', `${i},`, (err) => { write(++i) }) } write(0) ͜ͷࢿྉͷϦϯΫ https://speakerdeck.com/ajido/minimum-handson-nodejs ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣ bit.ly/2XWSQQK εΫϦϓτϦϯΫ https://github.com/ajido/nodejs-handson ! 45 / 53
Πϕϯτۦಈύλʔϯͷϑϩʔ੍ޚ try { for await (const keys of stream) {
for (const key of keys) { console.log(key) } } } catch (err) { console.error(err) } ΠϕϯτۦಈܕͷॲཧforawaitߏจʹΑΓ "TZOD'VODUJPOͷϑϩʔ੍ޚԼʹΈࠐΉ͜ ͱ͕Ͱ͖·͢ɻ const Redis = require('ioredis') const redis = new Redis() const stream = redis.scanStream({ match: '*', count: 100 }) // 約100件のキーを読み込むごとに呼び出される stream.on('data', (keys) => { for (const key of keys) { console.log(key) } }) // 全てのキーを走査した後に呼び出される stream.on('end', () => { console.log(‘end') }) // 何かしらエラーが発生した時に呼び出される stream.on('error', (err) => { console.error(err) }) ίʔϧόοΫ͕PromiseʹΑͬͯߏԽ͞Ε͍ͯͨΑ͏ ʹɺΠϕϯτۦಈܕͷॲཧstream.ReadableʹΑͬͯ ߏԽ͞Ε͍ͯΔඞཁ͕͋Γ·͢ɻ ! 46 / 53
ԼهΠϕϯτۦಈύλʔϯͷίʔυΛforawaitΛͬͨॲཧʹม͍ͯͩ͘͠͞ɻ ԋश const fs = require('fs') const rs =
fs.createReadStream(__filename) rs.on('data', (data) => { console.log(data.toString()) }) rs.on('error', (err) => { console.error(err) }) ͜ͷࢿྉͷϦϯΫ https://speakerdeck.com/ajido/minimum-handson-nodejs ԋशϦϯΫ https://chouseisan.com/s?h=4a0d7eb9c38a440e9ad585abfbb16e79 ‣ bit.ly/2XWSQQK εΫϦϓτϦϯΫ https://github.com/ajido/nodejs-handson ! 47 / 53
BTZODBXBJUͷΤϥʔϋϯυϦϯά "TZOD'VODUJPOͷଆͰtry/catchΛʢ⁞ʣɺ"TZOD'VODUJPOͷ֎ଆͰ .catchΛͬͯΤϥʔΛॲཧ͍ͯͩ͘͠͞ʢ ʣɻ const fs = require('fs').promises const main =
async () => { for (let i = 0; i < 100; i++) { try { await fs.appendFile('./data.txt', `${i},`) } catch (err) { console.error(err) } } } main().catch((err) => { console.error(err) }) ⁞ "TZOD'VODUJPOͷ෦ͰΤϥʔ͕ൃੜ͢ ΔͱɺҎ߱ͷॲཧ࣮ߦ͞Εͣ.catchʹ δϟϯϓ͠·͢ɻ ͨͩ͠"TZOD'VODUJPO෦ͷΤϥʔൃੜ ෦͕try/catchͰแ·Ε͍ͯΔ߹ɺ try/catchʹัଊ͞Ε.catchʹಧ͖· ͤΜɻ͜ͷ߹try/catchΛൈ͚ͨޙ "TZOD'VODUJPOͷॲཧܧଓ͞Ε·͢ɻ ! 48 / 53
BTZODBXBJUͷΑ͋͘Δࣦഊྫ ⁞awaitͷॻ͖Ε ෆཁͳPromiseͷར༻ .catchͷॻ͖ΕʢΤϥʔϋϯυϦϯάͷهड़࿙Εʣ const fs = require('fs').promises const main
= async () => { for (let i = 0; i < 100; i++) { const stat = fs.appendFile('./data.txt', `${i},`).then(() => { return fs.stat(‘./data.txt’) }) // await fs.appendFile('./data.txt', `${i},`) console.log(stat) // const stat = await fs.stat('./data.txt') } return Promise.resolve(‘done') // return 'done' } main().then((result) => console.log(result)) // .catch((err) => console.error(err)) ⁞ ! 49 / 53
BTZODBXBJUΛͬͨแׅతͳΤϥʔϋϯυϦϯά BTZODBXBJU ݫີʹ1SPNJTF try/catchͷׂΛ݉Ͷἧ͍͑ͯ·͢ɻԼهίʔυͰ "TZOD'VODUJPOͷଆͰൃੜ͢ΔಉظॲཧͷΤϥʔΛ.catchʹٵऩ͍ͤͯ͞·͢ɻॲཧΛ͢ ͯasync/awaitڥԼʹ࣮͢Δ͜ͱͰɺඇಉظɾಉظॲཧΛΘͣɺแׅతʹΤϥʔΛॲཧ Ͱ͖·͢ɻ const main =
async () => { JSON.parse('invalid_json') } main().catch((err) => { console.error(err) }) // SyntaxError: // Unexpected token b in JSON at position 0 // at JSON.parse (<anonymous>) try/catchͷهड़࿙ΕʹΑΔϓϩηεμϯΛ͗·͢ɻͯ͢ͷ έʔεʹ͓͍ͯasync/awaitΛར༻͢Δͱ͍͏ϧʔϧҰݟۃ ʹࢥ͑Δ͔͠Ε·ͤΜ͕ɺՄಡੑͷ໘Ͱ҆શੑͷ໘Ͱ͓͢͢Ί Ͱ͖Δ༏Εͨํ๏Ͱ͢ɻ ! 50 / 53
νΣοΫϙΠϯτ ‣ BTZODBXBJUͷѻ͍ํΛཧղ͢Δ ‣ BTZODBXBJUͷΤϥʔϋϯυϦϯάํ๏Λཧղ͢Δ ‣ Մಡੑͱ҆શੑΛߟྀ͠ɺՄೳͳݶΓBTZODBXBJUϑΝʔετͷઃܭΛ৺ֻ͚Δ ઃܭύλʔϯ ΤϥʔϋϯυϦϯά Ϋϥογϡ
ඇಉظॲཧ $BMMCBDL if (err) &WFOU&NJUUFS emitter.on(‘error') ✔ BTZODBXBJU try/catch .catch() ಉظॲཧ try/catch BTZODBXBJU ✔ ! 51 / 53
جૅ Ԡ༻ ‣ Πϯετʔϧ 5 ‣ ϑϩʔ੍ޚ 38 ‣ Ϟδϡʔϧཧ
11 ‣ ඇಉظؔ 42 ‣ ಛ 16 ‣ σόοά ‣ σβΠϯύλʔϯ 21 ‣ Ϟδϡʔϧͷ࡞ ‣ ίʔϧόοΫ 23 ‣ ϓϩϑΝΠϦϯά ‣ Πϕϯτۦಈ 31 ‣ ϑϨʔϜϫʔΫͱπʔϧ ‣ ಉظॲཧ 35
͓࣌ؒർΕ༷Ͱͨ͠ɻ Photo by Paul Hanaoka on Unsplash