code-dot-org / dance-party

Renderer for the Dance game type. Based on p5.js and p5.play.js.
https://code-dot-org.github.io/dance-party/
13 stars 13 forks source link

Optimize character loading with static analysis #516

Closed islemaster closed 5 years ago

islemaster commented 5 years ago

Get faster load times and a smaller memory footprint by only downloading and preparing spritesheets for the characters used by the student's code.

This change is ready to go and only moderately risky, but we decided not to take it prior to Hour of Code in light of the many other changes we have going in at the last minute. We are still interested in adding this improvement in the week following Hour of Code, and should revisit this starting on December 10th.

Requires these two interdependent changes:

islemaster commented 5 years ago

Excellent write-up by Chris on how this change works and why we should take it:

I've changed how we load spritesheets and animations so that we can load only the assets needed for the characters referenced in the student's program.

Since p5 only initializes once (and therefore enters preload and setup once), we must now do asset loading without relying on the p5 preload phase (which through trickery tracks async asset loading functions and delays the exit of the preload phase and the start of the setup phase until after all of those async asset loading functions have completed.)

The fetch of characters.json, the spritesheet PNGs, and the construction of the p5.play animations now occur within an async function that must be completed before play() can be called. This function is called ensureSpritesAreLoaded(). It can be called without parameters (in which case all character assets are loaded) or with an array of character names that must be loaded.

The asset loading is additive. If a student's code is modified to reference additional characters, ensureSpritesAreLoaded() should be called again with a different list of characters. Any characters not yet loaded will be loaded before the Promise it returns is resolved.

We do not unload any animations at this time. We do not do any conditional loading of specific dance moves. We do cache the characters.json response in memory and do not request it more than once, much as we already cache each spritesheet PNG Image object and will not request those more than once.

Many new tests have been added to verify the behavior of ensureSpritesAreLoaded(). Existing tests have been updated to ensure that all sprites are loaded before calling play(). The test runner (tape) has been augmented with tape-async for unit tests to ensure that we can properly perform async waits within our tests.

The benefits are:

  1. Code Studio is responsive and ready to run more quickly
  2. The network payload is reduced for any program that doesn't use all characters (we only download what we need) so we can start dancing quickly when Run is pressed
  3. The memory footprint is reduced for any program that doesn't use all characters.
  4. Visiting a share page is lighter weight and faster, where we cannot expect to have the assets already in the browser cache. We now can start the dancers much more quickly (unless the shared program uses every character).
joshlory commented 5 years ago

Resolving (shipped).