I have a component in React that receives 2 functions as props, they work pretty well. However, I need to call them one after another, as promises. By now I am calling them as:
this.props.function1();
this.props.functions2();
But they are called in parallel, I tried:
let whenfirst =this.props.function1();
whenfirst.then(this.props.function2());
But then I get: TypeError: whenfirst is undefined
I really cannot make modifications over function1, so how is the easy way to execute the function2 after function1 is completed?
EDIT: Sorry, I missed the crucial part where you said you can't change function1. Ignore the rest.
So I'm guessing function1 looks something like this
function function1() {
// make the POST call
someAJAXLibrary.post('someUrl', maybePostData);
// Do nothing.. post is doing its work and maybe
// you didn't care about the return
}
Which means you can't know when the POST call is done. But the library POST call probably does return a Promise (that's pretty standard), you just don't use it.
So instead do
function function1() {
return someAJAXLibrary.post('someUrl', maybePostData);
}
Now you can use it like you first thought, in your component.
let whenfirst = this.props.function1();
whenfirst
.then(useMeOrNot => this.props.function2());
Related
I know this question has been asked tens if not hundreds of times, but I turned google purple and still can't find an answer that suits my case.
I have a set of three functions that I need to call one from within the other, and need each function to finish before the one that calls it continues. Currently what happens is that a function would call another one, and then continue before the function it called finished.
Most of what I have seen says to use callback functions, my problem is that my inner most function is taken from a library, thus I can not adapt it to accept a callback function as a parameter. I also saw things on timeouts, but I do not want to force my code to wait any longer than it has to, I just want it to continue once the function it calls finished.
I just want everything to work synchronously, like I am used to from any other language.
To illustrate my current code, I am using three.js and this is (basically) what I have:
firstfunction(){
secondFunction();
}
secondFunction(){
var loader = new THREE.JSONLoader(); //loader is an object from three.js library
//loader.load is a three.js function that calls thirdFunction that I made. I can not make loader.load send a callback function to thirdFunction, as thirdFunction takes its arguments from three.js library
loader.load(url, thirdFunction);
}
thirdFunction(){ //this is a function that gets called from loader.load
//do stuff
}
I feel like I am missing something very trivial, but as I said I can't find anything online that fits my needs.
Any help would be greatly appreciated
Even if some libraries and apis allow you to do things synchronously, this is not how javascript should work. Even if you're used to this in other languages, javascript is different.
The answer to your question probably is 'this is not possible'.
Try to lean javascript the correct way, instead of making it behave like other languages.
However, there's some hope. Once you understand fully how callback works, and structure your code around that, you might realize that Promises is a better pattern that callbacks. Promises still need a sort of call-back and are still asynchronous, but it's easier to make your code easier to read.
Then once you fully understand promises, you might be able to use async and await. New browsers support this. These 2 keywords make a lot of your code 'look' synchronous like you're used to, but it's still asynchronous. It's pretty great.
Edit
I wanna address the follow sentence more directly:
//loader.load is a three.js function that calls thirdFunction that I made. I can not make loader.load send a callback function to thirdFunction, as thirdFunction takes its arguments from three.js library
Do you really need to send that third function another callback? What kind of callback is this? Is it just another function it should always call?
You can just call another function normally from your ThirdFunction. If you need it to be variable, you can probably just assign that function to a variable. Functions can access variables from their parent scope. For example:
var callback = '..'; // assuming this a callback.
thirdFunction(){
callback();
}
If only your second function knows what the callback should be, you might need to structure it like this:
secondFunction(){
var loader = new THREE.JSONLoader(); //loader is an object from three.js library
var callback = '...';
loader.load(url, function() {
thirdFunction(callback);
});
}
I'm reading over a legacy codebase and I ran into this following code:
andThenWe: function(callback) {
var qunitAssertAsync = new window.AssertAsync(callback);
return qunitAssertAsync;
},
and here's the call site:
andThenWe(function(done) {
...(some code)
done();
});
So in the call site, we're passing in an anonymous function which will then be === 'callback' right? However, this callback has an argument called done and seems to be called at the end of this function. That argument is kind of like a block parameter in Ruby right? So somewhere in the window.assertAsync the callback MUST be called and passed some kind of arugment which is probably === to Qunit's assert.async right? (most likely). The details of the window.assertAsync are really complicated so I just want to understand at a high level what must be going on. Am I making proper assumptions?
This is all possible because callback in the function signature is an anonymous function that be invoked at a later time right? Also done itself in the callback function must be a function itself at runtime right?
I think this is an attempt to make qunit.async more "readable" (haha).
qunit.async is used to force tests to wait until an async operation has completed before exiting the test.
The done callback must be invoked when the writer of the test knows everything async has completed.
I have some javascript functions being called on Document Ready:
fogFields();
getLoS();
getShips();
startGame();
getNextMove();
However, it is as though getNextMove() is being called first, most likely as all it does is an ajax call and alerts the result. All the other functions have more work, so, the first thing that happens on load is the getNextMove() alert, and in the background you can see that none of the other functions did their work. Until I click OK on the alert window, no results are shown. Can I make it so that until a function finishes, the next wont even start. Some functions call their own extra functions before they finish, and that works in order, but I cant do that with the whole code...
Given the code in your question, there is no way the call to getNextMove can be invoked before startGame has been exited, regardless of their contents.
It may be true that a function that has been scheduled asynchronously (via timeout, AJAX callback etc.) within startGame completes at any time before or after the invocation of getNextMove, but this is a separate issue. To resolve that issue we need to know more about the contents of the functions.
If the other functions have an AJAX call in them, then these AJAX calls most certainly take a callback argument, which is a function that gets executes, when the AJAX call has finshed. Now, if you want to execute your functions in a way, the one function starts when the AJAX call of the previous function finished, you can add an additional callback argument to your own functions, which will then be passed to the AJAX calls. This should illustrate what I mean:
function logFields(callback) {
ajaxCall(callback);
}
function getLoS(callback) {
ajaxCall(callback);
}
function getShips(callback) {
ajaxCall(callback);
}
function startGame(callback) {
ajaxCall(callback);
}
function getNextMove() {
}
fogFields(function(){
getLoS(function(){
getShips(function(){
startGame(function(){
getNextMove();
});
});
});
});
If all of your functions use a ajax call then just use promises.
Simply return it, for example:
function fogFields(){
return $.ajax();
};
and then just use .then:
fogFields().then(getLos());
more information about deffered object on jquery doc page if you use it.
Or implementation in pure javascript you can find here and more theory here.
or another option, which I will not recommend you is to set async param in $.ajax call to false. Again it's for case you use jQuery.
This is a newbie question: I have a pre-existing function that I would like to have call another function when it is finished, however, it does not accept a callback nor of course call one. I can modify this code to accept and call a function however this got me thinking about whether JavaScript supports doing this ... I would think it does but I've never had reason to find this out, I'm assuming it's necessary when working with libraries where we cannot change the code to our liking. Thanks.
The only time you need a callback is when you are doing something asynchronous, such as:
making an HTTP request (and waiting for a response)
animating something, one frame every time period until it is done
waiting for the user to click a button
All of these are considered "done" when something happens, but there is no generic way to determine when the something has happened. You need something custom for each one.
If you aren't waiting for something, then you can just call one function after the other (foo();bar();) and not need to fiddle around with callbacks.
So…
It might be possible to do what you want, but we can't tell you a generic way to achieve it.
This is a bit of a hack, and i'm sure there's tidier ways to do this with polymorphism, but you can treat the function as a variable and re-assign it somewhat:
Say you start with this function:
function originalFunctionName()
{
// do something
}
you can assign the existing function to a new name:
var backupOfOriginal = originalFunction;
then you can define a new function over the original name:
var originalFunctionName = function()
{
// do something else
// call backup function
backupOfOriginal();
}
then if you call the original function name:
originalFunctionName();
all the code will execute.
You can always create a new function which calls that function and provides you with opportunities to do something else before and after it is called. Underscore.js provides .wrap() to do exactly that sort of thing and return you a function you can call instead of the first function.
That just gives you a new function to call instead of your original function, if you want every spot that called the original function to get the new behavior instead, you could take advantage of JavaScript's prototypal inheritance to replace the original function with your new version of it.
Create a wrapper function that calls the original function, then one you pass in.
If the original function is an Ajax call and you're trying to replace one of its handlers, that's a different issue, though you might be able to use jQuery's $.when(original).then(function () { ... }) depending on your actual needs.
I'd like to do something like this:
var res = myAjax.post();
myAjax is basically my own ajax wrapper (asynchroneous). I don't necessary need the chaining, but i'd like to be able to do the call like shown above. I'd like a callback to be handled by the object itself. I've read about asynchroneous method queues, but, honestly, couldn't fully understand it. I know i could use a synchroneous ajax call, but it should be possible to do it asynchroneously as well if i understand it correctly. Any help is very appreciated. Thank you.
I've done a demo here that might be something along the lines of what you mean...
In that demo, there are two types of objects: MyAjax which has the 'post' method as above, and a MyRes object with a getData method that will return null until the async call has successfully completed. After it has completed, it will return the data fetched from the ajax call.
In the demo, I have a function checking for the response every second, but the post method also handles a callback which allows you to be notified when the ajax call has completed successfully.
I don't know why you'd want to do it this way, but it is doable.