I'm just trying to get my head around JavaScript Promises and I'm confused about something.
What is the difference between the following two functions?
function func_1()
{
var myArgs = Array.prototype.slice.call(arguments),
arg_1 = (myArgs[1]) ? myArgs[1] : 1,
arg_2 = (myArgs[2]) ? myArgs[2] : 2
;
return new Promise(function(resolve, reject) {
var result = arg_1 + arg_2;
resolve(result);
});
}
function func_2()
{
return new Promise(function(resolve, reject)
{
var myArgs = Array.prototype.slice.call(arguments),
arg_1 = (myArgs[1]) ? myArgs[1] : 1,
arg_2 = (myArgs[2]) ? myArgs[2] : 2
;
var result = arg_1 + arg_2;
resolve(result);
});
}
Your first function will work as you expect, because it accesses the arguments object of the func_1() call.
Your second function accesses the arguments of the anonymous callback function that you pass to the Promise constructor. Here, myArgs == [resolve, reject].
Notice that for your task you should not use the Promise constructor with its callbacks at all, but the Promise.resolve function:
function func(_, arg1, arg2) {
return Promise.resolve((arg1 || 1) + (arg2 || 2));
}
In your example, those two functions will result in essentially the same behavior, with the exception that in func_2, your arguments will refer to the arguments of the Promise callback instead of the args of the func_2 closure, which will certainly cause bugs in your code. The example, however, doesn't really utilize Promises in the way they are designed for.
The best way to understand how a promise works, is to use it to handle asynchronous behavior. So, if you change your example to the following:
function func_1()
{
return new Promise(function(resolve, reject) {
$.get('stuff.json')
.success(function (result) {
resolve(result);
}).fail(function () {
reject();
});
});
}
In this example, the promise starts an asynchronous request using jQuerys get method. When the request either succeeds or fails it either calls resolve or reject. So the way you'd use func_1 in your code is something like the following:
func_1().done(function (result) {
// do something with the result
});
FYI, this example is a little contrived, since $.get already returns a promise you can do essentially the same thing with.
Related
I'm rewriting some database code from synchronous (LocalStorage) to asynchronous (IndexedDB). I'm using the Alasql library and Promises. One of the problems I encounter is that when doing things asynchronously, sometimes it seems impossible to avoid duplicating code.
For example, my synchronous (pseudo) code could be something like this (idExists, doUpdate and doInsert are database methods):
function insertOrUpdate(data,id)
{
var result = null;
if (!idExists(id)) // idExists returns a boolean
result = doInsert(data,id); // doInsert returns an object
else
result = doUpdate(data,id); // doUpdate returns an object
doSomething(result);
}
With asynchronous code, it becomes something like this:
function insertOrUpdate(data,id)
{
var promise1 = idExists(id); // idExists returns a promise
promise1.then( function(id_exists) {
if (id_exists) {
var promise2 = doInsert(data,id); // doInsert returns a promise
promise2.then( function(result) {
doSomething(result);
});
}
else {
var promise3 = doUpdate(data,id); // doUpdate returns a promise
promise3.then( function(result) {
doSomething(result);
});
}
});
}
Here I have to call doSomething at two places in the code. Is there a way to avoid this situation? I'm new to promises and my apologies if this has been asked before, but I couldn't find an answer to this.
You can return a promise from a chained callback, which then gets inserted into the promise chain. Your code can, and should, be written as:
function insertOrUpdate(data, id) {
return idExists(id)
.then(function (exists) {
return exists ? doInsert(data, id) : doUpdate(data, id);
})
.then(doSomething);
}
The promises from doInsert or doUpdate will be chained into the existing chain from idExists, so the final .then(doSomething) will be executed with their result.
You can store promise into variable and call doSomething only once:
function insertOrUpdate(data, id) {
return idExists(id).then(function(id_exists) {
var promise = id_exists ? doInsert(data, id) : doUpdate(data, id)
return promise.then(doSomething)
});
}
function f () {
return new Promise(function (resolve, reject) {
resolve(4);
})
}
function g () {
return f().then((res) => {return res;})
}
console.log(g());
This returns Promise { <pending> }
If I returned res(in the then) and then returned f(), why isn't the output 4?
a valid answer would be:
function f() {
return new Promise(function(resolve, reject) {
resolve(4);
})
}
function g() {
return f().then((res) => {
return res;
})
.then((res) =>{
console.log(res);
})
}
g()
Why? Any time you return from inside a then statement in a promise, it passes it to the next statement (then or catch). Try commenting out return res and you'll see that it prints undefined.
==============
However, with ES7 we can use async/await. We can replicate the above using the following code:
function f() {
return new Promise(function(resolve, reject) {
resolve(4);
});
}
async function g() {
var a = await f();
// do something with a ...
console.log(a);
}
g();
It's important to note that console.log(g()) still returns a promise. This is because in the actual function g, resolving the promise gets delayed and therefore doesn't block the rest of our code from executing but the function body can utilize the returned value from f.
NOTE: to run this you need node 7 and it should be executed with the --harmony-async-await option.
===========
EDIT to include new code snippet
Look at the following code. You must use then to access the previous objects - however, where you access it in this case is up to you. You can call then on each promise inside of Promise.all, in this case .then((userVictories) => ...).then(...) or once Promise.all returns. It's important to note that Promise.all returns once all promises it contains resolve.
var membersArray = groupFound.members;
Promise.all(membersArray.map((member) => {
return db.doneTodo.find({ 'victor._id': member._id }).then((userVictories) => {
return {
email: member.email,
victories: userVictories.length,
}
}).then(obj => {
/*
obj is each object with the signature:
{email: '', victories: ''}
calling this then is optional if you want to process each object
returned from '.then((userVictories) =>)'
NOTE: this statement is processed then *this* promise resolves
We can send an email to each user with an update
*/
});
}))
.then((arr) => {
/*
arr is an array of all previous promises in this case:
[{email: '', victories: ''}, {email: '', victories: ''}, ...]
NOTE: this statement is processed when all of the promises above resolve.
We can use the array to get the sum of all victories or the
user with the most victories
*/
})
Let's look at jQuery first as an introduction to learning promises.
What does this code return? What is the value of result?
var result = $('body');
Hint: It won't be the <body/> body HTML element.
result is a jQuery collection object. Internally it holds a reference to the body tag. But the actual result object is a collection.
What does this return?
var result = $('body').css('background', 'red');
Again, it returns a jQuery collection.
And this?
var result = $('body').css('background', 'red').animate({height: "20px"});
Same thing. A jQuery collection.
Now, what does this promise based code return?
var result = new Promise();
It's probably clear this returns a promise. But what about this code?
var result = new Promise().resolve().then(() => {
return 'Hello';
});
What is the value of result now? Hint: It's not the string 'Hello'.
It's a promise!
What does this return?
var result = new Promise().resolve().then(() => {
return new Promise().resolve();
}).then(() => {
return 'Hello';
}).catch(() => {
console.log('Something went wrong');
});
It returns a promise! Promises let us access values in functions that are called at later times. Until the function is executed, you won't have access to whatever the promise "returns," or "resolves" with. Once you enter a promise chain, you always have to use .then(fn) to handle the next step in the program flow.
Javascript is asynchronous. All top level code is executed in order without pausing. The promise resolves at a later time, long after your console.log has finished executing. To get values back, you need to stay in promise chain land:
g().then( result => console.log(result) );
I have got a javascript code like this:
function justTesting() {
promise.then(function(output) {
return output + 1;
});
}
var test = justTesting();
I have got always an undefined value for the var test. I think that it is because the promises are not resolved yet..there is a way to return a value from a promise?
When you return something from a then() callback, it's a bit magic. If you return a value, the next then() is called with that value. However, if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails).
Source: https://web.dev/promises/#queuing-asynchronous-actions
To use a promise, you have to either call a function that creates a promise or you have to create one yourself. You don't really describe what problem you're really trying to solve, but here's how you would create a promise yourself:
function justTesting(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
Or, if you already have a function that returns a promise, you can use that function and return its promise:
// function that returns a promise
function delay(t) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, t);
});
}
function justTesting(input) {
return delay(100).then(function() {
return input + 10;
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
What I have done here is that I have returned a promise from the justTesting function. You can then get the result when the function is resolved.
// new answer
function justTesting() {
return new Promise((resolve, reject) => {
if (true) {
return resolve("testing");
} else {
return reject("promise failed");
}
});
}
justTesting()
.then(res => {
let test = res;
// do something with the output :)
})
.catch(err => {
console.log(err);
});
Hope this helps!
// old answer
function justTesting() {
return promise.then(function(output) {
return output + 1;
});
}
justTesting().then((res) => {
var test = res;
// do something with the output :)
}
I prefer to use "await" command and async functions to get rid of confusions of promises,
In this case I would write an asynchronous function first,
this will be used instead of the anonymous function called under "promise.then" part of this question :
async function SubFunction(output){
// Call to database , returns a promise, like an Ajax call etc :
const response = await axios.get( GetApiHost() + '/api/some_endpoint')
// Return :
return response;
}
and then I would call this function from main function :
async function justTesting() {
const lv_result = await SubFunction(output);
return lv_result + 1;
}
Noting that I returned both main function and sub function to async functions here.
Promises don't "return" values, they pass them to a callback (which you supply with .then()).
It's probably trying to say that you're supposed to do resolve(someObject); inside the promise implementation.
Then in your then code you can reference someObject to do what you want.
I think what the original poster wants is to return an unwrapped value from a promise without actually returning another promise. Unless proven otherwise, I'm afraid this is not possible outside of a then() or async/await context. You always get a promise no matter what.
You need to make use of reference data type like array or object.
function foo(u,n){
let result = [];
const userBrands = new Promise((res, rej)=> {
res(['brand 1', 'brand 3']);
})
userBrands.then((ub)=>{
return new Promise((res, rej) =>{
res([...ub, 'brand 4', 'brand 5']);
})
}).then(response => {
return result.push(...response);
});
return result;
};
foo();
You cannot return value after resolving promise. Instead call another function when promise is resolved:
function justTesting() {
promise.then(function(output) {
// instead of return call another function
afterResolve(output + 1);
});
}
function afterResolve(result) {
// do something with result
}
var test = justTesting();
I need to throw in a userID param in the middle of a promise chain(it is the only promise that needs it). All the promises should execute in a synchronous order.
SideNote- All the similar examples on stackoverflow are all a bit different- like using lambda functions(I use declared functions).So I'm still not quite sure.
var initialize = function(userID) {
var firstPromise = Module2.getFirstPromise();
firstPromise.then(getSecondPromise)
.then(getThirdPromise)
.then(getFourthPromise) //<----Fourth promise needs userID
.then(getFifthPromise)
.then(Utils.initializeComplete);
}
All the promises are functions that look like this:
var thirdPromise = function() {
return new Promise(function(resolve, reject) {
//fetch data
//On Return, Store it
resolve() //Nothing needed to passed down from this promise
});
});
}
I'm trying this, and it "works", but I'm not sure if that is how I am "suppose" to handle something like this. :)
var initialize = function(userID) {
var firstPromise = Module2.getFirstPromise();
firstPromise.then(getSecondPromise)
.then(getThirdPromise)
.then(function(){ return fourthPromise(userID)})
.then(getFourthPromise)
.then(Utils.initializeComplete);
}
Note: getFirstPromise is coming from a different module in my code. That shouldn't be important to the question though :)
Assuming that firstPromise is really a promise but secondPromise and so on are actually functions returning promises, then yes, what you've done is how you're supposed to do that. Here's a live example on Babel's REPL, which looks like this:
function doSomething(userID) {
getFirstPromise()
.then(getSecondPromise)
.then(getThirdPromise)
.then(() => getFourthPromise(userID))
// Or .then(function() { return getFourthPromise(userID); })
.then(getFifthPromise)
.catch(err => {
console.log("Error: " + err.message);
});
}
doSomething("foo");
function getFirstPromise() {
console.log("getFirstPromise called");
return new Promise(resolve => {
setTimeout(() => {
resolve("one");
}, 0);
});
}
// and then second, third, fourth (with user ID), and fifth
(If you don't use arrow functions, just replace them with the function form.)
Note the catch in the example above. Unless you have a really good reason not to, a promise chain should always have a .catch if you don't return the result.
Your solution is perfectly fine. It might be easier to understand with concrete signatures.
If your thirdPromise doesn't take anything and doesn't return anything its signature might be written (pseudocode assuming a -> b is a function from a to b) as _ -> Promise (_). If it returns some value a, it would be _ -> Promise (a). If it took something and returned something it might be a -> Promise (b)
So you can reason about your promise chains as about functions taking some value and returning some other value wrapped in a promise. However, your fourthPromise looks differently:
fourthPromise : UserId -> a -> Promise (b)
Which can be written as:
fourthPromise : UserId -> (a -> Promise (b))
It takes one parameter before becoming an actual promise you can chain. In a way, it's a template of a promise.
If you want the plain .then chain in the main function, try to write getFourthPromise as a factory function
function getSomethingByUserID(userId) {
return function() {
return new Promise(function(resolve) {
//your actual async job
resolve('a result');
});
};
}
Then you will get plan list of thens
var firstPromise = Module2.getFirstPromise()
.then(getSecondPromise)
.then(getSomethingByUserID(userId))
.then(Utils.initializeComplete);
Do not forget that if you missed to provide userId to getSomethingByUserID, it will not work.
I just implemented my first function that returns a promise based on another promise in AngularJS, and it worked. But before I decided to just do it, I spent 2 hours reading and trying to understand the concepts behind promises. I thought if I could write a simple piece of code that simulated how promises worked, I would then be able to conceptually understand it instead of being able to use it without really knowing how it works. I couldn't write that code.
So, could someone please illustrate in vanilla JavaScript how promises work?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:
promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:
promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/
When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
For the simplicity to understand about the promises in Javascript.
You can refer below example. Just copy paste in a new php/html file and run.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function test(n){
alert('input:'+n);
var promise = new Promise(function(fulfill, reject) {
/*put your condition here */
if(n) {
fulfill("Inside If! match found");
}
else {
reject(Error("It broke"));
}
});
promise.then(function(result) {
alert(result); // "Inside If! match found"
}, function(err) {
alert(err); // Error: "It broke"
});
}
</script>
</head>
<body>
<input type="button" onclick="test(1);" value="Test"/>
</body>
</html>
Click on Test button,
It will create new promise,
if condition will be true it fulfill the response,
after that promise.then called and based on the fulfill it will print the result.
In case of reject promise.then returns the error message.
Probably the simplest example of promises usage looks like that:
var method1 = (addings = '') => {
return new Promise(resolve => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '') => {
return new Promise(resolve => {
console.log('method2' + addings)
resolve(addings + '_adding2');
});
}
method1().then(method2).then(method1).then(method2);
// result:
// method1
// method2_adding1
// method1_adding1_adding2
// method2_adding1_adding2_adding1
That's basic of basics. Having it, you can experiment with rejects:
var method1 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method2' + addings)
reject();
});
}
var errorMethod = () => {
console.log('errorMethod')
}
method1()
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod);
// result:
// method1*
// method2*_adding1
// errorMethod
// method2*
// errorMethod
// method2*
As we can see, in case of failure error function is fired (which is always the second argument of then) and then next function in chain is fired with no given argument.
For advanced knowledge I invite you here.
please check this simple promise code. this will help you to better understand of promise functionality.
A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved. A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
let myPromise = new Promise((resolve, reject)=>{
if(2==2){
resolve("resolved")
}else{
reject("rejected")
}
});
myPromise.then((message)=>{
document.write(`the promise is ${message}`)
}).catch((message)=>{
document.write(`the promise is ${message}`)
})
check this out