Retry costume image reading if there's an error to mitigate random browser errors

This commit is contained in:
Thomas Weber committed 2022-02-12 13:21:54 -06:00
1 parent 9fa77886dc
commit 8b46c78595
1 file changed
+35 -14
+35 -14
View File
@@ -84,6 +84,40 @@ const canvasPool = (function () {
return new CanvasPool();
}());
const readImage = src => new Promise((resolve, reject) => {
const image = new Image();
image.onload = function () {
resolve(image);
image.onload = null;
image.onerror = null;
};
image.onerror = function () {
reject(new Error('Costume load failed. Asset could not be read.'));
image.onload = null;
image.onerror = null;
};
image.src = src;
});
const persistentReadImage = async src => {
// Sometimes, when a lot of images are loaded at once, especially in Chrome, reading an image
// can throw an error even on valid images. To mitigate this, we'll retry image reading a few
// time with delays.
let firstError;
for (let i = 0; i < 3; i++) {
try {
return await readImage(src);
} catch (e) {
if (!firstError) {
firstError = e;
}
log.warn(e);
await new Promise(resolve => setTimeout(resolve, (i + Math.random()) * 5000));
}
}
throw firstError;
};
/**
* Return a promise to fetch a bitmap from storage and return it as a canvas
* If the costume has bitmapResolution 1, it will be converted to bitmapResolution 2 here (the standard for Scratch 3)
@@ -111,20 +145,7 @@ const fetchBitmapCanvas_ = function (costume, runtime, rotationCenter) {
return null;
}
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = function () {
resolve(image);
image.onload = null;
image.onerror = null;
};
image.onerror = function () {
reject('Costume load failed. Asset could not be read.');
image.onload = null;
image.onerror = null;
};
image.src = asset.encodeDataURI();
});
return persistentReadImage(asset.encodeDataURI());
}))
.then(([baseImageElement, textImageElement]) => {
if (!baseImageElement) {