Why is writing and reading callback code often such a challenge? The answer lies in the non-sequential execution of code lines, causing programmers to grapple with intricate execution sequences. However, the introduction of the new Async/Await syntax in ES 2017 offers a ray of hope. While not all code is awaitable, we can neatly encapsulate the asynchronous aspects into small, manageable functions, sparing us from future headaches.
Let’s delve into an example to illustrate this. Consider the scenario where we want to load an image. As things stand, the order of display appears as (2), (3), (1), while the execution sequence is (1), (2), (3).
const imageUrl = baseUrl + exampleStudyImageIds[imageId];
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = function () { //(2)
createImageBitmap(image, 0, 0, 500, 300)
.then((img) => { // (3)
const canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 300;
const ratio = 1;
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(
img,
0, 0, img.width, img.height,
0, 0, img.width * ratio, img.height * ratio
);
const imageData = context.getImageData(0, 0, img.width, img.height);
resolve(imageData);
})
.catch((error) => {
console.error(error);
reject(error);
});
}
image.src = imageUrl; //(1)
});
Now, let’s embrace the power of Async/Await to streamline this code:
const imageUrl = baseUrl + exampleStudyImageIds[imageId];
const image = await this._loadImage(imageUrl);
const img = await createImageBitmap(image, 0, 0, 500, 300);
const canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 300;
const ratio = 1;
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(
img,
0, 0, img.width, img.height,
0, 0, img.width * ratio, img.height * ratio
);
const imageData = context.getImageData(0, 0, img.width, img.height);
return imageData;
}
async _loadImage(imageUrl) {
let img;
const imageLoadPromise = new Promise((resolve) => {
img = new Image();
img.onload = resolve;
img.src = imageUrl;
});
await imageLoadPromise;
console.log("image loaded");
return img;
}
By leveraging Async/Await, we’ve transformed the code into a more readable and intuitive structure. The code lines now align with the expected execution sequence, making it easier to write, read, and maintain. This is the power of modern JavaScript, simplifying complex asynchronous workflows for a more enjoyable coding experience.