How to turn this callback into a promise using async/await? - javascript

The following function takes and image from an url, loads it, and returns its width and height:
function getImageData (url) {
const img = new Image()
img.addEventListener('load', function () {
return { width: this.naturalWidth, height: this.naturalHeight }
})
img.src = url
}
The problem is, if I do something like this:
ready () {
console.log(getImageData(this.url))
}
I get undefined because the function runs but the imaged hasn't loaded yet.
How to use await/async to return the value only when the photo has loaded and the width and height is already available?

How to use async/await to turn this callback function into a promise?
You don't. As usual, you use the new Promise constructor. There's no syntactic sugar for that.
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', reject); // don't forget this one
img.src = url;
});
}
How to use await/async to log the value only when the photo has loaded and the width and height is already available?
You can do
async function getImageData(url) {
const img = await loadImage(url);
return { width: img.naturalWidth, height: img.naturalHeight };
}
async function ready() {
console.log(await getImageData(this.url))
}

This library works pretty well - it allows connection to the child process or simply returns the result asynchronously if desired: https://github.com/expo/spawn-async

Related

Is an async function without await keyword equivalent to a function returning a Promise? [duplicate]

The following function takes and image from an url, loads it, and returns its width and height:
function getImageData (url) {
const img = new Image()
img.addEventListener('load', function () {
return { width: this.naturalWidth, height: this.naturalHeight }
})
img.src = url
}
The problem is, if I do something like this:
ready () {
console.log(getImageData(this.url))
}
I get undefined because the function runs but the imaged hasn't loaded yet.
How to use await/async to return the value only when the photo has loaded and the width and height is already available?
How to use async/await to turn this callback function into a promise?
You don't. As usual, you use the new Promise constructor. There's no syntactic sugar for that.
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', reject); // don't forget this one
img.src = url;
});
}
How to use await/async to log the value only when the photo has loaded and the width and height is already available?
You can do
async function getImageData(url) {
const img = await loadImage(url);
return { width: img.naturalWidth, height: img.naturalHeight };
}
async function ready() {
console.log(await getImageData(this.url))
}
This library works pretty well - it allows connection to the child process or simply returns the result asynchronously if desired: https://github.com/expo/spawn-async

How to write a preload function in Javascript?

How do I write a function where everything within the function gets loaded before another function is called? For example, (similar to P5.js) I want to implement a preload function that will load anything that needs to be loaded (ie Images) before executing a setup function.
let someImage;
function preload() {
someImage = new Image();
someImage.src = "some URL";
someImage.onload = imageLoaded;
}
function imageLoaded() {
//this is called before setup
}
function setup() {
//I can safely assume everything is properly loaded
}
To preload an image, you need to actually be careful what order you supply the values. If you add src before onload it is possible that the image will load before the onload function will run.
It is annoyingly more possible than it sounds. Same thing goes for <script> as well.
Here's how I would do it:
let someImage;
function preload() {
someImage = new Image();
return new Promise((resolve, reject) => {
// this will pass the event object in the .then function
someImage.onload = resolve;
// Optional if you want to handle images not loading
// someImage.onerror = reject;
someImage.src = "some URL";
});
}
// Now you can do it two ways depending on what floats your boat
// You can change your setup function to be async/await
async function setup() {
try {
let imageResult = await preload();
imageLoaded();
// code that would be in your original setup function
} catch (e) {
// handle error
}
}
// Or you can do promise chaining with callbacks
preload()
.then(loadEvent => imageLoaded())
.then(() => setup());
// .catch(error => handleError(error)); // Optional;
Making sure you assign the Event before the .src, you could execute a function .onload of your image....
function preload(url, doneFunc){
const img = new Image;
img.onload = ()=>{
doneFunc();
}
img.onerror = ()=>{
console.log(img.src+' load failure');
}
img.src = url;
}
preload('yourImg.png', ()=>{
console.log('execute code here');
});
.... or you could use a Promise, like:
function preload(url){
const img = new Image;
const p = new Promise((resolve,reject)=>{
img.onload = ()=>{
resolve();
}
img.onerror = ()=>{
reject(img.src+' load failure');
}
});
img.src = url;
return p;
}
preload('not_a_good_src.png').then(()=>{
console.log('execute code here');
}).catch(error=>{
console.log(error);
});
Of course, I don't recommend loading the images synchronously, when they can be loaded at the same time instead.
using async await you can do it
let someImage="i-m-a--g-e";
let load = true
function preload() {
console.log("running preload",someImage)
return new Promise((resolve,reject)=>{
if(load){ return resolve()}else{return reject()}
}
);
}
function setup(){
console.log("running setup")
}
(async () => {
await preload();
setup();
})();
JavaScript Demo: Promise.reject()
The best way to implement that in Javascript is to have your preload function return a promise, then put all of your code in the promise success return. If you want functions called in a certain order, then you can do a promise chain.
let someImage;
function preload() {
someImage = new Image();
someImage.src = "some URL";
someImage.onload = imageLoaded;
return new Promise((resolve)=>resolve());
}
preload().then(function(){
setup();
});
function setup() {
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://javascript.info/promise-chaining

If a function returns new promise, does it need the async keyword? [duplicate]

This question already has answers here:
Returning Promise with an async function
(2 answers)
Closed 2 years ago.
I have a function that checks if an image exists, like this:
function getImage(source) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = source
}
}
Should I write the function as:
async function getImage(source) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = source
}
}
Does it make a difference in this particular case? Can somebody please explain?
The code will be used like this:
async function checkImage() {
try {
const img = await getImage('path-to-image')
this.logoImg = img.src // does something with the image
}
catch(e) {
this.logoImg = 'path-to-a-different-image' // does something else if the image is broken, etc.
}
}
Never mind the "this.logoImg" part.
Many thanks in advance.
No,
async is required for functions those are using await inside it.
await is used to avoid .then
Here if getImage returns promise only so no need to use async
function getImage(source) { // This function returns promise
return new Promise((resolve, reject) => {
// ..doesn't have await..
}
}
Here async is required because usingGetImage() using await inside it
async function usingGetImage(){
const img = await getImage('my-image')
}
Hope this will answer your question :)

Use async/await instead of promise to handle loading an image in Javascript [duplicate]

This question already has answers here:
How to turn this callback into a promise using async/await?
(2 answers)
Closed 3 years ago.
I have written a promise based loading image function.
function loadImage() {
const img = new Image();
return new Promise((resolve, reject) => {
img.addEventListener("load", () => {
resolve();
});
img.addEventListener("error", () => {
reject();
});
img.src = 'assets/myImg.jpg';
});
}
loadImage.then(
() => console.log('image loaded'),
() => console.error('image did not load')
);
I would like to convert it using the async/await but I am actually struggling to do it. Any idea how it can achieved ?
You can await your loadImage function, but the new Image() object doesn't use promises, it uses events which you've wrapped with a Promise.
Inside of an async function, you can await your loadImage function, like so:
async function loadImage() {
const img = new Image();
return new Promise((resolve, reject) => {
img.addEventListener("load", () => {
resolve();
});
img.addEventListener("error", () => {
reject();
});
img.src = 'assets/myImg.jpg';
});
}
async function doSomething() {
try {
await loadImage();
console.log("image loaded");
} catch(e) {
console.error("image did not load");
}
}
With a couple changes you can make it work.
The async await side of things would generally replace the ".then()" chaining.
First of all, keep the loadImage() function as is, and define an additional "async" function to run your async await code in. I've called this "main()". You can then create a variable, for example "loadedImage", and then await the promise function. This will pause execution of the next step (being the console log in this case) until the promise has resolved/rejected and the image is loaded.
async function main() {
let loadedImage = await loadImage();
console.log(loadedImage);
}
main()
Additionally, if you wanted to actually return a value into the loadedImage variable (as right now it will be undefined), inside your promise "resolve()" you can place a value. Eg:
resolve('the image has loaded')

How to call functions only after the completion of the previous

Im stuck in trying to get imageData of base64 image. I have 2 functions, and the problem is that second function starts before first ends.
I have 2 functions
frame.restoreImageDataForLayers();
frame.changeResultLayer();
first - load image on a page and then change variable 'layers.data' to imageData of that loaded image.
second - work with imageData of image.
restoreImageDataForLayers() {
this.layers.forEach((item) => {
const layer = item;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const image = new Image();
image.onload = function drawImg() {
context.drawImage(image, 0, 0);
layer.data = context.getImageData(0, 0, layer.canvasSize, layer.canvasSize).data;
console.log('FIRST', layers.data');
};
image.src = layer.data;
});
}
changeResultLayer() {
console.log('SECOND', this.layers[0].data);
}
And then i have
second console log before
first console log
and my another code that must work with imageData - crash.
How to fix that?
You will want to convert restoreImageDataForLayers into a function that returns a promise, whose promise only resolves when the operations in the function complete.
restoreImageDataForLayers() {
const layerPromises = this.layers.map(item => {
return new Promise((resolve, reject) => {
// All your canvas-image code here...
image.onload = function(){
// Your onload code here
// Then resolve the promise for this item
resolve()
}
})
})
return Promise.all(layerPromises)
}
To do that, you need to wrap your image loading procedure in a promise. Use array.map() to create an array of these promises, one for each item. Then use Promise.all() to create that one promise that resolves only when all of the promises in the array resolves.
To call this function, you simply do this:
frame.restoreImageDataForLayers().then(() => {
frame.changeResultLayer();
});
Or if the caller is in an async function, do this:
async thatWrapperFunction(){
await frame.restoreImageDataForLayers();
frame.changeResultLayer();
}

Categories