Promises - difference between passing resolve function and wrapper function [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
I have Node.js application. Why these two code fragments do not work in the same way?
1)
function myFn1() {
return new Promise(function(resolve, reject) {
myFn2().then(function(url) {
resolve(url);
});
});
}
2)
function myFn1() {
return new Promise(function(resolve, reject) {
myFn2().then(resolve);
});
}
Common:
function myFn2() {
return new Promise(function(resolve, reject) {
var url = 'example.com';
resolve(url);
});
}
I call it with
myFn1().then(function(url) {
console.log(url);
});
With code 1) url is passed properly, but with code 2) url is undefined.
Do I not pass one-argument function in both cases? What is the difference?

First off, avoid the promise anti-pattern. When you already have a promise, just use it and return it. Don't wrap it in a new promise. Besides being inefficient, it's real easy to make mistakes, particularly with error handling (which you have).
So, what you should be doing is this:
function myFn1() {
return myFn2().then(function(url) {
// do some modification to url and then return that
// or some other processing here
return url;
});
}
There is simply no need to wrap the returned promise from myFn2() in another promise. In your specific case when doing so, you silently ate any errors from that inner promise and they were not propagated to the caller of myFn1() which is nearly always a bug, sometimes a very serious bug.
And, if you really have nothing to do inside the .then() handler, then you don't even need it either:
function myFn1() {
// some code here
return myFn2();
}
As to the original question, your two code fragments 1) and 2) work the same way and have no meaningful behavior differences other than one makes an extra function call and uses a little more stack to do so.
When you do this:
myFn2().then(resolve);
You're telling .then() to call resolve with whatever argument would normally be passed to the .then() handler. Since that argument in your case is url, then:
.then(resolve);
is exactly the same as:
.then(function(url) {
resolve(url);
});
They both call resolve with exactly the same argument. The first is a shorthand and should be used when the argument that .then() will use for it's callback is exactly the argument you want to your function. The second should be used if the arguments for your function are not exactly the same or, obviously, if you have more than a single function call to do in the .then() handler. So, if you wanted to add a ".jpg" extension to the URL before calling resolve, then you'd have to do:
.then(function(url) {
resolve(url + ".jpg");
});
With code 1) url is passed properly, but with code 2) url is
undefined. Do I not pass one-argument function in both cases? What is
the difference?
Assuming the promise returned by myFn2() resolves to url, then there should be no difference between your scenario #1 and #2. The promise returned by myFn1() should resolve to the same value either way.
Now, if you put some code in a .then() handler and forget to return the desired value from that .then() handler, then the resolved value of the promise becomes undefined which may be what is happening in your real code. So, if you do this:
function myFn1() {
return myFn2().then(function(url) {
console.log(url);
});
}
myFn1().then(function(url) {
console.log(url); // will be undefined
})
Because you didn't return anything from the .then() handler inside of myFn1. That means the return value is undefined so the promise took on that return value. Just remember, if you want your promise to have a specific resolved value, you have to return it from any .then() handlers in the chain.
function myFn1() {
return myFn2().then(function(url) {
console.log(url);
return url; // make sure the promise retains this resolved value
});
}

Related

How to use JavaScript Promise with conditional logic and store into local variable before returning?

I would like to involve more logic than just return new Promise(...); from a function. I'm not sure if storing a Promise into a variable is changing the "synchronicity" behind it, as every example I've seen does not do that. I would also like to store a Promise into a variable in general to return at the end, even when I'm not involving conditionals, as it just seems bad for debugging and in general to have all the logic reside in a return statement.
function doSomething(){
var promise_var1;
if (condition){
//Do something async, like an AJAX call to an API
setTimeout(function(){promise_var1 = Promise.resolve('a')}, 3000);
}else{
//Do something synchronous, like setting a default value
promise_var1 = Promise.resolve('b');
}
return promise_var1;
}
doSomething().then(function(value){console.log('c'+value)});
I'm currently getting
doSomething() is undefined
however I've tried various ways so I may be misunderstanding something conceptually.
Edit: "Duplicate" question is asking how to handle conditionals inside a promise. I'm asking how to return promises via variable (to achieve single exit). That may not be possible because JavaScript is weakly typed and Promise variable return vs. Promise return may behave differently, but if there is a solution to do that I would prefer single-exit over multiple returns.
Try writing your promise like this.
function doSomething(condition){
var promise_var1= new Promise(function(resolve, reject) {
if(condition){
//resolve after your async action
setTimeout(resolve('a'), 3000);
}else{
//resolve immediately
resolve('b');
}
});
return promise_var1;
}
To answer your question simply: Yes. You can absolutely store a promise in a variable. This is exactly why we have promises. It allows us to "store" a value that may not exist yet, so we can easily pass it around to other parts of the program.
Ultimately you still need to call a callback to get at the internal value, either with .then or with the overly-sweet sugar of async/await. But until you are ready to define your callback, you can pass that future-value around just like any other value.
However, in your example, I don't think the use of a temporary variable does anything to improve the logic or readability of your code. (And in fact, it doesn't work at all, because your if doesn't add a promise to the returned variable until 3 seconds later, after .then has already been called.) Just make sure that every branch of your conditional returns a promise, and you're good to go.
function doSomething(condition){
if (condition){
//Do something async, like an AJAX call to an API
return new Promise(resolve => {
setTimeout(() => resolve('a'), 3000);
})
}
//Don't actually need an else because if condition returns.
//Do something synchronous, like setting a default value.
return Promise.resolve('b');
}
doSomething(true)
.then(value => console.log('c ' + value));
doSomething(false)
.then(value => console.log('c ' + value));
Why make it complicated?
let doSomething = condition => condition ? somethingAsync() : Promise.resolve('b');
function always returns a Promise you can .then whether it resolves in one turn of the event loop or 3 minutes
Update
here's a version with one return and the branch inside the Promise
let doSomething = condition => {
return new Promise(resolve => {
if (condition) {
resolve(someAsyncThing());
} else {
resolve('b');
}
});
};
I would still argue that it's less readable and simple than the version above, but it's your codebase, YMMV.

Optional Promise API

I have a validation library that is purely synchronous but is often used as part of a chain of async functions. However, I have to maintain an existing synchronous API and would like to make the promise API optional.
Can I somehow detect (at runtime) whether a function is part of a Promise chain?
This is pretty easy with callbacks since you can just check if a callback was passed in. I understand that I could pass in an optional promise boolean, but that seems inelegant.
I've also considered doing a callback interface and using a library to convert the callback interface to a promise based interface on the fly. However, I'm working in Haxe and I would prefer to keep the transforms/abstractions down to a minimum.
I also understand that you can sandwich regular functions in-between promises, but there are some instances where the behavior would differ between the two.
FINAL Edit Lots of confusion as to why I can't just return the same values, first example (below) didn't seem to help. Remember, this is still simplified.
//mix of sync with promise
new Promise(function(resolve, reject){
var safeToAdd = thingTracker.preflight(newThing);
if(safeToAdd){
return client.request.addThing(newThing); //send request to server
} else {
reject(newThing.errorMessages); //requires explicit reject, cannot just pass results along
}
}).then(function(newThing){ //client and server both cool with newThing?
thingTracker.save(newThing);
}).catch(function(errorMessages){ //handles errorMessages from client and server
ui.show(errorMessages);
});
//pure promise
thingTracker.preflight(newThing).then(function(){
return client.request.addThing(newThing); //sends request to server
}).then(function(newThing){ //client and server both cool with newThing?
thingTracker.save(newThing);
}).catch(function(errorMessages){ //handles errorMessages from client and server
ui.show(errorMessages);
});
(Old) Edit to clarify (but didn't really):
function preflight(thing){
var validity = thing === 42;
if(promise){
if(validity){
return Promise.resolve(validity);
} else {
return Promise.reject(validity);
}
} else {
return validity;
}
}
Obviously I can do the same checks in a then's anon function, but that is not much better than using the sync interface directly. Also note that this is a very simple example, in the real function there are side effects on thing and messages are produced.
Edit Just to illustrate my point a bit better, here is a gist of what things look like.
Synchronous functions can be used within a promise chain just fine. If you have a synchronous API call that is called like this:
var info = myApi("foo");
That can be used just fine within a promise chain:
someAsyncCall().then(myApi).then(someOtherFunction)
You don't need to make myApi async or return a promise to be used this way. The only thing you can't do in a promise chain with a synchronous function is that it can't be the first item in the chain, but then it doesn't need to be. Since it's synchronous, it can just be called before you start the chain if anyone wants it to execute first. Or, worst case, you can do:
Promise.resolve().then(myAPI).then(someOtherFunction);
Can I somehow detect (at runtime) whether a function is part of a
Promise chain?
No, you cannot (unless you explicitly pass it some info that tells it that) and you do not need to in order to use it in a promise chain. You do not need to return a promise to be a .then() handler. You can just return a value and that value will become the value of the promise chain at that point in the chain.
I also understand that you can sandwich regular functions in-between
promises, but there are some instances where the behavior would differ
between the two ... such as returning false vs throwing a message.
It is not clear to me why the behavior would have to be different. If returning false is your normal synchronous behavior, you can do that just fine in a promise chain - the next step in the chain just needs to handle the false value that is passed to it, just like the next line of synchronous code would do. If throwing an exception is your normal behavior, you can do that just fine in a promise chain too (the promise chain will turn the exception into a rejection) which the following code can decide how it wants to handle. One can make a good argument that it would be worse if your synchronous function behaved differently based on whether it was part of a promise chain or not. If you see a good reason for two different behaviors, then you should probably have either two different functions (that can be documented differently) or an option passed in that determines the behavior.
Comment based on the code you added in your edit
You seem to think that when called via a promise chain that you need to return a resolved or rejected promise chain. You do not need to do that. You can just return a normal value and the promise chain will inherit the value you return. There is really no reason to return a resolved or rejected promise unless you want it to be the first function in a promise chain, but in that case, it isn't in a promise chain yet anyway so you could never detect that. And, there's no reason for a synchronous operation to be the first one in a promise chain. Just call the synchronous operation first and then initiation your promise chain with the async operations.
Here's a demo of a synchronous function being used in a promise chain:
function log(str) {
var div = document.createElement("div");
div.innerHTML = str;
document.body.appendChild(div);
}
// test async call
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}
function square(x) {
return x * x;
}
log("Calculating the square of 9");
delay(500, 9).then(square).then(function(result) {
log("Result = " + result);
});
Or, you can even do this to initiate a promise chain with your synchronous operation as the first operation in the chain:
function log(str) {
var div = document.createElement("div");
div.innerHTML = str;
document.body.appendChild(div);
}
function square(x) {
return x * x;
}
log("Calculating the square of 9");
Promise.resolve(9).then(square).then(function(result) {
log("Result = " + result);
});
I believe promises have only one argument so it's not possible to pass an isPromise boolean through the chain, even if you could, you'd have to consciously add the parameter, so why not just call the async function...
function preflight(thing){
return thing === 42;
}
function preflightAsync(thing){
return new Promise(resolver);
function resolver(resolve,reject){
setTimeout(function foo(){
preflight(thing) ? resolve(true,"this won't make it") : reject();
},1000);
}
}
// Promised
preflightAsync(42).then(doSomethingWithIt).catch(doSomethingWithIt);
preflightAsync(89).then(doSomethingWithIt).catch(doSomethingWithIt);
// Call Directly
doSomethingWithIt(preflight(42));
doSomethingWithIt(preflight(89));
function doSomethingWithIt(result,nada){
result = result ? "BAM!!!" : "WAM!!!";
console.log("doSomethingWithIt",result,nada);//doSomethingWithIt BAM!!! undefined
return result;
}
These examples use the new native Promise function, browser support is limited.
As we can see from previous answers you can't use exactly the same function also for Promises. Adding my workaround here which is unfortunately extending the function prototype ...
The problem is that if you want to use the same function synchronously and in a Promise the use of arguments would differ.
As an example - a function truncating a string:
sync:
truncate('A very long string coming from a sync. operation', 10);
async:
Promise.resolve('A very long string coming from a network request')
.then( truncate(10) )
The async version would make the truncate Function think that 10 is the string and you would need to check typeof in every function or do ducktyping.
What would work:
Promise.resolve('A very long string coming from a network request')
.then( truncate.it(10) )
if you extended the function prototype before:
Function.prototype.it = (function() {
return function() {
var args = arguments;
return function(){
Array.prototype.push.apply(arguments, args);
return this.apply(null, arguments);
}.bind(this);
};
}());
function foo(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
};
// LOGIC :
foo(1, 2, 3);
// SAME AS
foo.it(2, 3)(1);
// OR
foo.it(3)(1, 2);
// OR pretty useful for .then()
Promise.resolve(1).then(foo.it(2, 3));
fiddle

What is the use of the .then function in javascript? [duplicate]

This question already has answers here:
jQuery deferreds and promises - .then() vs .done()
(11 answers)
Closed 7 years ago.
There is not much answer for this simple question that I have. My main question is that I have seen the .then method used a lot in JavaScript and I know the main thing where randomobject.then(//This returns success, //this returns failure). But there are things that I don't get such as the code here:
var success = function (response) {
return response.data;
};
var error = function (errResponse) {
$log.error(errResponse.data.Message);
};
function getsomeData() {
var url = baseUrl + 'api/somedata';
return $http.get(url).then(success, error);
}
First off in that code I'm wondering how the var success knows what data it is getting and the same with error. It says response.data but what is response? It's probably the result of the http.get but that doesn't make much sense code wise. Also it seems that when I have a function for example.
getsomeData returns what it returns. Why doesn't it work if I do the ff:
var dataHolder = randomAngularService.getsomeData()
it returns an object that holds a data under $$state but somehow the .then makes it work if you do the ff:
randomAngularService.getsomeData().then(function (response) {
if(response != null) {
console.log('got the data');
$scope.meeData = response;
}
});
I thought the .then only takes two parameters? This is what's confusing me.
Also is the .then property a JavaScript method or a jQuery one?
It's used to replace (or provide an alternate way) the old callback mechanism with a cleaner way to handle asynchronous requests, instead of passing your callbacks as parameters, you can chain your function with .then, given function will be executed once the promise gets resolved.
Anyhow, this is just a basic explanation, you should really get into the books of promises for more info.
I'm lazy to explain the whole promise thing, but just to answer question about .then
The 2 arguments inside .then actually means "call this function when the promise is resolved(success)/rejected(failed)"
About the arguments inside the functions, they should be specified in the API, because the caller (for instance $http.get) get to decide what to pass when calling that function.

Return promise value [duplicate]

This question already has answers here:
setting a variable to get return from call back function using promise
(2 answers)
Closed 8 years ago.
I'm new to Promise's and I'm trying to wrap my head around getting the value.
Here's an idea of what I'm trying to do:
API = {
get: function() {
return new Promise(function(res) {
setTimeout(function() {
res('foo')
}, 1000)
})
}
}
var foo = API.get()
console.log(foo)
It's important that var foo = API.get() remains as it is.
Any idea what to do here?
Promises are still asynchronous. You still can't inspect their value in synchronous code.
You need:
API.get().then(function(result) {
// Resolved value from the Promise object returned by API.get()
console.log(result);
});
API.get() returns a promise object, you then invoke the .then() method on that object.
Another more verbose way would be:
var fooPromise = API.get();
fooPromise.then(function(result) {
console.log(result);
});
Promises are about something happening in the future; you cannot examine their eventual values now unless you are in possession of a time machine.
I am not suggesting you do this, but merely for didactic purposes, if you really want your code to function as you seem to, you could redefine console.log to be promise-aware:
console.log = function() {
var old_console_dot_log = console.log.bind(console);
return function(maybe_promise) {
Promise.resolve(maybe_promise).then(old_console_dot_log);
};
}();
(This version only handles one argument; handling more is left as an exercise.)
Now when you say console.log(foo), it will log the resolved value of foo, but only when it is good and ready, one second from now.

Can I do a "lazy" promise with Bluebird.js? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want a construct similar to promise that waits until then is called before it runs. That is, if I never actually call then, the promise will never run.
Is this possible?
Make a function which creates and returns a promise on first invocation, but returns the same promise on each subsequent invocation:
function getResults() {
if (getResults.results) return getResults.results;
getResults.results = $.ajax(...); # or where ever your promise is being built
return getResults.results;
}
Promises don't work in such a way that they could support lazy loading. Promises are created by asynchronous code in order to communicate a result. Until the async code has been invoked, there simply is no promise.
You could certainly write a promise-like object which did lazy invocation, but code that generated these promises would be very different:
// Accepts the promise-returning function as an argument
LazyPromise = function (fn) {
this.promise = null;
this.fn = fn
}
LazyPromise.prototype.then = function () {
this.promise = this.promise || fn();
this.promise.then.apply(this.promise, arguments)
}
// Instead of this...
var promise = fn();
// You'd use this:
var promise = new LazyPromise(fn);
It's better in this uncommon use to make the actual creation of the promise lazy (as in either above example), rather than trying to make promises themselves responsible for lazy-evaluation.

Categories

Resources