[node.js] manier van functie declareren invloed op await

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • CB32
  • Registratie: November 2011
  • Laatst online: 16:25
Ik probeer node.js wat beter te bergrijpen, met name dat code synchronous loopt en niet, zoals ik bijvoorbeeld van PHP gewend ben, regel-per-regel. Nu heb ik door het inlezen van promises, async en await het volgende voorbeeld in elkaar gezet voor mijn eigen begrip. Het doel is simpel: tussen elk van de console.log's een vertraging creeren. Dit gebeurt alleen als ik de functie delayThree gebruik.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Delay functions
function delayOne(ms){
    new Promise(function(resolve){
        setTimeout(resolve, ms)
    })
}

const delayTwo = (ms) => { new Promise(function(resolve){ setTimeout(resolve, ms) }) }

const delayThree = (ms) => new Promise(function(resolve){ setTimeout(resolve, ms) })


// Main
async function main(){
    console.log("start")
    
    await delayOne(2000)
    console.log("After delayOne")
    
    await delayTwo(2000)
    console.log("After delayTwo")
    
    await delayThree(2000)
    console.log("After delay Three")
    
    console.log("end")
}
main()


De console output is
code:
1
2
3
4
5
6
start
After delayOne
After delayTwo
>>>> vertraging van 2 seonden <<<<
After delay Three
end



Ik ben gewend functies te declareren als in delayOne. Dat het ook op de manier van delayTwo en delayThree kan, snap ik inmiddels.

Wat ik echter niet snap, is dat de inhoud van alle drie de functies gelijk is, maar de delay alleen optreed bij delayThree. Het enige verschil dat ik tussen delayTwo en delayThree kan zien, is dat delayThree één regel is en niet omgeven is door { en }. Ik wil graag begrijpen waarom dát het verschil lijkt te maken. Ik heb gezocht naar de verschillen tussen het declareren van functies, maar kom er niet uit.

Wie heeft een verhelderende blik? Ik vind zelf delayThree het moeilijkste om te lezen (en het lelijkste), zeker als deze functie uiteindelijk vervangen gaat worden door iets met veel inhoud. Moet ik dit gewoon slikken of is er toch een andere manier?

Alvast bedankt!

[ Voor 3% gewijzigd door CB32 op 26-02-2019 11:22 ]

Beste antwoord (via CB32 op 26-02-2019 12:39)


  • Semyon
  • Registratie: April 2001
  • Laatst online: 06-10 14:16
Je await wacht op het return resultaat van je functies. Zowel delayOne en delayThree hebben geen return value... Dus wacht je nergens op.

Je zal dus iets moeten returnen, waarop gewacht kan worden. Dat is alleen nummer 2, je kan dat ook met het function keyword doen als je dat liever hebt.
JavaScript:
1
2
3
const delayFour = function () {
  return new Promise((resolve) => setTimeout(resolve, 3000));
}

Je kan er ook direct een async functie van maken:
JavaScript:
1
const delayFive = async () => {await new Promise((resolve) => setTimeout(resolve, 3000))}

Dan heb je zelf een functie die wacht.. Alle async functie hebben impliciet een Promise return waarde, die hoef je dan niet expliciet te vermelden.

[ Voor 4% gewijzigd door Semyon op 26-02-2019 11:35 ]

Only when it is dark enough, can you see the stars

Alle reacties


Acties:
  • Beste antwoord
  • +2 Henk 'm!

  • Semyon
  • Registratie: April 2001
  • Laatst online: 06-10 14:16
Je await wacht op het return resultaat van je functies. Zowel delayOne en delayThree hebben geen return value... Dus wacht je nergens op.

Je zal dus iets moeten returnen, waarop gewacht kan worden. Dat is alleen nummer 2, je kan dat ook met het function keyword doen als je dat liever hebt.
JavaScript:
1
2
3
const delayFour = function () {
  return new Promise((resolve) => setTimeout(resolve, 3000));
}

Je kan er ook direct een async functie van maken:
JavaScript:
1
const delayFive = async () => {await new Promise((resolve) => setTimeout(resolve, 3000))}

Dan heb je zelf een functie die wacht.. Alle async functie hebben impliciet een Promise return waarde, die hoef je dan niet expliciet te vermelden.

[ Voor 4% gewijzigd door Semyon op 26-02-2019 11:35 ]

Only when it is dark enough, can you see the stars


Acties:
  • +1 Henk 'm!

  • MueR
  • Registratie: Januari 2004
  • Laatst online: 23:42

MueR

Admin Tweakers Discord

is niet lief

Een shorthand arrow function doet impliciet een return. Zeker voor functies die bijvoorbeeld een simpele array filter moeten doen is dit ideaal leesbaar. Zodra je er accolades bij gebruikt moet je zelf zorgen voor de return.

Het grote verschil tussen arrow functions en klassieke functies is scope. De delayOne functie die jij defineert zit in de global scope. Daarnaast heeft die functie een eigen 'this' scope, wat echt het enorm grote voordeel is van arrow functions. Een arrow functie zit altijd in de block scope. Dit is overigens hetzelfde bij variabelen, een var bestaat altijd in de function scope. Een const of let bestaat enkel in de block scope, wat zo klein kan zijn als een if statement.

Wat leesvoer:
- https://medium.com/@theja...row-functions-864033baa1a
- https://www.deadcoderisin...on-scope-and-block-scope/
- https://hacks.mozilla.org...in-depth-arrow-functions/

Anyone who gets in between me and my morning coffee should be insecure.


Acties:
  • 0 Henk 'm!

  • CB32
  • Registratie: November 2011
  • Laatst online: 16:25
@Semyon Bedankt. Dat is duidelijk. Als ik in mijn script simpelweg de promise return, dan werken alle drie de functies zoals verwacht.

Nu wil ik ook een "nuttige" return value meegeven. Ik heb opnieuw drie functies:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Delay functions
function delayOne(ms){
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    })
}

function delayTwo(ms, msg){
    return new Promise(function(resolve) {
        setTimeout(resolve(msg), ms)
    })
}

function delayThree(ms, msg){
    return new Promise(function(resolve) {
        setTimeout(function(){
            resolve(msg)
        }, ms)
    })
}

// Main function
async function main(){
    console.log("First line")
    
    await delayOne(2000)
    console.log("Delayed using delayOne")
    
    const myMsg = await delayTwo(2000, "Return my message")
    console.log("Delayed using delayTwo ", myMsg)
    
    const myMsg2 = await delayThree(2000, "Return this message too")
    console.log("Delayed using delayThree ", myMsg2)
        
    console.log("Last line")
}
main()


Console output:
code:
1
2
3
4
5
First line
Delayed using delayOne // wel vertraagd
Delayed using delayTwo  Return my message // niet vertraagd
Delayed using delayThree  Return this message too // wel vertraagd
Last line


delayOne en delayThree doen wat ik wil. delayTwo wekrt niet zoals ik had gedacht. Waarom moet ik resolve(msg) nog in een aparte functie in de setTimeout stoppen?

Acties:
  • +1 Henk 'm!

  • ufear
  • Registratie: December 2002
  • Laatst online: 19:29
resolve(msg) is een functie aanroep, die wordt eerst geevalueerd en daarna pas aan setTimeout() doorgegeven - daardoor is je Promise dus al geresolved voordat de timeout uberhaupt iets gaat doen.

Als je nou resolve.bind(null, msg) zou gebruiken ipv resolve(msg) dan creeer je een (nieuwe) functie (met een scope van null) die nog niet aangeroepen is.

Of ipv direct resolven deze nogmaals in een functie wrappen;

code:
1
2
3
4
5
function delayTwo(ms, msg){
    return new Promise(function(resolve) {
        setTimeout(() => resolve(msg), ms)
    })
}

[ Voor 23% gewijzigd door ufear op 26-02-2019 12:36 ]


Acties:
  • +1 Henk 'm!

  • CB32
  • Registratie: November 2011
  • Laatst online: 16:25
@MueR @Semyon @ufear Bedankt, ik heb genoeg om even verder te gaan.

[bad joke]
I'll be sure to return.
[/bad joke]

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Even een extra tip:
Als je dit soort zaken wilt gaan gebruiken in iets meer dan een probeersel, dan loont het zeker om voor leesbaarheid van je code composition toe te passen en dit soort 'primitives' herbruikbaar te maken.

Maak bijv. een simpele delay functie als losse module:
JavaScript:
1
2
3
export default function delay( msec ) {
  return new Promise( resolve => setTimeout( resolve, msec ));
}
En importeer en gebruik deze om andere functies te maken die met vertraging iets doen zoals een waarde terug geven:
JavaScript:
1
2
3
4
5
6
7
8
import delay from "(...)/promise-delay";

async function delayedMessage( msec, msg ) {
  await delay( msec );
  return message;
}

console.log( "Delayed message: ", await delayedMessage( 1000, "Return my message" ))

[ Voor 5% gewijzigd door R4gnax op 26-02-2019 21:25 ]

Pagina: 1