This question already has answers here:
Is it an anti-pattern to use async/await inside of a new Promise() constructor?
(5 answers)
What is the explicit promise construction antipattern and how do I avoid it?
(3 answers)
Closed 5 months ago.
I'm fetching images from my app through js but eslint is warning about using async promise executors. I know that in other cases like this, you could just remove the promise all-together, but not sure if that's applicable here.
Here is the code in question:
async fn() {
let urls = _.map($('#img-container img'), (img) => $(img).attr('src'));
urls = await Promise.all(urls.map((url) => new Promise(async (res) => { // FIXME - async promise executor
const blob = await (await fetch(url)).blob();
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = res;
})));
urls = urls.map((u) => u.target.result);
return Buffer.from(pako.deflate(JSON.stringify(urls))).toString('base64');
}
How could I restructure this to get rid of this pattern? Or should I just dismiss the warning?
ESlint is complaining because there shouldn't be a need for an explicit Promise's executor to be async, because it generally means you're doing something wrong (mixing things that are already promisesque with building explicit promises).
You'll have a better time altogether (and ESlint won't complain either) if you refactor things so the callback-style FileReader API is wrapped in its own function that returns a promise (and that executor doesn't need to be async).
function blobToDataURL(blob) {
return new Promise((res) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = res;
});
}
async function x() {
let urls = _.map($("#img-container img"), (img) => $(img).attr("src"));
const dataUrls = await Promise.all(
urls.map(async (url) => {
const blob = await fetch(url).blob();
return blobToDataURL(blob);
}),
);
}
Related
This question already has answers here:
Use async await with Array.map
(9 answers)
Best way to call an asynchronous function within map?
(14 answers)
Closed 1 year ago.
I'm learning from Jonas Schmedtmann JS course. At the end of the async function section, I just don't understand some things.
Here are the three function:
const createImage = function (imgPath) {
return new Promise(function (resolve, reject) {
const img = document.createElement('img');
img.src = imgPath;
img.addEventListener('load', function () {
imgContainer.append(img);
resolve(img);
});
img.addEventListener('error', function () {
reject(new Error('Image not found'));
});
});
};
const loadNPause = async function () {
try {
// Load image 1
let img = await createImage('img/img-1.jpg');
console.log(img);
console.log('Image 1 loaded');
await wait(2);
img.style.display = 'none';
// Load image 1
img = await createImage('img/img-2.jpg');
console.log('Image 2 loaded');
await wait(2);
img.style.display = 'none';
} catch (err) {
console.error(err);
}
};
const loadAll = async function (imgArr) {
try {
const imgs = imgArr.map(async img => await createImage(img));
console.log(imgs);
const imgsEl = await Promise.all(imgs);
console.log(imgsEl);
imgsEl.forEach(img => img.classList.add('parallel'));
} catch (err) {
console.error(err);
}
};
loadAll(['img/img-1.jpg', 'img/img-2.jpg', 'img/img-3.jpg']);
By the loadAll function, when I log the imgs variable, it gives me an array of promises. Jonas said that is because of async function, it returns always a promise.
But, if I delete the async await keywords, like this "const imgs = imgArr.map(img => createImage(img));", it returns also a promise.
However, in the loadNPause function when I log the img variable, it is not a promise, but an img object.
Can you tell me why is that? In both function is returned a promise from the createImage function, in loadNPause gives me back an img Object, but in loadAll function when go through the array, then the createImage returns a promises.
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
I'm learning async/await but I really don't know what is wrong here. Why is my myArray always an empty when I use await? How can I solve this?
function getFileAsBinary(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
};
const preparePhotos = async (photoFiles, myArray) => {
photoFiles.forEach(async (photoFile) => {
const photoBinary = await getFileAsBinary(photoFile);
myArray.push("something")
});
}
// ----------------------------------------------------
const myArray= [];
const photos = [file1,file2];
await preparePhotos(photos,myArray);
console.log(myArray); // getting [] here, why is it empty?
The callbacks passed to the forEach are not synchronous, it can work, but not as expected. When the iteration is done the async function "preparePhotos" will return immediately.
I think you should use a for loop instead.
PD: not sure if this question is a duplicated of: Using async/await with a forEach loop
When you use await inside the forEach loop, you are telling the js engine to "wait" inside the lambda, not the overall function.
If you want to be able to await the preparePhotos function, you will need to some how get "await" out of the lambda.
Start by defining an array of promises
let promises = [];
Then instead of awaiting the promise returned by getFileAsBinary, append it to the list
photoFiles.forEach((photoFile) => {
promises.push(getFileAsBinary(photoFile));
})
You now have a list of promises, and can use Promise.all to await all promises in the list
let myArray = await Promise.all(promises);
Promise#all returns a list of all values resolved by the promises within the original array, so it will return effectively your original "myArray".
Alternatively, use a for of loop (MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)
for(let elem of photoFiles) {
let binary = await getFileAsBinary(elem);
myArray.push(binary);
}
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
I'm writing javascript code to parse a huge file (several GBs) and I'm using FileReader's readAsArrayBuffer function with promises (see below):
function readRaw(fc, length) {
const fileReader = new FileReader();
return new Promise((resolve, reject) => {
fileReader.onloadend = function(value) {
console.log("onloadend");
fc.offset += length;
resolve(new Uint8Array(value.result));
}
fileReader.onerror = (err) => {
console.error(err);
reject(err);
}
const slice = fc.handle.slice(fc.offset, fc.offset + length);
fileReader.readAsArrayBuffer(slice);
});
}
function parsefile(file) {
let fc = { handle: file, offset: 0 };
let buffer = {};
var promise = readRaw(fc, 32);
promise.then(function(value) {
console.log("success: offset=" + fc.offset)
buffer = value
}).catch((e) => {
console.error(e);
});
console.log("offset=" + fc.offset);
}
document
.getElementById('fileToRead')
.addEventListener('change', function () {
let file = this.files[0];
if (file) {
parsefile(file);
}
}, false);
My expectation is that Promise.prototype.then() should wait for the promise to resolve before continuing but I'm not able to get it to work no matter how I tweak the code or switch to use async/await.
Expected:
onloadend
success: offset=32
offset=32
Actual
offset=0
onloadend
success: offset=32
Thanks in advance for any help and enlightenment!
Per Why await beats Promise.then(...)"
The fundamental difference between await and vanilla promises is that await X() suspends execution of the current function, while promise.then(X) continues execution of the current function after adding the X call to the callback chain.
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
I have an async function that processes an Array and call another async function by increasing time interval by each element.
I wait for all promises to resolve and then I save the resulting Array in a file. Though for some reasons the write file operation executes before the Promises are resolved.
Can somebody tell me what I might be doing wrong?
The read and write file functions are turned into promise with node util and the getGuidesList returns a promise.
(async () => {
try {
const file = await readFilePromise('./kommuner.json');
const municipalities = JSON.parse(file).municipalities;
console.log(municipalities);
const municipalities_new = await Promise.all(municipalities.map(async (municipality, index) => {
setTimeout(async () => {
let guides = await getGuidesList(municipality.municipality_id);
// const guides = [];
if (typeof guides === 'string') {
guides = [];
}
console.log(`Number of guides for ${municipality.municipality_name}: ${guides.length}`);
Reflect.set(municipality, 'guides_number', guides.length);
Reflect.set(municipality, 'guides', guides);
console.log(municipality)
}, index * 5000);
}))
console.log(municipalities_new);
await writeFilePromise('./kommuner_guide.json', JSON.stringify({
"municipalities": municipalities_new
}));
} catch (err) {
console.log(err);
}
})();
The problem here is this line:
setTimeout(async () => {
you do a setTimeout call. That will schedule the callback to be called later. But you don't wait for that callback to happen. Instead use some promisified version of setTimeout:
const timer = ms => new Promise(res => setTimeout(res, ms));
then you can
await timer(2000);
await /*other stuff*/;
I am trying to read user uploaded file and convert it into String. I have 2 functions to do this.
handleFileInput
handleFileInput(event){
setTimeOut(async()=>{
let abcd= await this.convertFileToString(this.file) //the file has been uloaded successFully at this point
console.log(abcd) //this prints the enitre fn given in the resolve method
},3000)
}
convertFileToString
convertFileToString(file){
return new Promise((resolve, reject)=>{
let fileReader = new FileReader();
fileReader.readAsText(file);
resolve(fileReader.onload = (event) =>{
this.XMLAsString=fileReader.result as String
})
})
}
When i print the value of abcd in the console i get this:
ƒ (event) {
_this.XMLAsString = fileReader.result;
}
I am fairly new to the concept of async/await and Promises and understand that promise is the only asynchronous thing i can await. I want the value of the uploaded file (converted to String) to be stored in variable abcd. how do i get the value? Or if i have to return a promise, then how do i access the value of file read as String and store in in abcd?
Your convertFileToString looks a little wrong: you should be invoking resolve() in the onload handler, not the other way round:
convertFileToString(file){
return new Promise((resolve, reject)=>{
let fileReader = new FileReader();
fileReader.readAsText(file);
fileReader.onload = (event) => {
resolve(event.target.result);
}
})
}