Event Listener MVP

The problem here is that you are not restricting the click handling to whether or not there is an await "in flight"

Try this change, which will make it more clear you can only do one resolve() call per promise:

await: js-awaiter [] {
    return new Promise(
        function(resolve, reject) {
            ReplPad.wake = function(text) {
                ReplPad.wake = function(text) { alert("Stale resolve") }
                resolve(text)
            }
        }
    )
}

Getting "stale resolve" matches the failing cases.

So even though this is single-threaded...there's a race condition here where clicking fast enough means you can trigger a resolve when it's already resolved and there's no promise in effect. It seems by contract that additional calls to resolve() on a promise are no-ops, hence the handle you are allocating and passing will not be consumed.

You basically can't have the click functionality enabled unless you are in the waiting state. It has to be made a no-op or something...so think about how you can do a mitigation instead of this alert. Example:

await: js-awaiter [] {
    return new Promise(
        function(resolve, reject) {
            ReplPad.wake = function(text) {
                ReplPad.wake = function(text) {
                    console.log("Stale resolve(), dropping click on floor")
                    reb.Release(text)
                }
                resolve(text)
            }
        }
    )
}

(Note: Crashing the interpreter is more strict than we particularly need to be when handles are leaked. I've written separately on that topic. I think in cases like this it's actually sort of good, because it helps us know when things are amiss...but long term, being more forgiving unless you are in a diagnostic mode would probably be the better idea.)

2 Likes