Passing an extra parameter in the middle of a Promise chain - javascript

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.

Related

Return in .then(), when there are multiple .then()?

Js is not my first language, by a long chalk. I code in 5 or 6 others, and am comfortable with callbacks, which means that I should be able to grok promises.
However, I inherited a node.js project with something like this (simplified), which makes me uncertain)
let promise = someFunction.then({return xxxx;});
// lots of more code & promises
Promises.all().then(() => {return somethingElse});
I am comfortable with lots of promises and Promises.all() to wait for them all to resolve (although I am replacing all .then with await for cleaner code), BUT ...
that return inside a .then disturbs me. If I understand correctly, .then just wraps an async callback - which could happen at any time, even before the rest of the code and that Promises.all, leaving some of the code unexecuted.
Am I correct to be concerned, or is there something that I am missing?
Tl;dr - is it ok to return inside a .then?
Returning inside .then is extremely common and fine to do. What it does is it produces a Promise that now resolves to the value returned (rather than to the value returned by the previous Promise). Example:
// resolves to 1
const prom1 = Promise.resolve(1);
// chains off of prom1, resolves to 2
const prom2 = prom1.then(() => {
return 2;
});
prom1.then(console.log);
setTimeout(() => {
prom2.then(console.log);
});
This technique is very useful when you need to pass along a value from a prior .then to a subsequent .then.
const makeApiCall = num => Promise.resolve(num + 3);
Promise.resolve(1)
.then((result1) => {
return makeApiCall(result1);
})
.then((result2) => {
console.log(result2);
});
What the return will do in your situation specifically:
let promise = someFunction.then({return xxxx;});
// lots of more code & promises
Promises.all().then(() => {return somethingElse});
If promise is passed to the Promise.all, then its resolve value will be xxxx, rather than whatever someFunction resolves to. (If the Promise.all's .then ignores its argument, then it does nothing except wait for the returned value to resolve, if it's a Promise.)
const someFunction = () => Promise.resolve(1);
let promise = someFunction().then(() => {
return 'xxxx';
});
Promise.all([promise]).then((allResults) => {
console.log('allResults', allResults);
return 'somethingElse';
})
.then((result2) => {
console.log('Next `.then`', result2);
});
Note that your current code has a number of syntax issues you need to correct.

How do use Javascript Async-Await as an alternative to polling for a statechange?

I'd like to accomplish the following using promises: only execute further once the state of something is ready. I.e. like polling for an external state-change.
I've tried using promises and async-await but am not getting the desired outcome. What am I doing wrong here, and how do I fix it?
The MDN docs have something similar but their settimeout is called within the promise--that's not exactly what I'm looking for though.
I expect the console.log to show "This function is now good to go!" after 5 seconds, but instead execution seems to stop after calling await promiseForState();
var state = false;
function stateReady (){
state = true;
}
function promiseForState(){
var msg = "good to go!";
var promise = new Promise(function (resolve,reject){
if (state){
resolve(msg);
}
});
return promise;
}
async function waiting (intro){
var result = await promiseForState();
console.log(intro + result)
}
setTimeout(stateReady,5000);
waiting("This function is now ");
What you're doing wrong is the promise constructor executor function executes immediately when the promise is created, and then never again. At that point, state is false, so nothing happens.
Promises (and async/await) are not a replacement for polling. You still need to poll somewhere.
The good news: async functions make it easy to do conditional code with loops and promises.
But don't put code inside promise constructor executor functions, because of their poor error handling characteristics. They are meant to wrap legacy code.
Instead, try this:
var state = false;
function stateReady() {
state = true;
}
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function promiseForState() {
while (!state) {
await wait(1000);
}
return "good to go!";
}
async function waiting(intro) {
var result = await promiseForState();
console.log(intro + result)
}
setTimeout(stateReady,5000);
waiting("This function is now ");
Based on your comments that you are waiting for messages from a server it appears you are trying to solve an X/Y problem. I am therefore going to answer the question of "how do I wait for server messages" instead of waiting for global variable to change.
If your network API accepts a callback
Plenty of networking API such as XMLHttpRequest and node's Http.request() are callback based. If the API you are using is callback or event based then you can do something like this:
function myFunctionToFetchFromServer () {
// example is jQuery's ajax but it can easily be replaced with other API
return new Promise(function (resolve, reject) {
$.ajax('http://some.server/somewhere', {
success: resolve,
error: reject
});
});
}
async function waiting (intro){
var result = await myFunctionToFetchFromServer();
console.log(intro + result);
}
If your network API is promise based
If on the other hand you are using a more modern promise based networking API such as fetch() you can simply await the promise:
function myFunctionToFetchFromServer () {
return fetch('http://some.server/somewhere');
}
async function waiting (intro){
var result = await myFunctionToFetchFromServer();
console.log(intro + result);
}
Decoupling network access from your event handler
Note that the following are only my opinion but it is also the normal standard practice in the javascript community:
In either case above, once you have a promise it is possible to decouple your network API form your waiting() event handler. You just need to save the promise somewhere else. Evert's answer shows one way you can do this.
However, in my not-so-humble opinion, you should not do this. In projects of significant size this leads to difficulty in tracing the source of where the state change comes form. This is what we did in the 90s and early 2000s with javascript. We had a lot of events in our code like onChange and onReady or onData instead of callbacks passed as function parameters. The result was that sometimes it takes you a long time to figure out what code is triggering what event.
Callback parameters and promises forces the event generator to be in the same place in the code as the event consumer:
let this_variable_consumes_result_of_a_promise = await generate_a_promise();
this_function_generate_async_event((consume_async_result) => { /* ... */ });
From the wording of your question you seem to be wanting to do this instead;
..somewhere in your code:
this_function_generate_async_event(() => { set_global_state() });
..somewhere else in your code:
let this_variable_consumes_result_of_a_promise = await global_state();
I would consider this an anti-pattern.
Calling asynchronous functions in class constructors
This is not only an anti-pattern but an impossibility (as you've no doubt discovered when you find that you cannot return the asynchronous result).
There are however design patterns that can work around this. The following is an example of exposing a database connection that is created asynchronously:
class MyClass {
constructor () {
// constructor logic
}
db () {
if (this.connection) {
return Promise.resolve(this.connection);
}
else {
return new Promise (function (resolve, reject) {
createDbConnection(function (error, conn) {
if (error) {
reject(error);
}
else {
this.connection = conn; // cache the connection
resolve(this.connection);
}
});
});
}
}
}
Usage:
const myObj = new MyClass();
async function waiting (intro){
const db = await myObj.db();
db.doSomething(); // you can now use the database connection.
}
You can read more about asynchronous constructors from my answer to this other question: Async/Await Class Constructor
The way I would solve this, is as follows. I am not 100% certain this solves your problem, but the assumption here is that you have control over stateReady().
let state = false;
let stateResolver;
const statePromise = new Promise( (res, rej) => {
stateResolver = res;
});
function stateReady(){
state = true;
stateResolver();
}
async function promiseForState(){
await stateResolver();
const msg = "good to go!";
return msg;
}
async function waiting (intro){
const result = await promiseForState();
console.log(intro + result)
}
setTimeout(stateReady,5000);
waiting("This function is now ");
Some key points:
The way this is written currently is that the 'state' can only transition to true once. If you want to allow this to be fired many times, some of those const will need to be let and the promise needs to be re-created.
I created the promise once, globally and always return the same one because it's really just one event that every caller subscribes to.
I needed a stateResolver variable to lift the res argument out of the promise constructor into the global scope.
Here is an alternative using .requestAnimationFrame().
It provides a clean interface that is simple to understand.
var serverStuffComplete = false
// mock the server delay of 5 seconds
setTimeout(()=>serverStuffComplete = true, 5000);
// continue until serverStuffComplete is true
function waitForServer(now) {
if (serverStuffComplete) {
doSomethingElse();
} else {
// place this request on the next tick
requestAnimationFrame(waitForServer);
}
}
console.log("Waiting for server...");
// starts the process off
requestAnimationFrame(waitForServer);
//resolve the promise or whatever
function doSomethingElse() {
console.log('Done baby!');
}

Correctly using Promise.resolve

I have a a changePassword function returning a promise:
function changePassword(userName, oldPassword, newPassword) {
return new Promise(
function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(ok) {
if (ok) resolve(); else reject();
}
});
}
I need to modify this function so that newPassword can be either a value or a promise:
// functionReturningNewPasswordValOrPromise is a function returning either a value
// or a promise that will resolve with a value
function changePassword(userName, oldPassword, functionReturningNewPasswordValOrPromise) {
return new Promise( ...
If functionReturningNewPasswordValOrPromise returns a value (the new password), everything proceeds as above.
However if functionReturningNewPasswordValOrPromise returns a a promise, it will run first (ie prompting the user). If resolved (ie with the new password string) changePassword will continue resolution with that value. If rejected changePassword itself will reject.
I understand I need to use Promise.resolve(thenable) somehow but not sure how to proceed.
Thx!
(I need an answer in ES6 so that I can use it in IE with polyfill .. no ES7)
The simple answer to handling newPassword being a password or a promise is:
function changePassword(userName, oldPassword, newPassword) {
return Promise.resolve(newPassword).then(password => new Promise((r, e) =>
someAsyncFunction(userName, oldPassword, password, ok => ok ? r() : e())));
}
Promise.resolve(x) returns x when x is a promise (*), and a promise resolved with value x when it isn't.
There is good advice in other answers, but I believe this is all that was asked for.
*) In most implementations, but not all (Safari being an exception), I observe that Promise.resolve(p) === p when p is a promise, but this is a detail. The important bit is it acts like the original promise in this case.
It is often an anti-pattern to have values which might or not be promises, then try to check which they are, or have special logic to handle this, or convert them to promises. The same applies to functions which might return such maybe-a-promise-maybe-not values.
So we need to go back to where your function is being called and where it is getting the newPassword parameter. Let's assume it's something like this, using a getNewPassword function which is currently designed to return either a value or a promise:
changePassword(userName, oldPassword, getNewPassword())
The first and probably best approach would be to simply change the definition of getNewPassword so it always returns a promise--even if it's already resolved with some value. Then you can write the above as
getNewPassword() .
then(newPassword => changePassword(userName, oldPassword, newPassword))
and you don't have to change your original definition of changePassword at all.
Even if you cannot change the definition or signature of getNewPassword, it seems clumsy to build the logic for handling a parameter which might or might not be a promise into a specific interface such as changePassword. Instead, I would do that at the calling point, via
Promise.resolve(getNewPassword()) .
then(newPassword => changePassword(userName, oldPassword, newPassword))
In other words, absorb the impact of the ambiguous design of getNewPassword at the point where it is called, rather than making people downstream worry about it.
A general solution
If you really want to deal with functions which take parameters which might or might not be promises, you could generalize this:
function promisify_arguments(fn) {
return function(...args) {
return Promise.all(args) . then(vals => fn(...vals));
};
}
If for some reason you have promises but not ES6 support, then in ES5:
function promisify_arguments(fn) {
return function() {
return Promise.all(arguments) . then(function(vals) {
return fn.apply(0, vals));
});
};
}
This takes a function which expects non-promise paramters, and returns a modified function which can be called with promises for some or all parameters, and waits for all its promise-valued parameters to resolve, then invokes the original function with the resolved values as parameters, returning a promise whose value is the resulting value.
You can use this to transform your changePassword function as
var changePasswordWhereNewPasswordMayBePromise = promisify_arguments(changePassword);
and then use changePasswordWhereNewPasswordMaybePromise instead of changePassword. This has the potential advantage that if userName or oldPassword ever are provided as promises, it will automatically do the right thing.
I'd suggest to wrap someAsyncFunction into a promise based function.
e.g.
function someAsyncFunctionP(userName, oldPassword, newPassword) {
return new Promise(function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(err) {
if(err) reject(err); else resolve();
});
});
}
Then to allow newPassword to be a Promise you can write this.
function changePassword(userName, oldPassword, newPassword) {
return Promise.resolve(newPassword).then(function(newPassword) {
return someAsyncFunctionP(userName, oldPassword, newPassword);
});
}
the solution I came up with is:
function changePassword(userName, oldPassword, functionReturningNewPasswordValOrPromise) {
var getNewPassPromise=functionReturningNewPasswordValOrPromise(email);
return Promise.resolve(getNewPassPromise).then(function(newPassword) {
return changePasswordWithVal(email, oldPassword, newPassword);
});
}
// do the real work
function changePasswordWithVal(userName, oldPassword, newPassword) {
return new Promise(
function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(ok) {
if (ok) resolve(); else reject();
}
});
}

Promise.resolve vs new Promise(resolve)

I'm using bluebird and I see two ways to resolve synchronous functions into a Promise, but I don't get the differences between both ways. It looks like the stacktrace is a little bit different, so they aren't just an alias, right?
So what is the preferred way?
Way A
function someFunction(someObject) {
return new Promise(function(resolve) {
someObject.resolved = true;
resolve(someObject);
});
}
Way B
function someFunction(someObject) {
someObject.resolved = true;
return Promise.resolve(someObject);
}
Contrary to both answers in the comments - there is a difference.
While
Promise.resolve(x);
is basically the same as
new Promise(function(r){ r(x); });
there is a subtlety.
Promise returning functions should generally have the guarantee that they should not throw synchronously since they might throw asynchronously. In order to prevent unexpected results and race conditions - throws are usually converted to returned rejections.
With this in mind - when the spec was created the promise constructor is throw safe.
What if someObject is undefined?
Way A returns a rejected promise.
Way B throws synchronously.
Bluebird saw this, and Petka added Promise.method to address this issue so you can keep using return values. So the correct and easiest way to write this in Bluebird is actually neither - it is:
var someFunction = Promise.method(function someFunction(someObject){
someObject.resolved = true;
return someObject;
});
Promise.method will convert throws to rejects and returns to resolves for you. It is the most throw safe way to do this and it assimilatesthenables through return values so it'd work even if someObject is in fact a promise itself.
In general, Promise.resolve is used for casting objects and foreign promises (thenables) to promises. That's its use case.
There is another difference not mentioned by the above answers or comments:
If someObject is a Promise, new Promise(resolve) would cost two additional tick.
Compare two following code snippet:
const p = new Promise(resovle => setTimeout(resovle));
new Promise(resolve => resolve(p)).then(() => {
console.log("tick 3");
});
p.then(() => {
console.log("tick 1");
}).then(() => {
console.log("tick 2");
});
const p = new Promise(resolve => setTimeout(resolve));
Promise.resolve(p).then(() => {
console.log("tick 3");
});
p.then(() => {
console.log("tick 1");
}).then(() => {
console.log("tick 2");
});
The second snippet would print 'tick 3' firstly. Why?
If the value is a promise, Promise.resolve(value) would return value exactly. Promise.resolve(value) === value would be true. see MDN
But new Promise(resolve => resolve(value)) would return a new promise which has locked in to follow the value promise. It needs an extra one tick to make the 'locking-in'.
// something like:
addToMicroTaskQueue(() => {
p.then(() => {
/* resolve newly promise */
})
// all subsequent .then on newly promise go on from here
.then(() => {
console.log("tick 3");
});
});
The tick 1 .then call would run first.
References:
http://exploringjs.com/es6/ch_promises.html#sec_demo-promise

How do promises work in JavaScript?

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

Categories

Resources