regenerator icon indicating copy to clipboard operation
regenerator copied to clipboard

[bug?] `await null` inside while loop causes infinite loop?

Open trusktr opened this issue 8 years ago • 1 comments

Based on the discussion at https://github.com/facebook/regenerator/issues/236, await should always defer. However, I seem to have found bug?

The following example behaves as if the await null line doesn't defer, causing the while loop to loop forever and crashing the browser tab. The first console.log inside of main() fires, which indicates control leaves the while loop and goes to regenerator, but then regenerator never routes control away from the while loop to the second console.log:

class TickCounter {
    constructor() { this.current = -1 }
    async start() {
        this.shouldCount = true
        while (this.shouldCount) {
            this.current += 1
            await null
        }
    }
    stop() { this.shouldCount = false }
}

const sleep = time => new Promise(r => setTimeout(r, time))

async function main() {
    let counter = new TickCounter
    counter.start()
    console.log('current tick:', counter.current) // is 0

    await sleep(0)

    // these lines never fire.
    console.log('current tick:', counter.current) // was expecting 1
    counter.stop()
}

main()

A simple reproduction can be found here, in client/main.js: https://github.com/trusktr/site/tree/regenerator-issue-236

To run, just

git clone [email protected]:trusktr/site.git
cd site
git checkout regenerator-issue-236
meteor

When visiting localhost:3000, the page will freeze.

trusktr avatar Apr 08 '16 19:04 trusktr

@benjamn Got a chance to look at this yet? The issue is reproducible, it's a simple Meteor 1.3.1 app.

On a related note, I discovered that code following the await of a promise inside of a requestAnimationFrame loop fires within the same frame, which makes it seem like Promise settling is happening synchronously.

Here is the code: https://esdiscuss.org/topic/promises-async-functions-and-requestanimationframe-together

I was under the impression that since Promises should settle asynchronously, that the code in the loop would fire outside of the animation frame, not inside. Can you offer any insights on what's happening with that animation loop and why the code, which I thought would be deferred, still fires inside the animation frame? I guess I'm asking: what is the behavior we should expect (and how does it compare to what I'm seeing in practice)?

TLDR, writing an animation loop like that, using while, is nice in concept and and in how the code reads, but I'd like to avoid it if the behavior that I am experiencing (all logic fires in the frame) isn't what will actually happen when async functions become native in browsers.

Cheers!

trusktr avatar Apr 23 '16 22:04 trusktr