I know this is a highly answered topic, but reading tons of posts I can't figure if my dilema has a solution as I want.
I want to write a simple function that returns the User Name passing the UserId. It will be used everywhere to multiple purposes.
function getUserName(userId) {
//...some code to retrieve the Name from a REST webservice like $.ajax or $.getJSON or anything else that helps me achieve my need
return name;
}
$('#txtUserName').val(getUserName(sessionStorage.userId));
//...
if (getUserName(sessionStorage.userId) == getUserName($('#inputUser').val())) {
alert('Error: User typed with the same name as '+ sessionStorage.userID);
}
I know that can rewrite it all to put callback's or whatever, but I want to know if there's any implementation that makes possible to write this simple function that returns a value from a PHP webService.
I imagine a function like this:
function getUserName(userId) {
var users ={
'me': 'Seak Oink'
, 'you': 'Who knows'
, 'jd': 'John doe'
};
return users[userId];
}
...but instead of having the fixed users object, i retrieve it from my php webService that gets it from a DB.
Using a callback, makes impossible to handle values. For example (if I'd use callback and assuming calling getUserName(userId, callback) handles the function call):
$('#txtUserName').val('');
getUserName(sessionStorage.userId, function(userName) {
$('#txtUserName').val(userName);
});
if ($('#txtUserName').val() == '') {
alert('user '+ sessionStorage.userId +' doesn't exist');
}
Instead, you could answer me to put it into the callback, but if need to call again my function, I must nest it to a callback again and again... I think it's a bad programming practice:
$('#txtUserName').val('');
getUserName(sessionStorage.userId, function(userName) {
$('#txtUserName').val(userName);
getUserName($('#inputUser').val(), function (userName2) {
if (userName2 == userName) {
alert('Error: User typed with the same name as '+ sessionStorage.userID);
}
//....here I must continue the code flow instead of continuing to caller's flow.
//...nesting, and more nesting... impossible to read code?¿¿?:
userpermission(userId, function(bAllowed) {
if (bAllowed) {
saveRecord(userId, sKey, sSomeText, function () {
alert('record saved -or not-');
// ...and continue nesting
});
} else {
alert('forbidden');
}
});
});
});
... instead of this simple code flow logic:
var lOk = false;
$('#txtUserName').val('');
$('#txtUserName').val(getUserName(sessionStorage.userId);
if ($('#inputUser').val() == getUserName($('#inputUser').val())) {
alert('Error: User typed with the same name as '+ sessionStorage.userID);
}
if (userpermission(userId)) {
lOk = saveRecord(userId, sKey, sSomeText);
} else {
alert('forbidden');
}
if (lOk) {
alert('record saved');
}
// ...continue the validation process or whatever
I understand the simple example of retrieving a value with a callback, but don't using it in code logic.
I've been read How do I return the response from an asynchronous call? and much more like that and understood, but I can't uderstand how to use retrieved values from different sources and apply the necessary logic. Basicly, how to order the chaos?
Looks like you're experiencing callback hell.
That happens when you have several asynchronous functions and you need to handle all their errors and success.
That's exactly for that case that promises have been invented.
If you don't have ES6, have a look on jquery promises, otherwise they are built-in : ES6 promise
They allow more readable, synchronous like code.
For example, you can do code like that:
$.when( // waits for two promises to be resolved
getUserName(userId)
.then(function(name) { // once name resolved, fetch profile (new promise)
return getUserProfile(name);
}),
getUserPoints(userId) // another independent promise
).done(function(userProfile, userPoints) { // the two above are done, I can move on and update the DOM
$("#profile").doSomething(userProfile);
$("#points").doOtherThing(userPoints);
});
Related
output = true;
if($("#password-field").css('display') != 'none') {
if(!($("#verificationCode").val())) {
output = false;
$("#code-error").html("required");
}
var codeverify = function(){
var code = document.getElementById("verificationCode").value;
coderesult
.confirm(code)
.then( function(result) {
if (result.user.uid) {
let phoneNumber = result.user.phoneNumber;
//alert(output);
alert("Verification done");
console.log(phoneNumber);
} else {
alert(output);
$("#code-error").html("no user");
output = false;
}
})
.catch(function(error) {
output = false;
$("#code-error").html("wrong");
alert(error.message);
});
}();
}
return output;
When i run this code everything works fine. but before checking the codeverify function it return the output to true even if the codeverify() function returns false
PS. I am using wizard form.
This comes down to how you write JavaScript code, I found that usually when to get to a point where my procedures are out of sync it means that I have done something wrong in previous steps. This is usually only fixed by refactoring.
Remember JavaScript does not behave the same as other languages.
What I can see from your procedure is that you are trying to do many things in one go.
Although I do not have a solution I have a suggestion, consider each action that you want your procedure to execute. Declare a separate function for each of these steps, even if your function only has one line to execute.
If there are dependencies make sure they can be resolved by parameterization.
And lastly, think pure functions. Try and structure every function to receive something and return something.
Another tip that I can give is, write your procedure to select and hold elements in variables until they are required. Consider what elements are required in execution, which of those are in the dom when execution starts and set them to variables before you start executing, then during execution if elements are added that are maybe required for later select them immediately after they are placed in the dom, this means that as your procedure executes all the ingredients are available to do whatever must be done they don't have to go find what they need on the fly.
Good Luck and happy coding.
Your coderesult.confirm(code) using promise(then & catch) so i assume it is asynchronous. You need to google yourself to learn what is async
One important thing of JS behavior is JS always process the rest of the code if there is a async function in between.
Sample:
console.log(1)
setTimeout(()=>{
console.log(2,"i suppose at position 2 but i'm at the last. This is because setTimeout is async function")
},1000)
console.log(3)
In your case, your codeverify function has async code (.confirm()) in between, so JS will process the code after codeverify (return output)until codeverify is fully completed.
Since your output was set at true since the beginning, it will return true from the last row of code return output before your codeverify completed, this is why you always get true. If you change the first row output = undefined, i believe you will see undefined result.
To solve this, one of the way is you can wrap the entire codeverify as Promise.
function codeverify(){
return new Promise((resolve,reject)=>{
var code = document.getElementById("verificationCode").value;
coderesult.confirm(code).then( function(result) {
if (result.user.uid) {
let phoneNumber = result.user.phoneNumber;
//alert(output);
alert("Verification done");
console.log(phoneNumber);
output = true
resolve(output)
} else {
alert(output);
$("#code-error").html("no user");
output = false;
resolve(output)
}
}).catch(function(error) {
output = false;
$("#code-error").html("wrong");
alert(error.message);
reject(output) //you can reject(error.message) so you can pass error message back.
});
})
}
You can execute the function like this:
codeverify().then(successData=>{
console.log(successData) //from what you resolve
}).catch(failedData=>{
console.log(failedData) //from what you reject
})
Lastly, take some time to study what is Asynchronous and What Promise to do with Async because it is everywhere in JS.
I have a js file called example.js which has a line as follows:
gridOptions.api.setRowData(createRowData());
Then there's another file data.js which has the createRowData() function that should return ROW_DATA. It is as follows:
function createRowData() {
jQuery.getJSON('/file.txt',function(ROW_DATA){
return ROW_DATA;
});
}
But, whenever this createRowData() function is called from example.js file, it does not go inside the jQuery block and simply comes to the last curly bracket. Can anyone please tell me what is going wrong here??
I believe that you're not getting the value because getJSON is asynchronous as others have said. createRowData is retrieving the value at a later time rather than when it's called.
Here is one way to get the data with promises. I commented what's going on below:
function createRowData() {
//return a new promise
return new Promise(function(resolve, reject){
jQuery.getJSON('/file.txt',function(ROW_DATA){
//on reject, send an error
if (ROW_DATA === null) reject("Error fetching data");
//on resolve, send the row data
return resolve(ROW_DATA);
});
});
}
//use then to describe what happens after the ajax request is done
gridOptions.api.setRowData(createRowData()).then(function(rowdata){
return rowdata; //log data or error
})
Edit: to do a synchronous ajax request, you may be able to do something like this, referring to this SO question.
function createRowData() {
$.ajax({
url: "/file.txt'",
async: false,
success: function(rowdata){
return rowdata
}
})
}
To read some data to a variable like you mentioned, nodejs may help because it can handle reading input/output, and probably to a variable as well.:
You get JSON from the file, pass the result to the callback function, and then return it. Return it where??
As I said, your anonymous function is a callback one.
Program says: When you are done reading from the file, call this function, OK?.
While you do that, I am doing something else.
And that is what it does. The program, would go on, until the file is read, when your callback anonymous function would be called.
You can do sth like this.
createRowData(gridOptions.api);
// add code here if you want this code to execute even before you get the response
function createRowData(api) {
jQuery.getJSON('/file.txt',function(ROW_DATA,api){
api.setRowData(ROW_DATA);
//Whatever else you want to do. In case you want this to be done only
//after the values have been read
});
}
If you want to wait, for the file to be read, just, dont do anything after the function, but put it inside the callback function.
I want to package a ajax call into an interface without then.
If i do like this, it will just return 'No ajax return';
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax return';
// get fileName using an ajax get
$.ajax();
return text;
}
If i do like this, it will be ugly for using then;
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
I just want the interface to be simple and return the right thing, can i?
//return the right
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
Whoa, what is all that? You do need .then but you don't need most of the surrounding stuff. $.ajax generates a promise for you. You don't need to make a promise object yourself. In fact, often the only reason you need to manually set up a Deferred/Promise directly is if you're using some library that sets up callbacks and doesn't use promises itself.
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(data) { ... });
Now, let's say that you didn't actually want to return the JSON structure on the end of the ajax function; you want to take out just a number from inside of it, or tweak one value to make it an easier-to-use function for its callers. Easy enough:
function ajaxFunction(){
return $.ajax().then(function(data) {
return data[12].number;
}
}
ajaxFunction().then(function(number) { ... });
In direct answer to your question: No, what you asked for isn't possible. Whenever your JavaScript methods are running, the browser can't process other events like clicks and even basic scroll operations. So, any long-running operations (like contacting the server) do not return straight away, and instead offer a callback operation.
Well..., ajax is asynchronous so you either use .then() or use a callback logic... Doing synchronous ajax is not a option for me, so I won't even mention it.
The alternative to .then() would be something like this:
ajaxFunction(function(res){ // pass a function into it
// this will be called when the ajax is done
alert(res);
});
function ajaxFunction(callback){
// get fileName using an ajax get
$.ajax({
success: callback
});
}
But again, maybe you can use just a normal ajax callback pattern anyway
$.ajax({
...
success: function(res){
// use the res
}
});
Ajax is asynchronous. then is designed to make writing async operations look more similar to synchronous code and can actually be very elegant.
Additionally, $.ajax() returns a promise and is well suited to be written as follows:
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(response){
// do whatever you want with the response
})
You simply can't write asynchronous code that way (ajaxResult = ajaxFunction()). The interpreter is going to keep trucking along line by line and ajaxResult will not be ready in time.
Read up on chaining $.Deferred's. It will really clean up your async code.
I have two functions one of which includes multiple json call which are post by nature.
I want these to be synchronous. That is, one should run only upon the completion of the previous post (and if all posts are done and successful I want the second function to fire).
The code structure is somewhat like this:
$.getSomeData = function() {
$.postJSON("iwantdata.htm",{data:data},function(data)){
});
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
});
});
$.useSomeData = function() {
});
The useSomeData must work upon subsequent json calls.
Can anyone please help me? Thanks in advance.
So basically you want something like this:
function chainPost(url1, url2, initialInput, func) {
$.post(url1, {data: initialInput})
.done(function (initialOutput) {
$.post(url2, {data: initialOutput})
.done(function (secondOutput) {
func(initialOutput, secondOutput);
});
});
}
chainPost("iwantdata.htm", "iwantmoredata.htm", 0, function (first, second) {
alert(first);
alert(second);
});
You can just nest them, starting the 2nd one in the completion function of the first and so on:
$.getSomeData = function() {
$.postJSON("iwantdata.htm",{data:data},function(data) {
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
// use the data here
});
});
};
When dealing with asychronous functions, you cannot write code such as:
$.getSomeData();
$.useSomeData();
By definition, the first is asynchronous so it will not have completed yet with the second function is called and javascript does not have the ability to stop JS execution until an asynchronous operation is done.
You could pass your use function to the get function and then it would get called when the data was available as an addition to the above example like this:
$.getSomeData = function(fn) {
$.postJSON("iwantdata.htm",{data:data},function(data) {
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
fn(data);
});
});
};
Then, you'd have a getSomeData(useFn) function that would take an argument of the function to call when all the data was ready.
Deferred objects [docs] are perfect for this. Unfortunately, your code example contains syntax errors and it is not clear how the calls are nested. So, I'm not sure if you want to run both Ajax calls after one another or parallel, but either way is possible.
Here are two examples. Have a look at the documentation for more information and play around with it.
Note: .postJSON is not a built in jQuery method, I assume here that you are returning the return value from the $.ajax (or $.post) function.
Parallel Ajax calls:
$.getSomeData = function() {
var a = $.postJSON("iwantdata.htm", {data:data});
var b = $.postJSON("iwantmoredata.htm", {data:data});
// return a new promise object which gets resolved when both calls are
// successful
return $.when(a, b);
};
// when both calls are successful, call `$.useSomeData`
// it will have access to the responses of both Ajax calls
$.getSomeData.done($.useSomeData);
See: $.when
Chained Ajax calls:
... where the response of the first call is the input for the second one. This is only an example, of course you can pass any data you want.
$.getSomeData = function() {
return $.postJSON("iwantdata.htm", {data:data}).pipe(function(response) {
// execute the second Ajax call upon successful completion
// of the first one
return $.postJSON("iwantmoredata.htm", {data:response});
});
};
// if both Ajax calls are successful, call `$.useSomeData`
// it will have access to the response of the second Ajax call
$.getSomeData.done($.useSomeData);
See: deferred.pipe()
If you have a more complex logic, you can also create, resolve or reject your own deferred objects. Have a look at the examples in the documentation.
Coming from a c# background, I'm probably looking at JavaScript from a completely wrong perspective, so please bear with me.
Leaving the advantages of async aside for a minute,
let's say I simply want to retreive a value from an SQLite database in an HTML5 page.
What I want to see is something like
var something = db.getPicture(1);
Now consider a (perhaps very naive) implementation of this:
this.getPicture(id)
{
this.database.transaction(function(tx)
{
tx.executeSql('SELECT ......', null, function(tx, results)
{
if (results.rows.length == 1)
return results.rows.items(0).Url; //This of course does not resturn
//anything to the caller of .getPicture(id)
}
},
function(error)
{
//do some error handling
},
function(tx)
{
//no error
});
}
First off, it's one big mess of nested functions and second... there's no way for me to return the result I got from the database as the value of the .getPicture() function.
And this is the easy version, what if I wanted to retreive an index from a table first,
then use that index in the next query and so on...
Is this normal for JavaScript developers, am I doing it completely wrong, is there a solution, etc...
The basic pattern to follow in JavaScript (in asynchronous environments like a web browser or Node.js) is that the work you need to do when an operation is finished should happen in the "success" callback that the API provides. In your case, that'd be the function passed in to your "executeSql()" method.
this.getPicture = function(id, whenFinished)
{
this.database.transaction(function(tx)
{
tx.executeSql('SELECT ......', null, function(tx, results)
{
if (results.rows.length == 1)
whenFinished(results.rows.items(0).Url);
}
},
In that setup, the result of the database operation is passed as a parameter to the function provided when "getPicture()" was invoked.
Because JavaScript functions form closures, they have access to the local variables in the calling context. That is, the function you pass in to "getPicture()" as the "whenFinished" parameters will have access to the local variables that were live at the point "getPicture()" is called.