Unexpected output ide

Posted on
  • To my understanding of javascript, asynchronous-like behaviour from timeout is meant to run when execution stack is empty. I expect output with 'nope' at the bottom of the list. Why is this happening? Im running in the 'web ide' with emulator mode. Tested on my bangle watch connected to the ide too, same.

    setTimeout( function(){console.log("nope");},0);
    console.log("yep");
    console.log("yep");
    console.log("yep");
    console.log("yep");
    console.log("yep");
    var dontgetit = 345;
    

    OUTPUT:

    >yep
    nope
    >yep
    >yep
    >yep
    >yep
    

    another example :

    setTimeout( function(){console.log("nope");},100);
    var x =0;
    while ( x < 10000 ) {
      x++;
    }
      
    var dontgetit = 345;
    console.log("done");
    
  • @user114097, interesting... because if you have something else going on in the delayed function then just writing to the console, such as changing a value, you would see that showing in the console by the log statements. It for sure gives me something to think about. Btw, what is the output of your 'another example:'? ...because I know that a loop as you implemented holds on to the CPU in regard to JavaScript execution... I hope that is still true.

  • output from the 2nd example is :

    nope
    >done
    >
    > 
    

    I expected that 'done' comes first. Because thats the behaviour of JS timeouts. But it output 'nope' which means the timeout callback is fired inbetween the while loop.

  • But it output 'nope' which means the timeout callback is fired inbetween the while loop.

    it is called after the while loop finishes. Each syntactically complete line is evaluated separately. And more so if you are just copy pasting it or sending it (which is done line by line too).

    Maybe if you would save it to flash and then restart, only then maybe it would fire after whole file from flash is done but maybe not even then.

    I am still a bit surprised why you would expect it to work like you suggest, that would be quite limiting.

  • @fanoush ye i think you're right.
    I think its doing what its meant to, just the output is confusing me. I'm reading the left hand side of the web ide incorrectly. Like i'm not sure if i read top down , or down up, i thought it was like a traditional console, but having doubts. Also why does the output from console.log within the closure/timeout not have '>' before it. If it was output "AFTER" the while loop, then it should be "BELOW" .. if i'm reading top down..

  • Some more evidence of what i'm talking about.. without console.log..

    var ypos = 5;
    setTimeout( function(){
      ypos = ypos + 20;
      g.drawString("timeout", 5, ypos, 0);
    },0);
    
    var x =0;
    while ( x < 100000 ) {
      x++;
    }
    
    ypos = ypos + 20;
    g.drawString("final", 5, ypos, 0);
    

    timeout should be printed below final because ypos would be larger if the setTimeout callback ran 'after' the code was parsed and in idle state..
    however its not the case and final is printed below (lower on screen == higher ypos value)..
    So i take back my last response about it being something related to console..

  • You still repeat what it 'should' do. 'should' according to your assumptions which you found to be incorrect already in your first test? Maybe javascript works like you say when it is running as part of webpage/DOM rendering but there is no reason espruino on some device would work in same way.

    But anyway, unless your code is part of already defined function, you are entering it line by line so it is evaluated line by (syntactically complete) line.

  • but there is no reason espruino on some device would work in same way.

    If its not a javascript standard then we can forget about it. I thought it might had been a standard cos it affects the flow of code and thus the output of scripts if one were to copy paste from different environments.

  • If its not a javascript standard then we can forget about it.

    Did you try to save it to flash and reboot? Did you try to define it inside of function? Did you try it e.g. in node.js console? Can you point me to 'javascript standard' that would backup your expectations?

  • Tested on node.js. Outputs 'as' i expected:

    done
    nope

    yep
    yep
    yep
    yep
    yep
    nope

    Can you point me to 'javascript standard' that would backup your expectations?

    https://www.ecma-international.org/publi­cations/files/ECMA-ST/ECMA-262.pdf#page=­169

    A Job is an abstract closure with no parameters that initiates an ECMAScript computation when NO OTHER ECMAScript computation is currently in progress.

    Their implementations MUST conform to the following requirements:
    At some future point in time, when there is NO running execution context and the execution context stack is EMPTY

    |

    Did you try to save it to flash and reboot?

    I will try this later.

  • Im thinking the reasoning behind not having this compliance could be related to accuracy of scheduling? If the hardware execution is slow, it will make the timers less accurate and suspended too far into the future?
    Or that it never has a break and is endlessly running code, so then the scheduled tasks would never execute , hmm.

  • Hi,
    I am not JS expert, but I think it all comes down to the way the Web IDE handles your script as @fanoush already mentioned. The code gets executed line by line as it gets uploaded. You can clearly see this when you hit upload, then change to the left side of the editor and hit the up arrow button to show the executed command history.

    Here is your first example with added timestamps:

    setTimeout( function(){console.log("nope "+getTime());},0);
    console.log("yep "+getTime());
    console.log("yep "+getTime());
    console.log("yep "+getTime());
    console.log("yep "+getTime());
    console.log("yep "+getTime());
    var dontgetit = 345;
    

    Output:

    >nope 1592558510.36899995803
    yep 1592558510.37299990653
    >yep 1592558510.37599992752
    >yep 1592558510.38100004196
    >yep 1592558510.38400006294
    >yep 1592558510.39000010490
    

    You can see that nope was written earlier than the yeps. Now let's wrap this in a function and call the function to execute it as a single block:

    function test() {
     setTimeout( function(){console.log("nope "+getTime());},0);
      console.log("yep "+getTime());
      console.log("yep "+getTime());
      console.log("yep "+getTime());
      console.log("yep "+getTime());
      console.log("yep "+getTime());
      var dontgetit = 345;
      return dontgetit;
    }
    
    print(test());
    

    Output:

    >yep 1592559009.20099997520
    yep 1592559009.20099997520
    yep 1592559009.20199990272
    yep 1592559009.20300006866
    yep 1592559009.20300006866
    345
    nope 1592559009.20700001716
    

    You see that the nope now is being executed last, even after printing the result of the function. Maybe you can run your other tests in a similar fashion and it will clear things up for you.

  • Some good news :)
    After uploading the test code to the device. Expected output is seen!
    Thanks for your time.

    EDIT:
    Ye so because its doing it line by line there is a moment of emptiness/silence and the timeout callback is fired. Limitation of this web ide to visualise the output. Even when its emulating in "RAM" via the ide connected via bluetooth this happens too. It should be fixable, if it matters to anyone. But not a big issue if it works as expected on the device and not line by line emulation/debug w/e

  • Dude, i think your solution valid actually. I think the right hand side of the ide should be automatically wrapped in a function just like you did, to preserve the scheduled tasks behaviour :D.

  • https://www.ecma-international.org/publi­cations/files/ECMA-ST/ECMA-262.pdf#page=­169

    Sorry but there is nothing about setTimeout with zero parameter or interactive console and how it handles copy pasted unstructured code or anything that would map it directly to the detailed ordering of evaluation you expect in your example. Your link and the text you pasted is completely irrelevant to our discussion.

  • I think the right hand side of the ide should be automatically wrapped in a function just like you did, to preserve the scheduled tasks behaviour :D.

    That would be pretty pointless and even could cause lot of memory and performance related issues if it would be too large. Just write it yourself in your code if you want it like that.

    BTW I am amazed you still use words like 'compliance', 'fixable' and 'limitation' for such non issue.

  • FYI: https://github.com/espruino/EspruinoTool­s/pull/124

    BTW I am amazed you still use words like 'compliance', 'fixable' and 'limitation' for such non issue.

    Well, it can be a big deal for some users who are not familiar or technical. And want 1:1 behaviour in the ide emulator without having to dig around. It depends on their initial expectation when using the ide. Mine was clearly wrong.

  • Well, it can be a big deal for some users who are not familiar or technical. And want 1:1 behaviour in the ide emulator without having to dig around.

    I'd say that what you want is unreasonable and that it is a bad habit to think and write code like that - expecting 1:1 behavior on something that can be basically random. The sooner 'users who are not familiar or technical' hit issues like this the better so they can learn and fix their code so it is more reliable.

  • @user114097, Works as expected... if you know what is going on...

    EDIT: missed somehow @Raik 's post... so keeping goin is TL;DR, except checking out the linked conversation in the bottom of the post...

    All this excitement for just nothing other than that the (Chrome) browser console (and nodeJS console) behave a little bit different than the Espruino console. Btw, ECMAScfript / ECMA-262 / ES # makes no specification about console implementation. In other words, your statement If its not a javascript standard then we can forget about it. is a bit off-track.

    I want to tackle this difference first and then move on to a more essential thing...

    The Espruino console and related REPL work line by line - just as @fanoush pointed out - event though you may have pasted all seven (7) code lines in post #1 at once, where as the browser console - if you copy it all at once - behaves as expected. The (Chrome) browser console works like uploading of JavaScript in a Web page: Wait until all code that is between the tag is received, then it is compiled into byte code, and then it is executed. For understandable memory reason and because Espruino interprets from source and does not compile and execute from byte code, it does this line wise - more precisely - statement wise execution.

    Now you are asking yourself what happens when I upload this code onto Espruino...

    This brings me to my almost most famous and over and over repeated statement in tis forum:

    Do not put active stuff - other than function / prototype / class definitions into code level 0 or root level.

    ...since it is just the same as pasting that very same code into the console. Why? The upload uses the very same REPL 'channel' to get the code onto the Espruino board where the Espruino JavaScript interpreter receives it and executes it line by line. And now my citation continues:

    *** Always put your code into functions and activate the execution in the onInit() function.***

    While you develop and upload over and over this is a little bit a pain, so add as last line something that triggers onInit() deferred with a timeout. Why? Because you do not want to interfere with the upload!

    As a side note why you do not see the uploading of the code in the console? ...because the echo is turned off before the upload and turned back on after it.

    The code then looks like this:

    function f() {
      setTimeout( function(){console.log("nope");},0);
      console.log("yep");
      console.log("yep");
      console.log("yep");
      console.log("yep");
      console.log("yep");
      var dontgetit = 345;
    }
    
    function onInit() {
      f();
    }
    
    setTimeout(onInit,999); // while dev'g; remove before upload for save
    

    With that code you get what you expect...

     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     2v05 (c) 2019 G.Williams
    >
    yep
    yep
    yep
    yep
    yep
    nope
    > 
    

    Happy Espruino coding! - ao

    PS: @user114097, more? See this conversation: simple explanation how to save code that espruino run on start?. - I guess it is my most referenced one.

  • This might help as well: http://www.espruino.com/Saving

    But basically Espruino is designed for devices with limited RAM. As such, by allowing it to execute code as it is uploaded it is able to fit in twice as much code (it's not having to store the text version of what it is running, as well as the 'interpreted' version).

    Your suggestion for the EspruinoTools change effectively not only negates the efficiency but makes it 50% worse: you now have to store the text version, interpreted giant function, and the result of executing that function.

    If you want the behaviour you expect, all you have to do is flip the IDE over to 'save to flash' and you're sorted. When saving to flash Espruino can execute direct from flash so it's not having to use the RAM - but this isn't an option for all devices.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Unexpected output ide

Posted by Avatar for d3nd3-o0 @d3nd3-o0

Actions