-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
My code breaks from hoisting. Possible to _only_ transform async/await - not const
, etc?
#108
Comments
There is a need to change
get tranformed to
Hoisting to
becomes:
You should never have a problem in the way you describe - can you provide me with an example of source that doesn't translate correctly? |
Aha, interesting. Well then the "option-flaw" is really an awesome feature, since Safari is what needed to be solved XD Thanks for the detailed explanation, enlightening! I love awesome transpilations like this! :-) 👍 The problem is very easily remedied, but with a team of coders where not all are 10x, slips can occur, and also, where there already is a lot of code dev'ed and tested with const/let in effect and assumed. That's why it's less fun. My choices, my bad. It's simply:
[ed: clarified slightly] |
Sidenote, maintaining originally intended semantics would of course be possible by transpiling in iife-closures with scoped values locked in where deemed needed — but I guess that would be a hellish endeavor to implement... |
...it would be possible, but the code you have above wasn't actually creating a closure - if you had referenced The details can be found at https://github.com/MatAtBread/nodent-transform/blob/master/arboriculture.js#L2222 The issue here is exactly as you initially identified - implement |
Wrote it off the top of my head. But, yes, there is a closure. Let me clarify:
Would've been the same of course if assigned to a const within the loop. This is the minimal example. Thanks for the link, I'll check it out. [edit:] Should point out that there is an
|
Perhaps I should reopen, I'll leave closing to you. |
I apologise; your initial example did have a closure over I think you might me onto something, so I'll dig and work out under which conditions this fails. Thanks for persisting with your case :) EDIT: You're quite correct - |
Incorrect comment caused me to close this issue (it's open), not the actual issue I was working on! |
In all fairness my example was not far off from Perl-obfuscation XD |
Oh, have not tried Safari 9, it was reported by a dude running 10. Saying it worked on his mobile devices, but not desktop. I just assumed all <11 was foul!? |
I think I've got this fixed in nodent-transform@3.2.2. The semantics are pretty tricky - updates to the loop variable within the body are (of course) reflected by any subsequent callback references, but not updates in the "update" step (eg the Please let me know if it fixes your issue. |
Sorry I didn't see this 'til now - I'll check it out! |
Good news, and bad. It works with a Minimal example (the const li = [{a:1}, {a:2}]
// Now works fine
for (const v of li) {
await a.be_nice()
setTimeout(() => console.log("good_for:", v.a))
}
// Still no go
let ix = 0
while (ix < li.length) {
await a.be_nice()
const item = li[ix] // <-- [edit]
setTimeout(() => console.log("bad_while:", item.a))
if (ix === li.length - 1) break // or it will error because the index used will be the "overflown"
ix++
} Impressive AST-juggling! |
I thought about that case, but it doesn't happen as ix is declared outside the loop body. Forget the async/await, just the synchronous code
Produces the output
|
@ozra - I'm going to close this for now. If I've misunderstood your |
Sorry, I reduced the example too much in my effort to make it minimal. I edited the example above to reflect the const which is there in reality. It "locks it in" within the block scope of the while. |
Here's fine. It's actually a different cause; Nodent works out how far to hoist In this case, nodent is (incorrectly) selecting the pre-ES6 definition, which is that it has function (not block) scope and it is only assigned to once. You can fool nodent into realising it must be block scope by declaring it in the outer-block as well (see here) The problem for nodent is that it's trying to support the pre-ES6 and real ES6 semantics, which of course a browser doesn't have to do - it's either one or the other. Does you code work on Safari 9 (and maybe 10)? Either way, it's a bug. I'll see if I can find a fix that doesn't break something else, or at least assume ES6 semantics as the default. |
It gets complicated quickly when trying to please deviating definitions XD |
This change assumes loop blocks have scope (they do in ES6), which means it "fixes" (i.e. changes) the pre-ES6 behaviour of `const` declarations within loops. Whilst this is "correct", it differs from the previous behaviour and so early JS engines that previously returned "incorrect" results will now return "correct" results: specifically `const` in a loop is local and can be deferenced in a callback with it's loop value rather than it's terminal value. This change affects NodeJS versions before 6.x, Chrome until approx v48, Safari 9 and possibly 10 (I've not verified which browser versions are actually affected). These engine will run generate "correct" ES6 results for loops like: ``` async function nop(x) { return x } var resolve,p = new Promise(function(r){resolve = r}) ; var i = 0, x = 0, s = 1 ; while (i<5) { const j = i+1 ; await nop() ; setTimeout(function(){ x += 1 ; s *= j ; // REFERS to "j" if (x===5) { resolve(s) ; } }, 0); i++ ; } return await p ; ```
NB! The last 'fix' worked for the case identified above, but sadly broke another case (loops containing a |
I really hope this is now fixed. If you click on the link above it would appear to now work. Please re-open if I'm mistaken (again!) |
It's working all fine and dandy now! 👍 |
I have a loop, in it closures with click-handlers are created with id's from the loop. After running the code through nodent (which would be a saver because of Safari 10.*) it has transformed not only asyncs and awaits, but turned
consts
in tovar
, and thereby hoisted them far outside of the loop, thereby making all the click-handlers point to the last item.This in it self is easily remedied in our source - but there's no telling how many other places this causes a problem!
So — is there no flag to enable only transforming said constructs?
Cool concept and solution BTW! :)
[edit] I'm using the command-line tool in a build-script atm.
The text was updated successfully, but these errors were encountered: