I'm trying to use image.onload function but async issue is occuring. I'm passing the data through array but it is not executing according to array order in the image.onload function. How can I fix this issue?
Object.entries(data).forEach(element => {
const brushtype = element[0]['brush']
const img = new Image();
img.onload = () => {
brushctx.drawImage(img, 0, 0);
}
img.src = brushtype;
}
The problem is the way you're requesting those images.
By doing
Object.entries(data).forEach(element => {
}
it's happening at the same time virtually. Whatever image finished loading will be drawn right-after.
If you want your images to be drawn in a specific order - e.g. the order it's listed in the array - you need to request a new one after the previous finished loading.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let myImages = ['https://picsum.photos/id/1/50/50', 'https://picsum.photos/id/22/50/50', 'https://picsum.photos/id/83/50/50', 'https://picsum.photos/id/64/50/50'];
function loadImages(index) {
let image = new Image();
image.onload = function(e) {
context.drawImage(e.target, index % 2 * 50, parseInt(index / 2) * 50);
if (index + 1 < myImages.length) {
loadImages(index + 1);
}
}
image.src = myImages[index];
}
loadImages(0);
<canvas id='canvas' width='200' height='200'></canvas>
To draw images in order of request you either need to wait until all images have loaded and then draw them only when the earlier image have been draw. This answer gives an example of both approaches.
Note That if there are any load errors none of the images may be drawn. In the second method an error will mean none to all but one are drawn.
The snippet bellow loads first then draws. It stores the images in an array images
and keeps a count of images loading. Counting up for each new image, and when an image load it counts down.
When the counter is zero when know all images have loaded and can then draw them all
var imgCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
img.src = element[0]['brush'];
images.push(img);
imgCount ++;
img.onload = () => {
imgCount --;
if (!imgCount) {
for(const img of images) { brushctx.drawImage(img, 0, 0) }
}
}
}
The alternative is to again create an array to hold all the images. But this time we track what has been drawn. Each time an image is loaded, we check if any of the images in the array before it have loaded, then we draw all images until we find a empty image slot.
var drawnCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
const imgIdx = images.length;
img.src = element[0]['brush'];
img.onload = () => {
images[imgIdx] = img;
while (images[drawnCount]) { brushctx.drawImage(images[drawnCount++], 0, 0) }
}
images.push(null);
}