Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[javascript] arguments.callee vervangen door andere code

Pagina: 1
Acties:

  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Op gebied van Javascript ben ik nog een beginner. Met dank aan Stackoverflow heb ik behoorlijk wat zaken bijgeleerd en problemen kunnen oplossen. Maar deze kom ik niet uit: een van mijn functies gebruikt arguments.callee. Volgens JShint en andere bronnen is het gebruik hiervan meestal niet meer aan te raden. In sommige gevallen (b)lijkt het onvermijdelijk. Ik verwacht dat ik niet zo'n uitzondering heb, maar weet dit niet zeker. Ik kom er in ieder geval niet uit hoe ik dit vervangen kan door een named function wat de logische oplossing lijkt.

Mijn code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
//continue calling "then" until "test" is true 
function sometimeWhen (test, then, millis) {
    //http://fitzgeraldnick.com/weblog/35/
    async(function () {
        if ( test() ) {
            then();
        } else {
            async(arguments.callee, millis);
//          TODO: replace arguments.callee
//          http://stackoverflow.com/a/235760
        }
    });
}

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Milmoor schreef op woensdag 27 november 2013 @ 16:06:
Ik kom er in ieder geval niet uit hoe ik dit vervangen kan door een named function wat de logische oplossing lijkt.
Het is niet zo moeilijk als je misschien zou denken:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
function sometimeWhen (test, then, millis) {
  var poll = function() {
    if ( test()) {
      poll = null;
      then();
    } else {
      async( poll, millis );
    }    
  };

  async( poll, millis );
}

  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Dat zou moeten werken: eerst definieren, dan vertraagd aanroepen i.p.v. dit te combineren. Bedankt.

Dit soort constructies trainen wel de lenigheid van je hersenen ;). Vooral het impliciet meegeven van de test en then voor de volgende iteratie is even wennen.

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Mmm, vreemd. Het lijkt te werken, maar het effect is wel veranderd. Ik gebruik dit o.a. om de status van een teller te updaten. Deze update nu veel regelmatiger. Ik ga eens tracen op 'millis'.
...
Hij lijkt de test continu uit te voeren zonder de async die voor vertraging zou moeten zorgen.
---
Ik snap het nog niet en krijg het niet goed gemeten. Sometimewhen wordt wel telkens met millis aangeroepen, async krijgt ook geen andere waarden dan ik opgegeven heb binnen, maar toch lijkt async domweg direct aan de slag te gaan wegens de veranderingen in sometimewhen ?!. Ik ga er een nachtje over slapen.

[ Voor 54% gewijzigd door Milmoor op 28-11-2013 20:59 . Reden: iets meer info ]

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • Amanush
  • Registratie: Mei 2012
  • Laatst online: 18-06 09:30

Amanush

Saai persoon.

Als je if( test() ) veranderd in if( test ), dan moet het werken. Test() is geen object, test wel.

Of wou je niet op het bestaan van den object/function testen?

[ Voor 24% gewijzigd door Amanush op 29-11-2013 07:05 ]

Ga tot de luiaard, gij mier! Zie haar wegen en wordt wijs.


  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Test en then zijn beiden functies die meegegeven worden aan de sometimeWhen functie. Simpel voorbeeld met namaakcode:

code:
1
2
3
4
5
6
7
8
9
Lus om bestanden in te lezen totdat er geen bestanden meer zijn om in te lezen
 lees bestand in
 verwerk bestand op de achtergrond (met async, welke zelf setTimeout gebruikt)
Eind lus

Lus met gebruikersinteractie
 Doe je voorgrond ding
 sometimeWhen (alle bestanden ingelezen is waar, meld dat de bestanden allemaal verwerkt zijn)
Eind lus


Voor meer info van iemand die het wel zelf bedacht heeft: http://fitzgeraldnick.com/weblog/35/

[ Voor 9% gewijzigd door Milmoor op 29-11-2013 14:23 . Reden: URL toegevoegd ]

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Helaas snap ik nog niet genoeg van Javascript om te snappen wat hier precies gebeurd. Ik kan het aardig volgen, maar niet zelf aanpassen. Mijn eigen poging raakt Out of Stackspace:
code:
1
2
3
4
5
6
7
8
9
//continue calling "then" until "test" is true 
function sometimeWhen (test, then, millis) {
    //adapted from http://fitzgeraldnick.com/weblog/35/
    if ( test() ) {
        async(then, millis);
    } else {
        async(sometimeWhen(test, then, millis), millis);
    }
}

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Milmoor schreef op vrijdag 29 november 2013 @ 14:21:
Helaas snap ik nog niet genoeg van Javascript om te snappen wat hier precies gebeurd. Ik kan het aardig volgen, maar niet zelf aanpassen. Mijn eigen poging raakt Out of Stackspace:
code:
1
2
3
4
5
6
7
8
9
//continue calling "then" until "test" is true 
function sometimeWhen (test, then, millis) {
    //adapted from http://fitzgeraldnick.com/weblog/35/
    if ( test() ) {
        async(then, millis);
    } else {
        async(sometimeWhen(test, then, millis), millis);
    }
}
Lees eens goed wat daar staat; je maakt een oneindige recursieve lus door vanuit sometimeWhen direct opnieuw sometimeWhen aan te roepen...

  • Klaasvaak
  • Registratie: Maart 2010
  • Laatst online: 22-11 22:39
JavaScript:
1
2
3
4
async(function(){...});

var poll = function() {...};
async(poll, millis );       // hier is een extra argumentje ingeslopen.

  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Klaasvaak: Ik snap helaas niet wat je bedoeld.
R4gnax: Ik had beter direct ook de code van async in mijn post kunnen geven. Wat er naar mijn idee zou moeten gebeuren met mijn code staat hieronder. Hij is dus oneindig recursief zolang test niet waar blijft. Zodra deze waar wordt, wordt then uitgevoerd.

test:N wacht test:N wacht test:N wacht test:J then

wacht is geïmplementeerd als een async(sometimeWhen(...))


code:
1
2
3
4
5
6
7
8
9
10
//start function fn asynchronous after (at least) a certain amount of milliseconds
//and (of course) in the mean time, the rest of the javascript will continue to execute
function async (fn, millis) {   
    //http://fitzgeraldnick.com/weblog/35/
    if (millis === undefined) {
        setTimeout(fn, 20);
    } else {
        setTimeout(fn, millis);
    }
}

[ Voor 9% gewijzigd door Milmoor op 01-12-2013 20:55 . Reden: verduidelijking ]

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • Klaasvaak
  • Registratie: Maart 2010
  • Laatst online: 22-11 22:39
Als er bij het aanroepen van async geen argument voor milis wordt meegegeven, krijgt deze de standaardwaarde 20. In de code die R4gnax heeft gepost wordt er bij het aanroepen van async een argument voor milis meegegeven, waar dat in de oude code niet gebeurd.
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function sometimeWhen (test, then, millis) {
    async(function () {
        if ( test() ) {
            then();
        } else {
            async(arguments.callee, millis);    // 2 argumenten
        }
    });         // 1 argument, dus milis wordt binnen de async functie op 20 gezet.
}

function sometimeWhen (test, then, millis) { 
  var poll = function() { 
    if ( test()) { 
      poll = null; 
      then(); 
    } else { 
      async( poll, millis );    // 2 argumenten
    }     
  }; 
  async( poll, millis );    // 2 argumenten, dus milis heeft de waarde van de milis parameter waarmee sometimeWhen wordt aangeroepen.
}

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
function sometimeWhen (test, then, millis) { 
  var poll = function() { 
    if ( test()) { 
      poll = null; 
      then(); 
    } else { 
      async( poll, millis );
    }     
  }; 
  async( poll );        // hier moet dus het milis argument verwijderd moeten worden, om de code gelijk te laten zijn aan de oude code.
}

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Milmoor schreef op zondag 01 december 2013 @ 20:03:
Ik had beter direct ook de code van async in mijn post kunnen geven. Wat er naar mijn idee zou moeten gebeuren met mijn code staat hieronder. Hij is dus oneindig recursief zolang test niet waar blijft. Zodra deze waar wordt, wordt then uitgevoerd.

test:N wacht test:N wacht test:N wacht test:J then
Je maakt een oneindige recursieve call. Datgene wat test() aan het testen is, krijgt nooit de kans zichzelf bij te werken en dus zal de uitkomst nooit true worden.
Milmoor schreef op vrijdag 29 november 2013 @ 14:19:
Voor meer info van iemand die het wel zelf bedacht heeft: http://fitzgeraldnick.com/weblog/35/
Deze persoon draagt sometimeWhen aan als oplossing voor het synchroniseren van meerdere asynchrone taken. Iets wat in de regel opgelost wordt via het combineren van promises. Zie bijvoorbeeld jQuery.when. Voor deze klasse van problemen een polling oplossing aandragen is echt niet meer van deze tijd (en kun je zelfs 'dom' noemen).

Ik heb het zelf niet helemaal gelezen, maar ik zou je aanraden voorzichtig te zijn met wat daar geschreven staat en het met een dikke lading zout te nemen, het kan wel eens flink verouderd zijn.

Los daarvan; je geeft aan een beginner te zijn en niet goed te weten hoe alles in elkaar steekt. Dan is het niet erg slim om zo van andere mensen code snippits over te gaan nemen zonder te weten hoe ze in elkaar steken en wat het effect er van is. Van die aanpak plukken we vandaag de dag nog steeds de zure vruchten; zie o.a. mysql_real_escape_string...

[ Voor 89% gewijzigd door R4gnax op 02-12-2013 00:33 ]


  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Klaasvaak: goed gezien. Bedankt voor de duidelijke uitleg. Dit is een logische oorzaak van het probleem. Ik ga hier mee spelen.
R4gnax: ik ga de escape clausule van de recursie beter doornemen als het niet meer maandagochtend is ;). Volgens mij zou het goed moeten gaan omdat wat er getest wordt ook "asynchroon" draait. Dit is een wachtlus die elke keer kijkt of de hoofdlus al klaar is. Uit de hoofdlus worden meerdere acties asynchroon opgestart. Pas als alle acties afgerond zijn mag deze lus wat gaan doen. Ik besef me nu dat het handig was geweest als ik die context erbij genoemd had. Maar ik was dan ook op zoek naar een alternatief voor arguments.calee, zonder me genoeg te realiseren dat hetgeen eromheen gebeurd dan ook belangrijk is.

Wat betreft de gekozen oplossingsroute in de code en het kopiëren van anderen: je hebt gelijk, maar ik heb daar een stevige kennisachterstand en weet soms niet dat/wat er in de loop van de tijd veranderd is. Ik snap wat Fitzgeraldnick schrijft en kan dit aanpassen. Dat is wat anders dan dat ik het zelf kan verzinnen. In dit geval lukt(te) het me ook niet om dit totaal te verbouwen. Dat er inmiddels betere technieken zijn is goed om te weten. Maar ik ben voor dit soort zaken nog onbewust onbekwaam. Ik heb indertijd aardig gezocht naar hoe ik zaken asynchroon inlees. In die zoektocht ben ik op deze blog beland. Wat er stond was duidelijk beschreven met voorbeelden, ik kon het volgen en aanpassen en het werkt. De term "promises" ben ik toen niet tegen gekomen (ga ik me op inlezen). Wel wat korte verwijzingen naar webworkers, maar die impliceerden werk in uitvoering en werken niet op IE8 (wordt bijv. op mijn werk pas over een half jaar vervangen wegens gebrek aan support leverancier primair pakket, daarom had ik die versie supporten als ondergrens genomen). Hele oude XSLT voorbeelden (b)lijken bijvoorbeeld nog steeds actueel. Ik weet niet hoe ik herken dat ik met verouderde code bezig ben. In de praktijk ga ik zoeken als ik een probleem heb en vindt ik het antwoord negen van de tien keer op Stackoverflow. Maar mijn zoektermen zijn natturlijk bepaald/beperkt door mijn huidige kennis. Tips zijn welkom.

[ Voor 24% gewijzigd door Milmoor op 02-12-2013 09:15 . Reden: Kleine verduidelijking ]

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Milmoor schreef op maandag 02 december 2013 @ 08:01:
Klaasvaak: goed gezien. Bedankt voor de duidelijke uitleg. Dit is een logische oorzaak van het probleem. Ik ga hier mee spelen.
Uhm. Nee. Dat heeft compleet niets te maken met het feit dat je in een stack overflow terecht komt door recursie. Of je nu 20ms wacht of 20.000ms, in beide gevallen breek je de huidige execution flow en zult daardoor niet een oneindige recursie kunnen krijgen. Sterker nog; er zijn allerhande handige foefjes om efficient te yielden zonder zelfs die 20ms te hoeven wachten. Daar zijn complete libraries voor beschikbaar.

Jij krijgt een probleem met een stack overflow omdat sometimeWhen zichzelf continu aan blijft roepen zonder te yielden. Kijk maar eens naar regel 7. Je roept daar direct sometimeWhen aan en het resultaat daarvan geef je mee aan async.

JavaScript:
1
2
3
4
5
6
7
8
9
//continue calling "then" until "test" is true 
function sometimeWhen (test, then, millis) {
  //adapted from http://fitzgeraldnick.com/weblog/35/
  if ( test() ) {
      async(then, millis);
  } else {
      async(sometimeWhen(test, then, millis), millis);
  }
}


Vergelijk dat nu met wat je eigenlijk wilt doen: een functie aan async meegeven, die pas nadat de timer is verstreken sometimeWhen aan roept.

Jouw commentaar boven de functie strookt overigens ook niet met wat de functie daadwerkelijk doet; de functie roept test herhaaldelijk aan totdat deze true is en roept dan eenmalig then aan. Het commentaar beweert min of meer het tegenovergestelde.

JavaScript:
1
2
3
4
5
6
7
8
9
// Continue calling "test" until it is true, then call "then" once.
function sometimeWhen (test, then, millis) {
  //adapted from http://fitzgeraldnick.com/weblog/35/
  if ( test() ) {
      async(then, millis);
  } else {
      async(function(){ sometimeWhen(test, then, millis) }, millis);
  }
}



Milmoor schreef op maandag 02 december 2013 @ 08:01:
Dit is een wachtlus die elke keer kijkt of de hoofdlus al klaar is. Uit de hoofdlus worden meerdere acties asynchroon opgestart. Pas als alle acties afgerond zijn mag deze lus wat gaan doen.
Jij wilt dus inderdaad iets gaan doen met promises en je wilt niet een polling loop gebruiken zoals
je nu doet. Ga jezelf eerst maar eens goed daarover inlezen. Wat je uiteindelijk wilt gaan doen is je asynchrone acties zo opzetten dat ze een promise retourneren. Daarna gebruik je simpelweg een when operatie om de promises van al deze acties te combineren tot één promise die zichzelf pas resolved wanneer al die onderliggende promises geresolved zijn (wat wil zeggen dat de onderliggende acties afgerond zijn). Mochten je acties resultaat waardes hebben die verder verwerkt moeten worden; die kun je als argument aan de promise meegeven en zo naar buiten mee door sturen...

[ Voor 40% gewijzigd door R4gnax op 02-12-2013 21:28 ]


  • Milmoor
  • Registratie: Januari 2000
  • Laatst online: 22-11 21:22

Milmoor

Footsteps and pictures.

Topicstarter
Ik ga me verder inlezen, bedankt. Mijn code kan zo inderdaad niet werken, dat klopt echt niet qua meegeven van de functie. En mijn commentaar is inderdaad verkeerd om. Ouch :(. Bedankt voor je uitleg en voorbeelden. Leerzaam.

Klaasvaak heeft ook gelijk. Er zit een kleine fout in mijn eerste code waardoor de timing fout gaat (had altijd millis moeten zijn i.p.v. te resetten na de eerste test). Die staat los van mijn eigen slechte versie met Stack overflow error.

[ Voor 26% gewijzigd door Milmoor op 03-12-2013 19:36 . Reden: mijn en dijn door elkaar gehaald ;). ]

Rekeningrijden is onvermijdelijk, uitstel is struisvogelpolitiek.


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Milmoor schreef op dinsdag 03 december 2013 @ 17:51:
Ik ga me verder inlezen, bedankt. Mijn code kan zo inderdaad niet werken, dat klopt echt niet qua meegeven van de functie. En mijn commentaar is inderdaad verkeerd om. Ouch :(. Bedankt voor je uitleg en voorbeelden. Leerzaam.

Klaasvaak heeft ook gelijk. Er zit een kleine fout in mijn eerste code waardoor de timing fout gaat (had altijd millis moeten zijn i.p.v. te resetten na de eerste test). Die staat los van mijn eigen slechte versie met Stack overflow error.
Top. Succes met inlezen. Het is ineens een flinke brok extra theorie en paradigma waar je even je gedachten omheen moet winden, maar als het eenmaal klikt dan is het ook ineens helemaal logisch en zul je zien dat je er heel snel handigheid in krijgt. (Het is ook niet voor niets dat promise patterns in zo'n sneltrein vaart door zoveel partijen geadopteerd zijn.)
Pagina: 1