Callback to Promise and beyond

Callback to Promise and beyond

Fb10d67e7828952bf7b6d1cef477425a?s=128

Daiki Kuriyama

February 01, 2019
Tweet

Transcript

  1. $BMMCBDLUP1SPNJTFBOECFZPOE d1SPNJTFԽ͚ͩͰ͸ऴΘΒͳ͍d ೥݄೔ؔ੢/PEFֶԂ࣌ݶ໨ Ϡϑʔגࣜձࣾɹ܀ࢁଠر

  2. ࣗݾ঺հ ܀ࢁଠرʢ!"KJEPʣ Ϡϑʔגࣜձࣾ›/PEFKTࠇଳ

  3. w $BMMCBDLΛ1SPNJTFԽ͢Δํ๏ w $BMMCBDLΛ1SPNJTFԽͨ͠ޙʹ࢒Δ՝୊ w ੑೳ›ݱ୅తͳϑϩʔ੍ޚ͸ߴ଎ͳͷ͔ʁ w ετϦʔϜରԠ›4USFBNΛϑϩʔ੍ޚʹͲ͏૊ΈࠐΉʁ w Τϥʔॲཧ›ඇಉظॲཧͷελοΫτϨʔε͸Ͳ͏ݟ͑Δʁ

    ಺༰
  4. /PEFKTʹ͓͚Δඇಉظॲཧͱϑϩʔ੍ޚͷྺ࢙ "TZODUZQF /PEFWFSTJPO  $BMMCBDL  3FNPWFQSPNJTFT W  BTZOD

    OQN  CMVFCJSE OQN 2 OQN  1SPNJTF" W 7  (FOFSBUPS W 7  "TZOD'VODUJPOT BTZODBXBJU W 7  "TZOD*UFSBUJPO GPSBXBJUPG &YQFSJNFOUBM
  5. BTZODBXBJUʹΑͬͯඇಉظॲཧͷϑϩʔ੍ޚ͸༰қʹͳ͕ͬͨɺ$BMMCBDLܕͷϝ ιου͸1SPNJTFʹม׵͠ͳ͚Ε͹ϑϩʔ੍ޚʹ૊ΈࠐΉ͜ͱ͕Ͱ͖ͳ͍ɻ1SPNJTF ʹରԠ͍ͯ͠ͳ͍ɺϑϩʔ੍ޚʹ૊Έࠐ·ΕΔͰ͋Ζ͏Ϟδϡʔϧ͸ҎԼͷ͍ͣΕ͔ͷ બ୒ΛഭΒΕͨɻ $BMMCBDLΛݱ୅తͳϑϩʔ੍ޚʹରԠͤ͞Δ  $BMMCBDLͷ··ܧଓ͢Δʢ1SPNJTFม׵͸ར༻ऀʹ೚ͤΔʣ  1SPNJTFʹ੾Γସ͑ɺޓ׵ੑΛࣺͯΔ 

    $BMMCBDLͱ1SPNJTFͷΠϯλʔϑΣʔεΛཱ྆ͤ͞Δ બ୒
  6. $BMMCBDLͱ1SPNJTFͷΠϯλʔϑΣʔεΛཱ྆ͤ͞Δ  $BMMCBDLΛলུͨ࣌͠ʹ1SPNJTFΛฦ͢  1SPNJTFઐ༻ͷΠϯλʔϑΣʔεΛ௥Ճ͢Δ  ‣ 1SPNJTFܕͷϞδϡʔϧΛฦ͢  ‣

    ϝιουνΣʔϯ͔Β1SPNJTFΛฦ͢  ‣ 4VGpY෇͖ͷؔ਺͔Β1SPNJTFΛฦ͢ Ϟδϡʔϧ಺Ͱ$BMMCBDLͱ1SPNJTFͷΠϯλʔϑΣʔεΛཱ྆ͤ͞Δํ๏ʹ͸͍ͭ͘ ͔ͷબ୒ࢶ͕͋ΓɺͦΕͧΕʹϝϦοτͱσϝϦοτ͕ଘࡏ͢Δɻ
  7. $BMMCBDLͱ1SPNJTFͷཱ྆ $BMMCBDLΛলུͨ࣌͠ʹ1SPNJTF͕ฦΔ // Callback func((data) => { console.log(data) }) //

    Promise const data = await func() console.log(data) ϚʔέοτΛௐࠪ͢ΔݶΓ͜ͷελΠϧͷ࠾༻ྫ͸ଟ͘ɺ+BWB4DSJQUͷจԽΛݟͯ΋ ύϥϝʔλΛলུͯ͠ڍಈ͕มΘΔ࢓૊Έ͸ଟ͘ଘࡏ͍ͯ͠Δɻ ϝιου͝ͱͷஈ֊తͳ1SPNJTFԽ͕ՄೳͰɺকདྷతͳ$BMMCBDLͷഇࢭ΋ࢹ໺ʹೖ Ε΍͍͢ɻͨͩ͠TFU5JNFPVU΍DIJME@QSPDFTTFYFDͷΑ͏ͳίʔϧόοΫؔ ਺Λड͚औΓɺಉ࣌ʹฦΓ஋΋ଘࡏ͢Δؔ਺ͱ͸૬ੑ͕ѱ͍ͨΊ஫ҙ͕ඞཁɻ
  8. $BMMCBDLͱ1SPNJTFͷཱ྆ 1SPNJTFܕͷϞδϡʔϧΛฦ͢ // Callback const fs = require('fs') fs.readFile('/etc/hosts', (err,

    data) => { console.log(data) }) // Promise const fs = require('fs').promises const data = await fs.readFile('/etc/hosts') console.log(data) /PEFKTͷຊମ͕࠾༻͍ͯ͠Δํ๏ɻ͢΂ͯͷϝιουΛҰׅͰ1SPNJTFԽͰ͖Δͱ ͍͏ར఺͕͋Γɺ·ͨϞδϡʔϧͷ։ൃऀࢹ఺Ͱ͸طଘͷ$BMMCBDLؔ਺ʹखΛՃ͑Δ ඞཁ͕ͳ͍ͱ͍͏ར఺΋͋Δɻ ͔͠͠Ϟδϡʔϧ಺ʹଘࡏ͢Δ͢΂ͯͷཁૉΛෳ੡ͯ͠վम͢Δඞཁ͕͋ΔͨΊɺରԠ ͷίετ͸վम࣌ʹूத͢Δɻ
  9. $BMMCBDLͱ1SPNJTFͷཱ྆ ϝιουνΣʔϯ͔Β1SPNJTFΛฦ͢ // Callback func((data) => { console.log(data) }) //

    Promise const data = await func().promise() console.log(data) "844%,GPS+BWB4DSJQUͳͲ͕࠾༻͍ͯ͠Δํ๏ɻ1SPNJTFʹݶΒͣɺ4USFBN ͷΑ͏ͳෳ਺ύλʔϯͷΠϯλʔϑΣʔεΛ໌ࣔతʹࢦఆͯ͠ฦ͢͜ͱ΋Ͱ͖Δɻ طଘͷ$BMMCBDLؔ਺ʹखΛՃ͑Δඞཁ͕ͳ͍ͱ͍͏ར఺͕͋ΓɺϞδϡʔϧ಺ͷϝιο υΛ෦෼తʹ1SPNJTFରԠ͍ͯ͘͜͠ͱ΋Ͱ͖Δ͕ɺকདྷతͳ$BMMCBDLͷഇࢭΛࢹ ໺ʹೖΕΔ৔߹͸ѻ͍͕೉͍͠ɻ
  10. $BMMCBDLͱ1SPNJTFͷཱ྆ 4VGpY෇͖ͷؔ਺͔Β1SPNJTFΛฦ͢ // Callback func((data) => { console.log(data) }) //

    Promise const data = await funcAsync() console.log(data) VUJMQSPNJTJGZ΍CMVFCJSEQSPNJTJGZ"MMͳͲΛར༻͢Δ͜ͱʹΑͬͯɺ࠷খݶ ͷίετͰϞδϡʔϧ಺ͷϝιουΛ1SPNJTFʹରԠ͢Δ͜ͱ͕Ͱ͖Δɻ কདྷతͳ$BMMCBDLͷഇࢭΛߟ͑Δ৔߹ɺޓ׵ੑʹͲ͏ରॲ͢Δ͔͕೰·͍͠ɻ4VGpYΛ ҡ࣋͢Δ͔ɺ·ͨ͸4VGpYΛআڈͯ͠1SPNJTFͷར༻ऀʹෛՙΛ༩͑Δ͔ͷબ୒͕ඞཁɻ
  11. ֤ύλʔϯͷ۩ମతͳ࣮૷ํ๏͸ϒϩάͷهࣄ಺ʹɻ͓͢͢Ί͸ஈ֊తͳ1SPNJTFԽͱ $BMMCBDLͷഇࢭΛࢹ໺ʹೖΕ΍͍͢ʮ$BMMCBDLΛলུͨ࣌͠ʹ1SPNJTFΛฦ͢ʯํ๏ɻ $BMMCBDLͱ1SPNJTFͷΠϯλʔϑΣʔεΛཱ྆ͤ͞Δ  $BMMCBDLΛলུͨ࣌͠ʹ1SPNJTFΛฦ͢  1SPNJTFઐ༻ͷΠϯλʔϑΣʔεΛ௥Ճ͢Δ  ‣ 1SPNJTFܕͷϞδϡʔϧΛฦ͢

     ‣ ϝιουνΣʔϯ͔Β1SPNJTFΛฦ͢  ‣ 4VGpY෇͖ͷؔ਺͔Β1SPNJTFΛฦ͢ ݸਓత͓͢͢Ί
  12. ੑೳ ݱ୅తͳϑϩʔ੍ޚ͸ߴ଎ͳͷ͔ʁ

  13. ݱ୅తͳϑϩʔ੍ޚ͸ߴ଎ͳͷ͔ʁ %PY#FFϕϯνʔϚʔΫͰ/PEFW؀ڥͷ$BMMCBDLͱ1SPNJTFɺBTZOD BXBJUͷύϑΥʔϚϯεΛܭଌ‎ݱ࣌఺Ͱ͸$BMMCBDL͕࠷଎ εϧʔϓοτΛՄࢹԽ͍ͯ͠ΔͨΊ௿͚Ε͹௿͍ ΄ͲύϑΥʔϚϯε͕ߴ͍͜ͱΛද͢ɻ $BMMCBDL͸ଞͷඇಉظॲཧʹൺ΂ͯഒҎ্ͷύ ϑΥʔϚϯεΛୟ͖ग़͍ͯ͠Δɻແ৚݅ʹ͢΂ͯ ͷ$BMMCBDLΛ๾໓ͯ͠͸͍͚ͳ͍ɻ ϕϯνϚʔΫͷৄࡉ͸ԼهϦϙδτϦʹ IUUQTHJUIVCDPN"KJEPXIJDIJTUIF

    GBTUFTUBTZODQBUUFSO
  14. BTZODBXBJU͸1SPNJTFΑΓ΋଎͘ͳΔ ࠷৽ͷ؀ڥͰ֤ඇಉظॲཧͷύϑΥʔϚϯεΛܭଌɻ7Ҏ্Ͱ͸BXBJUͷ࢓༷ม ߋΛ൐͏࠷దԽ͕ߦΘΕɺBTZODBXBJU͸1SPNJTFΑΓ΋ߴ଎ʹɻ /PEFWʹೖΔ͔΋ɻ Ϟδϡʔϧͷ಺෦Ͱ΋BTZODBXBJUΛར༻͠ ͯ1SPNJTFͷΠϯλʔϑΣʔεΛ࣮૷͢Δͱ͍ ͏ํ๏͕ΑΓ༗ޮʹͳΔɻ ͦͷ৔߹ɺࠓ೥݄ʹ&0-ͱͳΔ/PEFW؀ ڥΛߟྀ͢Δ͔Ͳ͏͔͕য఺ʹɻ IUUQTWEFWCMPHGBTUBTZOD

  15. ݱ୅తͳϑϩʔ੍ޚ͸ߴ଎ͳͷ͔ʁ /PEFKTͷόʔδϣϯ͝ͱʹBTZODBXBJUͷύϑΥʔϚϯεΛܭଌ ‎BTZODBXBJU͸/PEFKTͷόʔδϣϯΞοϓʹ൐͍ܶతʹ଎౓͕޲্͍ͯ͠Δ ࠷దԽʹΑΓͦͷ଎౓͸$BMMCBDLʹഭΓ ͭͭ͋Δɻ 1SPNJTFΑΓ΋BTZODBXBJUΛɻͦ͠ ͯBTZODBXBJUΛ׆༻͢ΔͳΒɺϥϯλ ΠϜͷϝδϟʔόʔδϣϯΞοϓ͸ੵۃత ʹߦͳ͍͖͍ͬͯͨɻ

  16. ετϦʔϜରԠ 4USFBNΛϑϩʔ੍ޚʹͲ͏૊ΈࠐΉʁ

  17. 4USFBNͱϑϩʔ੍ޚ͸૬ੑ͕ѱ͍ ͜Ε·Ͱ4USFBNΛϑϩʔ੍ޚʹ૊ΈࠐΉ৔߹͸ɺ1SPNJTF ͰแΈࠐΈϫϯγϣοτͷΠϯλʔϑΣʔεʹม׵͢Δ͔ɺ ಠࣗʹΠςϨʔγϣϯରԠͤ͞Δͱ͍͏ঢ়گͩͬͨɻ const recv = new Promise((resolve, reject)

    => { let data = '' stream.on('data', (chunk) => { data += chunk }) stream.once('end', () => { return resolve(data) }) stream.once(‘error', (err) => { return reject(err) }) }) const data = await recv() const drain = (stream) => { return new Promise((resolve, reject) => { stream.once('data', (data) => { stream.pause() … resolve(data) }) stream.once('end', () => { … resolve(null) }) stream.once('error', (err) => { … reject(err) }) stream.resume() }) } const main = async () => { const stream = fs.createReadStream(‘file’) let data = null while (data = await drain(stream)) { console.log(data) } } 1SPNJTFͰแΈࠐΉ ϫϯγϣοτม׵ ෳࡶ೉ղͳ ΠςϨʔγϣϯରԠ
  18. 4USFBNͷΤϥʔϋϯυϦϯά͸ಠಛ 4USFBNͷجఈΫϥεͰ͋Δ&WFOU&NJUUFSͷΤϥʔϋϯυϦϯά͸ಠಛͰ͋Γɺͦ ͷϋϯυϦϯά࿙Ε͸ϓϩηεͷΫϥογϡʹ௚݁͢Δɻಛʹ஫ҙ͕ඞཁͳઃܭύλʔ ϯͷͻͱͭɻ ઃܭύλʔϯ ΤϥʔϋϯυϦϯά Ϋϥογϡ ඇಉظॲཧ $BMMCBDL if

    (err) &WFOU&NJUUFS emitter.on(‘error') 1SPNJTF .catch() BTZODBXBJU try..catch  .catch() ಉظॲཧ try..catch 1SPNJTFBTZODBXBJU
  19. "TZOD*UFSBUPSΛ࢖ͬͨ4USFBNͷϑϩʔ੍ޚ stream.on('data', (data) => { console.log(data) }) stream.on('end', () =>

    { console.log('finished') }) stream.on(‘error', (err) => { console.error(err) }) try { for await (const data of stream) { console.log(data) } console.log(‘finished') } catch (err) { console.error(err) } 4USFBN "TZOD*UFSBUPS &4ͷػೳ"TZOD*UFSBUPSΛ׆༻͢Δ͜ͱͰɺ4USFBNΛγʔϜϨεʹϑϩʔ ੍ޚʹ૊ΈࠐΉ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨɻʢ&YQFSJNFOUBM"1*/PEFWʣ
  20. "TZOD*UFSBUPSΛ࢖ͬͨ4USFBNͷϑϩʔ੍ޚ ςΩετϑΝΠϧΛߦ୯ҐͰॲཧͨ͠Γɺ)551ϦΫΤετͷDIVOLΛॲཧ͢Δ৔໘ͳ ͲͰ׆༻Ͱ͖Δɻ౷ҰతͳΤϥʔϋϯυϦϯά͕ඇৗʹັྗతɻ http.createServer(async (req, res) => { try {

    let body = '' req.setEncoding('utf8') for await (const chunk of req) { body += chunk } console.log(body) res.end() } catch { res.statusCode = 500 res.end() } }) const main = async () => { const rl = readline.createInterface({ input: fs.createReadStream('input.txt') }) for await (const line of rl) { console.log(line) } } main().catch((err) => { console.error(err) }) ࣍ʹ๾໓͞ΕΔͷ͸4USFBN͔ʁ
  21. Τϥʔॲཧ ඇಉظॲཧͷελοΫτϨʔε͸Ͳ͏ݟ͑Δʁ

  22. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʢʣ ຊདྷελοΫτϨʔε͸σόοάͷॿ͚ʹͳΔ΋ͷ͕ͩɺඇಉظॲཧͷελοΫτϨʔ ε͸໾ʹཱͨͳ͍ɻඇಉظॲཧͷݺͼग़͠ݩ͸ɺඇಉظॲཧͷ։࢝Λ໋ྩͨ͠ίʔυͰ ͸ͳ͘ΠϕϯτϧʔϓͰ͋ΔͨΊɺಠཱͨ͠ελοΫτϨʔε͕දࣔ͞Εͯ͠·͏ɻ const exec = require('child_process').exec const func

    = (cb) => { exec('exit 1', (err) => { cb(err) }) } func((err) => { console.error(err) }) Error: Command failed: exit 1 at ChildProcess.exithandler at ChildProcess.emit at maybeClose at Socket.stream.socket.on at Socket.emit at Pipe._handle.close ࣮ߦ݁Ռ ݺͼग़͠ݩͷGVODؚ͕·Ε͓ͯΒͣ ΤϥʔͷൃੜՕॴ͕ಛఆͰ͖ͳ͍
  23. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʢʣ "TZOD'VODUJPOͷ؀ڥԼͰ͸BXBJUʹΑͬͯελοΫτϨʔε͕෼཭͞ΕΔɻBXBJU Ͱதஅ͞Εͨؔ਺͸ϚΠΫϩλεΫΩϡʔ͔Βॲཧ͕࠶։͞ΕΔͨΊɺલड़ͷ໰୊ͱಉ ༷ʹؔ਺ͷݺͼग़͠ܦ࿏͕ҡ࣋͞Εͣɺ੾Γ཭͞Εͯ͠·͏ɻ const func = async () =>

    { await 'interrupt' throw new Error('error') } const main = async () => { await func() } main().catch((err) => { console.error(err) }) Error: error at func at process._tickCallback at Function.Module.runMain at startup at bootstrapNodeJSCore ࣮ߦ݁Ռ ݺͼग़͠ݩͷNBJOؚ͕·Ε͓ͯΒͣ ΤϥʔͷൃੜՕॴ͕ಛఆͰ͖ͳ͍
  24. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʹରॲ͢Δ લड़ͨ͠ελοΫτϨʔεͷ՝୊͸ҎԼʹྻڍͨ͠ํ๏ʹΑͬͯରॲͰ͖Δɻ ํ๏ ֓ཁ JOTQFDUCSL$ISPNF%FW5PPMT w ༷ʑͳσόοάػೳΛ಺แ w Φʔόʔϔου͋Γʢߴίετʣ BTZOD@IPPLTUSBDFDMBSJGZ

    w ߴ͍Մಡੑͱ࢖͍উखͷྑ͞ w Φʔόʔϔου͋Γ BTZODTUBDLUSBDFT w Φʔόʔϔουͳ͠ w BTZODBXBJUͷ՝୊ͷΈղܾՄೳ
  25. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʹରॲ͢Δ JOTQFDUCSL$ISPNF%FW5PPMT JOTQFDUCSLΦϓγϣ ϯ෇͖Ͱىಈɻ $ISPNF%FW5PPMT͔ Β֬ೝ͢Δɻ ελοΫτϨʔεʹ͸දࣔ͞Εͳ͍ ܦ࿏΋දࣔ͞ΕΔ

  26. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʹରॲ͢Δ BTZOD@IPPLTUSBDFDMBSJGZ USBDFϞδϡʔϧ͸ඪ४ϞδϡʔϧͷBTZOD@IPPLTΛར༻ͯ͠ɺඇಉظॲཧʹಠࣗίʔ υΛࠩ͠ࠐΈελοΫτϨʔεΛ֦ு͢ΔɻDMBSJGZϞδϡʔϧ͸ෆཁͳελοΫτϨʔ εΛআڈͯ͠ελοΫτϨʔεͷՄಡੑΛ޲্ͤ͞Δɻʢݸਓత͓͢͢Ίʣ ❯ node -r trace -r

    clarify exec.js Error: Command failed: exit 1 at func at Object.<anonymous> ࣮ߦ݁Ռ ݺͼग़͠ݩͷGVODؚ͕·Ε ෆཁͳߦ΋࡟আ͞Ε͍ͯΔ const exec = require('child_process').exec const func = (cb) => { exec('exit 1', (err) => { cb(err) }) } func((err) => { console.error(err) })
  27. ඇಉظॲཧ๊͕͑ΔελοΫτϨʔεͷ՝୊ʹରॲ͢Δ BTZODTUBDLUSBDFT 7Ҏ্ͷ؀ڥͰ͜ͷΦϓγϣϯΛ༗ޮʹ͢ΔͱɺBXBJUʹؚ·ΕΔ৘ใΛ࢖ͬͯ ඇಉظॲཧΛލ͍ͩελοΫτϨʔε͕ߏங͞ΕΔΑ͏ʹͳΔɻ෦෼తͳ໰୊ղܾखஈ Ͱ͸͋Δ͕ɺ࣮ߦதͷγεςϜʹෛՙΛ༩͑ͳֵ͍৽తͳػೳɻ const func = async ()

    => { await 'interrupt' throw new Error('error') } const main = async () => { await func() } main().catch((err) => { console.error(err) }) ❯ node --async-stack-traces await.js Error: error at func at process._tickCallback at Function.Module.runMain at startup at bootstrapNodeJSCore at async main ࣮ߦ݁Ռ ݺͼग़͠ݩͷNBJOؚ͕·Ε͍ͯΔ ·ͩϑϥά෇͖ͷػೳɻࠓޙͷϑϥάղআʹظ଴
  28. ϑϩʔ੍ޚͷ࠷దԽ͸$BMMCBDLΛ1SPNJTFʹม͚͑ͨͩͰ͸ ऴΘΒͳ͍ɻকདྷΛݟਾ͑ɺ͞ΒͳΔ࠷దԽΛਐΊΑ͏ʂ ‣ BTZODBXBJU͸վྑ͞Εɺߴ଎Խ͠ଓ͚͍ͯΔ ‣ 1SPNJTFΑΓ΋BTZODBXBJUͷੵۃతͳ׆༻Λ ‣ 4USFBNͷϑϩʔ੍ޚʹର͢Δ࠷దԽ͸ؒۙ ‣ "TZOD*UFSBUPSͷ&YQFSJNFOUBMղআʹظ଴

    ‣ ඇಉظελοΫτϨʔεͷ՝୊͸վળͷஹ͠ΞϦ