Firebase.createUser() - Create a return function [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I would like to create a simple function in Javascript that returns me the result of calling Firebase.createUser() dependent on onComplete.
I've done like this:
function createAUser(email, password) {
if (email === "" || password === "") { return false; }
var
onComplete = function (error, userData) {
if (error) {
switch (error.code) {
case "EMAIL_TAKEN":
console.log("The new user account cannot be created because the email is already in use.");
break;
case "INVALID_EMAIL":
console.log("The specified email is not a valid email.");
break;
default:
console.log("Error creating user:", error);
}
return false;
} else {
console.log("Successfully created user account with uid:", userData.uid);
return true;
}
};
MyFirebaseRootRef.createUser({ email: email, password: password}, onComplete);
/* return something here, true/false based on onComplete */
}
Or.. are there any other way to get me what I want. What I'm essentially after is just to find a way to figure out not only through console.log() how the creating of a user went.
Sorry for typos/bad code, thanks for all responses!
Edit:
Thanks for all responses I've now looked into the callback & the asynchronous stuff (something like starting another thread, and then follow through with the function). I must give it some thought over data, like the stack data in the function must be release upon return, how can this data be followed through to the callback.
Anyhow sorry for duplicate, thanks again

You're dealing with asynchronous data.
The call to create the Firebase user goes over the network, which means we have to patiently wait for the user to come back. But, we don't want to block the only thread we have to do other operations. This means the call will go on the JavaScript event loop and when the network request completes (and the call stack is clear), we will finally get our data back.
To handle this elegantly in code you can use a Promise.
var user = { email: 'my#email.com', password: 'secret' };
var promise = new Promise() {
function(resolve, reject) {
var ref = new Firebase('<my-firebase-app>');
ref.createUser(user, function(error, authData) {
if (error) {
reject(error);
} else {
resolve(authData);
}
});
}
};
promise
.then(function(authData) {
})
.catch(function(error) {
});
Promises are native to modern browsers, but if you want to support older browsers you'll have to use a library like jQuery, Bluebird, or RSVP.

onComplete is a callback. This means that your code is sending a request and when it is completed, onComplete is being called. When you call createUser, the request is being sent and is not completed, so at the line after calling createUser you are not able to get the result of onComplete, because the request is not finished yet. As a result, you need to handle the complete event inside the function you associated to it.

Related

Javascript fetch POST call doesn't wait for resolve [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I am working on a Python dashboard with FastAPI and Javascript. I have created a POST call returning an URL in FastAPI, which I am trying to fetch with Javascript and pass to the player. The output of this POST call is JSON. I am trying to assign the value of a certain key to the laURL variable. The problem is that even though I am using await and async function, Javascript is not really waiting for resolving the response and the second function is executed before the completion of the laURL assignment.
async function fetchLicense(playbackURL) {
try {
let response = await fetch(apiURL, {
method: "POST"
});
if (response.ok) {
let result = await response.json();
let laURL = JSON.parse(result).la_url;
return await laURL;
} else {
console.log("POST Error: ", response);
}
} catch (error){
console.log("POST Error: ", error);
}
}
And then I am using the returned value in another function:
function fetchSource(playbackURL) {
let laURL = fetchLicense(playbackURL);
const source = {
dash: playbackURL,
drm: {
widevine: {
LA_URL: laURL
},
immediateLicenseRequest: true
}
};
return source;
I have checked and tried a couple of different solutions, but nothing seems to be working.
This should be really something straightforward, but unfortunately, the solution isn't so obvious to me.
Javascript async/await is just syntactic sugar for using Promises. fetchLicense hence returns a promise. You can use Promise.then(/* callback */) to specify what should happen when data is resolved.
If you're unfamiliar with this, the following link might help you understand how it works exactly: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Execute promises when all resolved (as DB Transactions)

I have two promises that need to act as Transactions, if one of them fails, a "rollback" should occur.
For example: When I create a user I want to send a confirmation email, but what happens if there is an error on sending the email, the user will be created but will never get a confirmation.
await saveUser(user)
await sendEmail(user)
If I switch the order, what happens when something goes wrong on creating the user? It will get a confirmation.
await sendEmail(user)
await saveUser(user)
I thought a Promise.all will do the trick, but it doesn't.
await Promise.all([saveUser(user), sendEmail(user)]);
Is there a way to execute promises as transactions on Javascript? Promises should execute if and only if both of them resolve.
There is no built in 'transaction mechanism' in JavaScript like there is in some databases. You cannot go back in time to undo operations which you have already performed. If you wish to reverse the effects of saveUser when sendEmail fails, then you need to create another function, such as unsaveUser, and invoke it if sendEmail fails.
This can be done in the following way:
Using Promises:
saveUser(user)
.then(() => sendEmail(user))
.catch(err => {
if (err.message === "Email Error") { // Check the exception to determine if the email failed
unsaveUser(user);
}
});
// This will only send the email if 'saveUser' was successful, and call 'unsaveUser' if email fails
Same thing using Async/Await:
try {
await saveUser(user);
sendEmail(user);
} catch(err) {
if (err.message === "Email Error") { // Check the exception to determine if the email failed
unsaveUser(user);
}
}
For this example to work, in your async sendEmail function, you must throw new Error("Email Error"); upon detecting an error. If you are using resolve/reject, it would be reject(new Error("Email Error"));.
I hope this is clear to you and helps you resolve your issue.

Firebase / Cloud Function is very slow

I have a Firebase Cloud Function that does the following:
const firestore = require('firebase-admin')
const functions = require('firebase-functions')
const regex = require('../../utils/regex')
exports = module.exports = functions.https.onCall((data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.')
}
if (!data['displayName']) {
throw new functions.https.HttpsError('failed-precondition', 'An display name must be provided.')
}
if (!regex.noSpecialCharactersExceptSpace.test(data['displayName'])) {
throw new functions.https.HttpsError('input-validation-failed', 'Your display name cannot have special characters in it.')
}
return firestore.firestore().collection('profiles').doc(context.auth.uid)
.update({
displayName: data['displayName']
})
.then(() => {
console.info('Successful public profile update user='+ context.auth.uid)
return { text: 'Your profile has successfully been updated' };
})
.catch((error) => {
console.error('Error updating public profile user=' + context.auth.uid + ' error=' + error)
throw new functions.https.HttpsError('failed-precondition', 'An error happened, our team will look into it.')
})
})
From my front-end, when I call this function, it can take up to 20-30 seconds for it to complete and return a status code. This delay really disrupts the user experience.
What's the best way to improve the response time?
Testing
Direct calls to Firestore from the UI resolve incredibly quickly. Thus, it seems unlikely that the problem is DNS from our side.
Other API calls to Cloud Function from the UI, like "Invite a Friend", resolve quickly, and are not affected by this fault.
Calls to other Cloud Functions, which do not return a Promise, but do things like send emails with Postmark, are not affected by this fault and also resolve incredibly quickly. Thus, it seems that the problem isn't the location of the Firebase project (us-central1). Although changing the location hasn't been tested.
The fault only occurs on this one function. The one copied and pasted above.
The only difference between the affected function, and our other functions, is that the one with the fault returns a Promise for a Firestore operation.

Need clarification on calling Meteor methods asynchronously

So i've been doing some reading and I think I have a general grasp on this subject but could use some insight from someone more experienced. I've been trying to write a simple RSS reader in Meteor and have been facing some issues with calling the Meteor method asynchronously. I currently define the method on the server(synchronously) and call it on the client(asynchronously). What I don't understand is that when I try to make the HTTP.call on the server, I return an undefined value passed to my client if I pass a callback into the request. But when I make the API request synchronously everything seems to work fine. Is this the normal behavior I should expect/the way I should be making the API call?
Meteor.methods({
getSubReddit(subreddit) {
this.unblock();
const url = 'http://www.reddit.com/r/' + subreddit + '/.rss';
const response = HTTP.get(url, {}, (err, res) => {
if(!err) {
//console.log(res.content);
return res;
} else {
return err;
}
});
}
});
Here's the method defined on the server side. Note that logging res.content shows that I'm actually getting the right content back from the call. I've tried reading some other answers on the topic and seen some things about using Future/wrapAsync, but I'm not sure I get it. Any help would be greatly appreciated!
The HTTP.get is doing async work, so callback passed to it will be called out of this meteor method call context.
To get desired result you should do it like this:
Meteor.methods({
getSubReddit(subreddit) {
// IMPORTANT: unblock methods call queue
this.unblock();
const url = 'http://www.reddit.com/r/' + subreddit + '/.rss';
const httpGetSync = Meteor.wrapAsync(HTTP.get);
try {
const response = httpGetSync(url, {});
//console.log(response.content);
return response.content;
} catch (err) {
// pass error to client
throw new Meteor.Error(...);
}
}
});

simple user login validation module with node

I'm writing my first (non tutorial) node application and am at a point where I'm writing a function that should take the username and password as parameters and query them against the user table of my database to return either true or false. The database is setup, and the app is connecting to it successfully.
However, I haven't worked with SQL very much, nor node, and I'm unsure how to proceed with this function (and short surrounding script). Here it is:
console.log('validator module initialized');
var login = require("./db_connect");
function validate(username, password){
connection.connect();
console.log('Connection with the officeball MySQL database openned...');
connection.query(' //SQL query ', function(err, rows, fields) {
//code to execute
});
connection.end();
console.log('...Connection with the officeball MySQL database closed.');
if(){ //not exactly sure how this should be set up
return true;
}
else{ //not exactly sure how this should be set up
return false;
}
}
exports.validate = validate;
This is using node-mysql. I'm looking for a basic example of how I might set the query and validation up.
I think you'll want to rethink your app into a more node-like way (i.e. one that recognizes that many/most things happen asynchronously, so you're not usually "returning" from a function like this, but doing a callback from it. Not sure what you plan to get from node-mysql, but I would probably just use the plain mysql module. The following code is still most likely not entirely what you want, but will hopefully get you thinking about it correctly.
Note that the use of 'return' below is not actually returning a result (the callback itself should not return anything, and thus its like returning undefined. The return statements are there so you exit the function, which saves a lot of tedious if/else blocks.
Hope this helps, but I'd suggest looking at various node projects on github to get a better feel for the asynchronous nature of writing for node.
function validate(username, password, callback){
var connection = mysql.createConnection({ user:'foo',
password: 'bar',
database: 'test',
host:'127.0.0.1'});
connection.connect(function (err){
if (err) return callback(new Error('Failed to connect'), null);
// if no error, you can do things now.
connection.query('select username,password from usertable where username=?',
username,
function(err,rows,fields) {
// we are done with the connection at this point), so can close it
connection.end();
// here is where you process results
if (err)
return callback(new Error ('Error while performing query'), null);
if (rows.length !== 1)
return callback(new Error ('Failed to find exactly one user'), null);
// test the password you provided against the one in the DB.
// note this is terrible practice - you should not store in the
// passwords in the clear, obviously. You should store a hash,
// but this is trying to get you on the right general path
if (rows[0].password === password) {
// you would probably want a more useful callback result than
// just returning the username, but again - an example
return callback(null, rows[0].username);
} else {
return callback(new Error ('Bad Password'), null);
}
});
});
};

Categories

Resources