I have a Dialog object that will show, well, dialogs. There are many entry points to show dialogs, e.g. yesNo(), message(), confirm(), etc. However, all these methods basically call the same other method, called showSimpleDialog(title, message, buttons).
I'd like all these methods (showSimpleDialog too) to return a promise, but there's a snag:
yesNo() {
return new Promise((resolve, reject) => {
axios
.get(......)
.then(this.showSimpleDialog(...));
}
}
As you can see, I am prevented in the above example from either returning the promise that showSimpleDialog would make or by passing the instanced Promise to showSimpleDialog.
The former is impossible because we're already in a different Promise by the time we have access to it. The latter because the Promise object itself is not yet available within the constructor. Well, technically, in this particular case it is (exactly because we're already in a different Promise), but some of my entry functions are synchronous, some asynchronous and I simply can't use the same code pattern to achieve the same effect in both cases.
I investigated the thing and I found this, but the author suggests the approach is flawed and archaic to begin with.
So, what would be the correct approach to return a functioning Promise from ALL entry points while the entry points would still be free to reusing each other's Promises?
If I understand correctly, this.showSimpleDialog(...) also returns a Promise, right?
If you want yesNo() to return the Promise retunred by this.showSimpleDialog(...)
yesNo() {
return axios
.get(......)
.then(()=>{
return this.showSimpleDialog(...);
});
}
That being said, consider using async/await, especially when dealing with multiple sequential promises, if possible.
Your code is calling this.showSimpleDialog immediately (synchronously) without waiting for any promise to resolve (the axios one). This is because the code doesn't pass a function to the then method, but instead executes this.showSimpleDialog. This execution returns a promise (presumably), but then expects a function as argument, not a promise.
So you need to make sure to pass a callback to then, and let that callback return a promise. This way promises will be chained:
.then(() => this.showSimpleDialog(...));
It is also important to make that callback an arrow function, since you'll be referencing this, which is intended to be the this on which yesNo is called.
Related
I just learned about promises and async/await.
I want my function to wait for some function inside to finish before proceeding.
Basically, I guess it should look something like this:
async function doSomething(data){
//some code
await createMarkup(data)
//do some stuff which must wait for createMarkup to finish
}
function createMarkup(input){
return new Promise ((???) => {
//some code
resolve(markup)
})
}
Now, in most of the tutorials I read about promises and stuff, the parameter of the "new Promise" was always "(resolve, reject)". This has been the case so often that I wondered whether this is some necessity?
In my case, the promise shall take exactly one argument. So can I just, like in any other parameter, put my one argument into the parameter and thats it? Or do I have to take care of somethign?^^
In my case, the promise shall take exactly one argument.
Promise will take one argument. That argument will be the function you want it to run. This is how Promise is defined. It is not something under your control.
The function you pass to the promise will receive two arguments. It is passed them when it is called, which is done by the Promise library (which is not code you wrote, and follows the specification for Promises, so it is not something under your control). It is traditional to call them resolve and reject, but you can call them whatever you like. The function you pass needs to call resolve(any_data) if it succeeds and reject(any_data) if it fails. If you don't intend to call reject, then you don't need to mention it in the argument list, the second argument will be passed to the function though.
You can create a function which returns a promise (like createMarkup in your example), which takes any arguments you like and makes them available to the function you pass to Promise via closures.
So that the caller of the function (the user of the service) can use .then if he wants to do something with the information the function generates. If he doesn't care when it gets done, as long as it gets done sometime, he can just call the function without any .then infrastructure.
Will this work? I don't want to get into a situation where it will work in my tests, but in some obscure situation that doesn't happen very often, it will fail.
Hmm. I guess what I mean is this. If I am writing the routine that returns the promise, I have to say:
return new Promise(function (resolve, reject) { ... });
If my caller doesn't say:
.then(function () { ... }, function () { ... });
what will happen? I will at some point call resolve() or reject(), and resolve and reject won't be defined. Does the Promise constructor supply some default (do nothing) definition?
I suppose if I am a crazy person, I can say in my callee function:
(resolve || function () {})();
A function that returns a promise will do what you'd like it to do.
Given a function B():
If the user does not chain B().then(), they will get the answer eventually whenever it is done. It is up to them to handle the fact that they don't know when the value is populated. That is to be expected.
If the user does chain B().then(), they will have a nice and easy way to control what happens once the value is returned.
You do not need to worry about weird edge cases. A function that returns a promise is a clear and straightforward contract.
As with all functions in Javascript, the caller is free to ignore a return value. The Javascript garbage collector will take care of objects or values that are no longer in use.
So, if the caller of some async operation that returns a promise really doesn't care when it's done OR if there are errors, then the caller is free to just ignore the returned promise. Nothing bad happens (other than the fact that you may never know there are errors).
The part of your question that does not seem to be cool with this is where you say: "If he doesn't care when it gets done, as long as it gets done sometime". If you are ignoring async errors, then this may not actually get done sometime and you may never know that. In this case, it might be more appropriate to do:
someAsyncFunc(...).catch(function(err) {
console.err(err);
// so something meaningful with the error here
});
Unless you specifically need to wrap a legacy API, using the Promise constructor is an antipattern. Use the Promise factories instead, or if using bluebird, see if you can use bluebird's promisify on the legacy function.
You also seem to be misunderstanding what the parameters to the Promise constructor function argument are. They are not the callbacks, they are the functions that settle the Promise. The Promise itself will worry about notifying any callbacks, if they exist.
Also, if your function sometimes returns a Promise, and sometimes does not, you might crash any code that assumes it can call .then on your function's return value. Don't do that.
If your computation may be async, always return a Promise. If you want to return a value that is already settled, then return Promise.resolve(theValue).
I want to pass the previously resolved, returned data and an additional parameter within a promise chain. See the example for clarification.
Below functions both return a Promise and are properly executed. It's really just about passing additional parameter.
Lets consider a Promise chain like:
API.getSomething(id).then(API.processIt)
getSomething function(id) { returns a promise with data }
processIt function(data) { process the returned data }
With a syntax like above it works fine. Once I add additional parameter:
API.getSomething(id).then(API.processIt(data, "random"))
processIt function(data, misc) {...} it does't work anymore.
Is there a way to pass additional parameters within a Promise chain using the result of the previous executed Promise without any additional library?
It's not about the design of the whole chain. I know, the problem could be bypassed with a different design but due to changes in some APIs that's the way I have to handle with the problem.
On this line
API.getSomething(id).then(API.processIt(data, "random"))
You are trying to pass function as reference but you are invoking the function instead.
Try
API.getSomething(id).then(function(data){
API.processIt(data, "random");
});
There are many questions on making a Nodejs/Javascript method synchronous, but the answers I have seen so far involved using libraries such as async and fibrous.
But to use libraries such as fibrous, I have to wrap my function with their wrapper.
I am seeking a solution where the code lies within my function (not outside and wrapping it).
For example, this is my async function which uses a callback:
function myFunc(callback) {
// Classic database fetch which is asynchronous
db.find("foo", function(err, results) {
callback(err, results);
});
}
What I want is for the function to return the results:
function myFunc() {
// Make this function synchronous, and return the result
// ...
return results;
}
How do I do that?
Once again, I don't want to wrap myFunc with other functions. I am thinking if a sleep loop works?
No, you can't use a loop to wait for an asynchronous call. Javascript is single threaded, so you need to return control to the main event handler for the asynchronous callback to be called. If you run a loop, the event that the database query is completed will just wait in the queue and never be handled.
What you can do is to return a promise instead of the result itself. That's an object that keeps track of whether the callback has been called or not, has a property where the callback can put the result, and has a method for getting the result when you need it (which uses a callback, because once you use an asynchrous method it can't be handled completely syncronously).
If you want an actual return value from an asynchronous function, you have no other choice than using either generators or Promises.
You will always have to wrap your functions, or return Promises directly.
One of the best promise libraries out there is bluebird, which also has an explanation for how and why to use it (https://github.com/petkaantonov/bluebird#what-are-promises-and-why-should-i-use-them). If you need to interface with node style callbacks or need to expose an API that relies on node style callbacks instead of promises, it also comes with some convenience methods for automating that conversion.
I am writing an asynchronous javascript function that will be called by consumers to get certain data. Following is the simple implementation that I wrote initially (error handing and other stuff removed for clarity).
function getData(callback){
if (data is available as a JavaScript object){
callback(data);
}else{
getAsyncData(function(data){
//some transformations on data
callback(data);
});
}
}
What is important to note is that getData can return data quickly if data is already available as a JavaScript object.
I want to replace this implementation with the one that returns a promise object to the caller. This fiddle shows sample implementation - http://fiddle.jshell.net/ZjUg3/44/
The question - Since getData can return quickly, can there be a possiblity where getData is resolving the promise even before caller has established handler chain using then method? Just to simulate this, in the fiddle if i call then method inside setTimeout function (with zero delay), callback doesn't get called. If i call the then method outside of the setTimeout function, callback gets called. I am not sure if this is even a valid concern or valid usecase. I am quite new to angularjs development and would appreciate your views :)
If you want getData() to return a $q promise instead of using a callback, I'd do the following refactor using $q.when() and usual $q.resolve():
function getData()
{
if (data is available as a JavaScript object) {
return $q.when(data); // resolves immediately
} else {
var q = $q.defer();
getAsyncData(function(data){
//some transformations on data
q.resolve(data);
});
return q.promise;
}
}
No, a significant and important part of being a promise is that it doesn't matter when you attach the handler. Even if you create a promise now and resolve it immediately, then keep your computer running for the next 50 years, then attach a handler it will still fire.
All of this does assume that there isn't a bug/corner case in angularjs's promise implementation. If it doesn't work, it's a bug though.
If you ever need to know anything about how promises work, you can always refer to the Promises/A+ spec which angular adheers to. As a spec, it's one of the simplest and easiest to understand that I've come across (although I should mention that I've been involved in the spec for quite a while now).