Block while parsing scripts to prevent sending 'removes' before 'adds'#274
Conversation
|
I don't think this will fix your problem. You probably want a promise that you use as an async queue, like |
|
The problem is that we are getting a Two options:
I think the first one is better for perf, and would hopefully prevent other issues with things that depend on the _scriptsById map. |
|
Could you add a test to the PR as well, that adds some scripts, refreshes the page, and ensures that the script load/unload events are sent in the proper order? You can take some inspiration from this failing test on how to do that. |
|
Ran into a bug with the newest typescript: microsoft/TypeScript#21491 |
b2b9611 to
4a5ce3a
Compare
src/chrome/chromeDebugAdapter.ts
Outdated
| this._initialSourceMapsP = null; | ||
|
|
||
| initialSourceMapsP.then(() => { | ||
| await initialSourceMapsP.then(async () => { |
There was a problem hiding this comment.
The mixing of async/await and promises is a little confusing here (await ... .then()
src/chrome/chromeDebugAdapter.ts
Outdated
| await initialSourceMapsP.then(async () => { | ||
| this._session.sendEvent(new InitializedEvent()); | ||
| this._earlyScripts.forEach(script => this.sendLoadedSourceEvent(script)); | ||
| await Promise.all(this._earlyScripts.map(async script => await this.sendLoadedSourceEvent(script))); |
There was a problem hiding this comment.
The async/await inside map is redundant, just return the promise from this.sendLoadedSourceEvent
| } | ||
| } | ||
|
|
||
| public doAfterProcessingSourceEvents(action: () => void): Promise<void> { |
There was a problem hiding this comment.
The use inside onExecutionContextsCleared() doesn't return a promise
src/chrome/chromeDebugAdapter.ts
Outdated
|
|
||
| Promise.all(asyncOperations).then(() => | ||
| this.clearTargetContext()); | ||
| return Promise.all(asyncOperations).then(() => |
There was a problem hiding this comment.
This is confusing, asyncOperations will not be populated by this point because it's populated by an async function that we don't wait on. I'm not sure what's supposed to happen.
There was a problem hiding this comment.
Nice catch... I missed this...
src/chrome/chromeDebugAdapter.ts
Outdated
| this._session.sendEvent(scriptEvent))); | ||
| }); | ||
| private onExecutionContextsCleared(): Promise<void> { | ||
| const asyncOperations = []; |
There was a problem hiding this comment.
I think this method picked up an extra level of indentation
src/chrome/chromeDebugAdapter.ts
Outdated
|
|
||
| Promise.all(asyncOperations).then(() => | ||
| this.clearTargetContext()); | ||
| return this.doAfterProcessingSourceEvents(async () => { // Execute after sending all the 'removed' events |
There was a problem hiding this comment.
This is a confusing flow now. The asyncOperations array isn't needed if doAfterProcessingSourceEvents is forcing this to happen after sending the script removed events are sent.
Also, you could iterate the scripts inside the doAfterProcessingSourceEvent. That will be faster because the script processing doesn't have to happen one by one. You can use the await Promise.all(scriptById.map(async () => ... pattern again.
There was a problem hiding this comment.
I rewrote this to use async/wait. What do you think?
roblourens
left a comment
There was a problem hiding this comment.
I think this is right. Async code is hard :) Thanks!
We were running into an issue where we send 'remove' myscript.js before we sent the 'add' myscript.js when we went into a page, and quickly redirected into another page.
That happened because we have some async code in how we process onScriptParsed, so that processing can be on-flight, and onExecutionContextsCleared very quickly sends the 'remove' events, and we weren't waiting for the onScriptParsed events to be completed.
This fixes solve part of the issue.
I think there is another unrelated reason that I'm investigating after this.