Asynchronous agony

gbfs-web has been fixed (and updated a little!). It was my fault, not Chrome's. Chrome wasn't actually shuffling the files around while assembling the Blob that eventually became the ROM with the attached GBFS file—rather, I failed to notice (even though I swear I checked this at least once) that the directory entries were doing a Spiderman and pointing at the wrong files all over the place.

The offending code was formerly this:

let totalSize = directory.offset + directory.size;
const objectPromises = [...files].map(async (file) => {
  const object = {
    buffer: await file.arrayBuffer(),
    name: file.name,
    offset: totalSize,
    size: file.size,
  };
  totalSize += object.size;
  return object;
});
const objects = await Promise.all(objectPromises);
objects.sort((a, b) => 
  a.name < b.name ? -1 :
  a.name > b.name ? 1 :
  0);

The problem was actually in the calculation of the offset that got attached to each file. Going in, the files were actually in selection order, generally, in Safari and Firefox—meaning, already sorted. That meant that "offset" was gonna be correct if we then wrote the files out in that same order in the GBFS archive.

Which we did.

Except then Chrome came along, and every time I pushed Save, I got a file list in a slightly different order, which meant I generated a slightly different offset list. We sorted by name, great, but then that meant the offsets got shuffled around.

Then we output the directory and file contents in name order. Which is great, except now the offsets are pointing to the spots where the file contents used to be before they got sorted. Thus, shuffled.

The weird thing about this is that I swear I thought something like this could have been the problem early on, and I was looking closely at the directory contents including the offsets. I think I've just had a really tough week and must have missed something. Thankfully, I'm off now for a long weekend, which is probably why I'm suddenly paying attention to personal pursuits.

The fix was easy. Offset calculation is simply now deferred until after all the promises are resolved (probably not strictly necessary, but made the change easier) and all the sorting is done.

The other idea I had been looking at was gonna be an interesting one but, as it turned out, never would have fixed my problem: switching gears entirely to try writing the files with shiny new APIs. It would have been a cool experiment, but also, my brief proof-of-concept left me pretty unhappy with the user experience. So I decided to tackle the existing code one more time.

So now we've got a working gbfs-web that doesn't generate an amusingly random ROM every time you push the Save button anymore. I'll miss it a little, but also, huzzah!


You'll only receive email when they publish something new.

More from Mattie B
All posts