Why is my object's values a function and not a string? - javascript

I have an update function for an event. It is possible that the user has added a teaser video or not. If they have I want to upload it and save that object with the download url.
I use a different function to upload the video and only call it if the user attached a video.
But when I try to update, it tells me that I'm trying to write an invalid object because the data in teaser is a function, where I want it to be a string (either the download url, or just an empty string.
What am I doing wrong?
This is how I call the function:
updateEvent(values, videoAsFile, () => {
setIsEventEdited(false);
setCurrentEvent(values);
})
Then these are the functions:
const uploadTeaserVideo = (event, video) => async () => {
const ref = storage.ref(`/videos/events/${event.id}/`);
const upload = await ref.put(video);
if (!upload) return "";
const downloadUrl = await ref.getDownloadURL();
if (!downloadUrl) return "";
return downloadUrl;
};
export const updateEvent = (values, teaserVideo, cb) => async () => {
if (teaserVideo) {
const teaser = await uploadTeaserVideo(values, teaserVideo);
db.collection("events")
.doc(values.id)
.set({ ...values, teaser })
.then(() => {
cb();
});
} else {
db.collection("events")
.doc(values.id)
.set(values)
.then(() => {
cb();
});
}
};
I've checked, and teaserVideo is a valid video file, or null if a video wasn't chosen.

uploadTeaserVideo is defined as a function that returns a function:
// vv−−−−−−−−−−−−−−− Start of the uploadTeaserVideo function body
const uploadTeaserVideo = (event, video) => async () => {
// ^^−−− Start of the body of the function it returns
const ref = storage.ref(`/videos/events/${event.id}/`);
const upload = await ref.put(video);
if (!upload) return "";
const downloadUrl = await ref.getDownloadURL();
if (!downloadUrl) return "";
return downloadUrl;
};
I suspect you meant it to be an async function that returns (a promise of) downloadUrl:
const uploadTeaserVideo = async (event, video) => {

Related

How to catch Firebase promise in React?

I have a simple function that checks if the user has Premium access or not:
export const checkPremium = async () =>{
if (auth.currentUser) {
const q = query(collection(db_firestore, 'users'));
onSnapshot(q, (querySnapshot) => {
querySnapshot.forEach((doc) => {
if (doc.id === auth.currentUser.uid) {
return doc.data().userSettings.hasPremium
}
});
})
}
else{
return false
}
}
I tried to catch this in various ways, but no luck, it always returns an "undefined" object.
const getPremium = async => {
checkPremium.then((response) => console.log(response))
}
const getPremium = async => {
let hasPremium = await checkPremium()
}
let hasPremium = checkPremium()
What is the correct way to get the returned Boolean value?
onSnapshot is meant for listening to a collection continuously, getting repeatedly notified as its value changes. It does not create a promise, so the promise returned by getPremium is unrelated to the data you will eventually get in onSnapshot. If you just want to get the value once, you should use getDocs:
export const checkPremium = async () =>{
if (auth.currentUser) {
const q = query(collection(db_firestore, 'users'));
const querySnapshot = await getDocs(q);
const match = querySnapshot.docs.find(doc => doc.id === auth.currentUser.uid);
if (match) {
return doc.data().userSettings.hasPremium);
} else {
return false;
}
}
else{
return false
}
}
Also, instead of getting all the users and then using client side code to find the one with the right id, you could just fetch that individual doc directly:
const ref = doc(db_firestore, 'users', auth.currentUser.uid)
const snapshot = await getDoc(ref);
const data = snapshot.data();
if (data) {
return data.userSettings.hasPremium
} else {
return false
}

Waiting until image finishes upload to fire code

I am struggling to force code to be synchronous. The code is intended to upload an image using a vue composable, wait for the upload to succeed, then store the url from firebase storage into a database. The best I can do is get the code to function, but the success code fires before the upload is complete (though I get the url).
The code below does not work, but it's my attempt to try to chain the actions together using then callbacks to force them to behave in a synchronous manner. Not working.
VueComponent.vue
const newImage = async () => {
if (image.value) {
await uploadImage(image.value);
} else return null;
};
const handleSubmit = async () => {
try {
const colRef = collection(db, "collection");
newImage()
.then(() => {
addDoc(colRef, {
content: content.value
});
})
.then(() => {
//code to run only on success
});
});
} catch (error) {
}
};
useStorage.js composable
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import {
uploadBytesResumable,
getDownloadURL,
ref as storageRef,
} from "#firebase/storage";
const useStorage = () => {
const error = ref(null);
const url = ref(null);
const filePath = ref(null);
const uploadImage = async (file) => {
filePath.value = `${file.name}`;
const storageReference = storageRef(projectStorage,
filePath.value);
//<--I want this to be synchronous, but it isn't.
const uploadTask = uploadBytesResumable(storageReference,
file);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) *
100;
console.log("Upload is " + progress + "% done");
},
(err) => {
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL)
=>
{console.log("File available at", downloadURL);
});
}
);
};
return { url, filePath, error, uploadImage };
};
export default useStorage;
Your uploadImage doesn't wait for the upload to complete, so that's why the addDoc happens earlier than you want it to.
const uploadImage = async (file) => {
filePath.value = `${file.name}`;
const storageReference = storageRef(projectStorage,
filePath.value);
const uploadTask = uploadBytesResumable(storageReference,
file);
await uploadTask; // 👈 Wait for the upload to finish
const downloadURL = getDownloadURL(uploadTask.snapshot.ref)
return downloadURL;
}
Now you can call it with:
newImage()
.then((downloadURL) => {
addDoc(colRef, {
content: content.value
});
})
Or, by using await again, with:
const downloadURL = await newImage();
addDoc(colRef, {
content: content.value
});

Creating an continous increasing list using promise-pool and puppeteer

I need to create scraping tool using puppeteer however I have some issues adding items to the queue
What I got
const PromisePool = require("#supercharge/promise-pool");
const puppeteer = require("puppeteer");
const domain = process.argv[2];
let list = [];
list[0] = domain;
const run = async () => {
const { results, errors } = await PromisePool.for(list)
.withConcurrency(2)
.process(async (webpage) => {
links = [];
const getData = async () => {
return await page.evaluate(async () => {
return await new Promise((resolve) => {
resolve(Array.from(document.querySelectorAll("a")).map((anchor) => [anchor.href]));
});
});
};
links = await getData();
for (var link in links) {
var new_url = String(links[link]);
new_url = new_url.split("#")[0];
console.log("new url: " + new_url);
if (new_url.includes(domain)) {
if (new_url in list) {
console.log("Url already exists: " + new_url);
continue;
}
list[new_url] = new_url;
} else {
console.log("Url is external: " + new_url);
}
}
browser.close();
});
};
const mainFunction = async () => {
const result = await run();
return result;
};
(async () => {
console.log(await mainFunction());
console.log(list);
})();
The problem is inside
links = [];
const getData = async () => {
return await page.evaluate(async () => {
return await new Promise((resolve) => {
resolve(Array.from(document.querySelectorAll("a")).map((anchor) => [anchor.href]));
});
});
};
links = await getData();
page.evaluate is async and it doesn't wait for a return this links is never updated for the next PromisePool process.
I need a way to wait for response to return and then continue rest of the script to process.
You could use page.$$eval to retrieve the same links with a single await.
page.$$eval(selector, pageFunction[, ...args])
It is basically what you are trying to achieve as the $$eval method "runs Array.from(document.querySelectorAll(selector)) within the page [context] and passes it as the first argument to pageFunction." (docs)
E.g.:
const links = await page.$$eval('a', anchors => anchors.map(el => el.href));

get the return value from async function without calling it again

Here is the code:
const onStartRecord = async() => {
try {
const path = Platform.select({
ios: `file:///audio/${filenameGenerator}.m4a`,
android: `file:///audio/${filenameGenerator}.mp4`,
});
const audioSet: AudioSet = {
AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
AudioSourceAndroid: AudioSourceAndroidType.MIC,
AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
AVNumberOfChannelsKeyIOS: 2,
AVFormatIDKeyIOS: AVEncodingOption.aac,
};
console.log('audioSet', audioSet);
const uri = await audioRecorderPlayer.startRecorder(path, audioSet);
audioRecorderPlayer.addRecordBackListener((e: any) => {
setAudioProp(audioProp => {
return { ...audioProp,
recordSecs: e.current_position,
recordTime: audioRecorderPlayer.mmssss(Math.floor(e.current_position)),
}
});
});
console.log(`uri: ${uri}`);
return uri
} catch (err) {
console.log(err);
return;
}
};
const audioPath = async() => {
const result = await onStartRecord();
return result;
}
const onSubmit = async() => {
const audiopath = await audioPath();
console.log("this is the audiopath", audiopath)
}
};
I can get what I want when I trigger the onSubmit function, but the problem is, it also trigger the onStartRecord function again which will cause error in my case, I just want to get the uri generated when the onStartRecord resolved, but I don't want to trigger it again, so what can I do if I need to use the onSubmit function and get the value from onStartRecord? thx !
Instead of returning uri, onStartRecord should assign it to a global variable.
Then audioPath() can return that variable.
let savedAudioPath;
const onStartRecord = async() => {
try {
const path = Platform.select({
ios: `file:///audio/${filenameGenerator}.m4a`,
android: `file:///audio/${filenameGenerator}.mp4`,
});
const audioSet: AudioSet = {
AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
AudioSourceAndroid: AudioSourceAndroidType.MIC,
AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
AVNumberOfChannelsKeyIOS: 2,
AVFormatIDKeyIOS: AVEncodingOption.aac,
};
console.log('audioSet', audioSet);
const uri = await audioRecorderPlayer.startRecorder(path, audioSet);
audioRecorderPlayer.addRecordBackListener((e: any) => {
setAudioProp(audioProp => {
return { ...audioProp,
recordSecs: e.current_position,
recordTime: audioRecorderPlayer.mmssss(Math.floor(e.current_position)),
}
});
});
console.log(`uri: ${uri}`);
savedAudioPath = uri;
} catch (err) {
console.log(err);
return;
}
};
const audioPath = async () => savedAudioPath;

React JS - promise returns before execution completes. Async function does not work

I am trying to load data from firebase by calling a function in which it filters data and returns them.
When I call this function in my main function, it returns "undefined". I know the data is there (console.log(postsArray)) prints the data but I guess the return executes before data is loaded.
What am I doing wrong?
calling_Function_in_Main = async () => {
const data = await FirebaseData ();
console.log(data);
};
FirebaseData is the function that I call in my main function to load data and to return them
let postsArrays=[];
const FirebaseData = async () => {
const getViewableLink = async (link) => { //some function };
const loadData = async () => {
const database = firebase.database();
const data = database.ref();
const loadProfile = data
.child('Posts')
.orderByChild('Active')
.equalTo(true)
.once('value', function gotData(data) {
Object.values(readInfo).forEach(async (element) => {
element.Option1Link = await getViewableLink(
preLink + element.Option1Link,
);
postsArray.push(element);
}
});
})
.catch((error) => {
console.log(error);
}
})
.then((postsArray) => {
console.log(postsArray);
return postsArray;
});
};
await loadData();
};
export default FirebaseSwipeData;
You can't use foreach with async/await because It is not asynchronous. It is blocking.
you have 2 ways to fix this:
1- Reading in sequence: you can use for...of loop
for(const element of Object.values(readInfo)) {
element.Option1Link = await getViewableLink(
preLink + element.Option1Link,
);
postsArray.push(element);
}
2- Reading in parallel: you can use Promise.all
await Promise.all(Object.values(readInfo).map(async (element) => {
element.Option1Link = await getViewableLink(
preLink + element.Option1Link,
);
postsArray.push(element);
}));
Hope that solves the problem, for you

Categories

Resources