Correctly using Promise.resolve - javascript

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();
}
});
}

Related

How to grab value of promise and fire function

I know this is a common question asked, but I'm having a bit of an issue, trying to fire a function, ONLY when a promise has been returned. I also want to grab the value returned of the promise.
So I want to access an angular service, which seems to make an API call.
Wait for the promise to resolve.
Then store the promise returned as a value.
And then fire the function hello()
It seems when I fire run my code below, validPassengerId and hello()console.logs, before the promise has resolved.
How do I rewrite this code, to:
Wait for promise to resolve.
Then grab the value of the promise resolved - validPassengerId. (And then console.log it).
And then fire the function hello()?
function hello() {
console.log("hello");
};
const promise = new Promise((resolve, reject) => {
let validPassengerId = _funnelBasketLuggageService.FindValidPassengerIdForBag(PassengerIds, bagsAssignedToPassengers, bag);
resolve(validPassengerId);
});
promise.then(validPassengerId => {
console.log("validPassengerId", validPassengerId);
hello();
});
Assuming FindValidPassengerIdForBag returns a promise, you do not need to wrap it in another promise. You would use it like this:
_funnelBasketLuggageService
.FindValidPassengerIdForBag(PassengerIds, bagsAssignedToPassengers, bag)
.then(validPassengerId => {
console.log("validPassengerId", validPassengerId);
hello();
});
If validPassengerId is null with this code, then that must be what FindValidPassengerIdForBag is resolving its promise to. If you weren't expecting that, check the code of FindValidPassengerIdForBag or check that you're passing in valid parameters.
If in fact _funnelBasketLuggageService.FindValidPassengerIdForBag returns a promise, you solve this without creating your own Promise:
function hello() {
console.log("hello");
};
const promise = _funnelBasketLuggageService.FindValidPassengerIdForBag(PassengerIds, bagsAssignedToPassengers, bag);
promise.then(validPassengerId => {
console.log("validPassengerId", validPassengerId);
hello();
});
Explanation What you did was actually wrapping the Promise returned by FindValidPassengerIdForBag in another Promise that returns immediately.
If you absolutely have to wrap it in your own Promise, e.g. because you need to do some preprocessing, use .then instead of the return value of the function:
function hello() {
console.log("hello");
};
const promise = new Promise((resolve, reject) => {_funnelBasketLuggageService.FindValidPassengerIdForBag(PassengerIds, bagsAssignedToPassengers, bag).then(id=>resolve(id));
});
promise.then(validPassengerId => {
console.log("validPassengerId", validPassengerId);
hello();
});

Promises in a const function in nodejs

This is my function
const f = (value,err) => {
if(!value === Number){
throw err;
}
return (value);
}
Using promises I want to return an object of parameter value and after some wait it will return parameter in number. Is that possible?
A promise doesn't do anything in and of itself, and it doesn't make anything asynchronous in and of itself (other than that promise reactions are always asynchronous¹). A promise is just a standardized way to report the completion of something that's (potentially) asynchronous. So the literal answer to your question is: No, you can't use a promise to do that, not on its own. You'd have to combine it with something like setTimeout or similar.
Also note that if (!value === Number) is always false. It's evaluated like this: !value, negating the value of value, and then x === Number, which will always be false because there is no value that, when negated, turns into the Number function.
But for instance, if you wanted to check whether something is a number but not respond for 100ms:
const f = (value, err) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (typeof value !== "number") {
reject(err);
} else {
resolve(value);
}
}, 100);
});
};
Other than the promise, the two significant changes there are:
Using setTimeout to introduce asynchronousness, and
Changing the if condition to something that won't always be false (I may or may not have guessed correctly what you wanted there :-) )
¹ A promise reaction is a call to a then, catch, or finally callback registered on the promise. Here's an example of what I mean by "promise reactions are asynchronous:"
console.log("Before creating the promise");
new Promise(resolve => {
console.log("Inside the promise executor function");
resolve(42);
})
.then(value => {
console.log(`Promise reaction ran, value = ${value}`);
});
console.log("After creating the promise");
That code has this output:
Before creating the promise
Inside the promise executor function
After creating the promise
Promise reaction ran, value = 42
Notice that everything was synchronous except the call to the then callback (the promise reaction), which per specification is always done asynchronously, even if (as in this case) the promise is already settled when the reaction is added to it.

Extend Javascript promise and resolve or reject it inside constructor

I want to extend native Javascript Promise class with ES6 syntax, and be able to call some asynchronous function inside the subclass constructor. Based on async function result the promise must be either rejected or resolved.
However, two strange things happen when then function is called:
subclass constructor is executed twice
"Uncaught TypeError: Promise resolve or reject function is not callable" error is thrown
class MyPromise extends Promise {
constructor(name) {
super((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
this.name = name
}
}
new MyPromise('p1')
.then(result => {
console.log('resolved, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
The reasoning is simple but not necessarily self evident.
.then() returns a promise
if then is called on a subclass of Promise, the returned promise is an instance of the subclass, not Promise itself.
the then returned promise is constructed by calling the subclass constructor, and passing it an internal executor function that records the value of resolve and reject arguments passed to it for later use.
"later use" covers resolving or rejecting the promise returned by then asynchronously when monitoring execution of onfulfilled or onrejected handlers (later) to see if they return a value (which resolves the then returned promise) or throw an error (which rejects the promise).
In short then calls internally obtain and record references to the resolve and reject functions of promises they return.
So regarding the question,
new MyPromise( 'p1')
works fine and is the first call to the subclass constructor.
.then( someFunction)
records someFunction in a list of then calls made on new MyPromise (recall then can be called multiple times) and attempts to create a return promise by calling
new MyPromise( (resolve, reject) => ... /* store resolve reject references */
This is the second call to the subclass constructor coming from then code. The constructor is expected to (and does) return synchronously.
On return from creating the promise to return, the .then method makes an integrity check to see if the resolve and reject functions it needs for later use are in fact functions. They should have been stored (in a list) along with callbacks provided in the then call.
In the case of MyPromise they are not. The executor passed by then, to MyPromise, is not even called. So then method code throws a type error "Promise resolve or reject function is not callable" - it has no means of resolving or rejecting the promise it is supposed to return.
When creating a subclass of Promise, the subclass constructor must take an executor function as its first argument, and call the executor with real resolve and reject functional arguments. This is internally required by then method code.
Doing something intricate with MyPromise, perhaps checking the first parameter to see if it is a function and calling it as an executor if it is, may be feasible but is outside the scope of this answer! For the code shown, writing a factory/library function may be simpler:
function namedDelay(name, delay=1000, value=1) {
var promise = new Promise( (resolve,reject) => {
setTimeout(() => {
resolve(value)
}, delay)
}
);
promise.name = name;
return promise;
}
namedDelay( 'p1')
.then(result => {
console.log('fulfilled, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
;TLDR
The class extension to Promise is not an extension. If it were it would need to implement the Promise interface and take an executor function as first parameter. You could use a factory function to return a Promise which is resolved asynchronously (as above), or hack the posted code with
MyPromise.prototype.constructor = Promise
which causes .then to return a regular Promise object. The hack itself refutes the idea that a class extension is taking place.
Promise Extension Example
The following example shows a basic Promise extension that adds properties supplied to the constructor. Of note:
The Symbol.toString getter only affects the output of converting an instance to a string. It does not change "Promise" to "MyPromise" when logging an instance object on browser consoles tested.
Firefox 89 (Proton) is not reporting own properties of extended instances while Chrome does - the reason test code below logs instance properties by name.
class MyPromise extends Promise {
constructor(exec, props) {
if( typeof exec != "function") {
throw TypeError( "new MyPromise(executor, props): an executor function is required");
}
super((resolve, reject) => exec(resolve,reject));
if( props) {
Object.assign( this, props);
}
}
get [Symbol.toStringTag]() {
return 'MyPromise';
}
}
// Test the extension:
const p1 = new MyPromise( (resolve, reject) =>
resolve(42),
{id: "p1", bark: ()=>console.log("woof") });
console.log( "p1 is a %s object", p1.constructor.name);
console.log( "p1.toString() = %s", p1.toString());
console.log( "p1.id = '%s'", p1.id);
console.log( "p1 says:"); p1.bark();
const pThen = p1.then(data=>data);
console.log( "p1.then() returns a %s object", pThen.constructor.name);
let pAll = MyPromise.all([Promise.resolve(39)]);
console.log( "MyPromise.all returns a %s object", pAll.constructor.name);
try { new MyPromise(); }
catch(err) {
console.log( "new MyPromise() threw: '%s'", err.message);
}
The best way I found to extend a promise is
class MyPromise extends Promise {
constructor(name) {
// needed for MyPromise.race/all ecc
if(name instanceof Function){
return super(name)
}
super((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
this.name = name
}
// you can also use Symbol.species in order to
// return a Promise for then/catch/finally
static get [Symbol.species]() {
return Promise;
}
// Promise overrides his Symbol.toStringTag
get [Symbol.toStringTag]() {
return 'MyPromise';
}
}
new MyPromise('p1')
.then(result => {
console.log('resolved, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
The post by asdru contains the correct answer, but also contains an approach (constructor hack) that should be discouraged.
The constructor hack checks if the constructor argument is a function. This is not the way to go as the ECMAScript design contains a specific mechanism for sub-classing Promises via Symbol.species.
asdru's comment on using Symbol.species is correct. See the explanation in the current ECMAScript specification:
Promise prototype methods normally use their this value's constructor
to create a derived object. However, a subclass constructor may
over-ride that default behaviour by redefining its ##species property.
The specification (indirectly) refers to this note in the sections on finally and then (look for mentions of SpeciesConstructor).
By returning Promise as the species constructor, the problems that traktor's answer analyzes so clearly are avoided. then calls the Promise constructor, but not the sub-classed MyPromise constructor. The MyPromise constructor is called only once with the name argument and no further argument-checking logic is needed or appropriate.
Therefore, the code should simply be:
class MyPromise extends Promise {
constructor(name) {
super((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
this.name = name
}
static get [Symbol.species]() {
return Promise;
}
get [Symbol.toStringTag]() {
return 'MyPromise';
}
}
Less is more!
Some notes:
MDN has an example for the use of the species symbol in extending Array.
The most recent browser versions (Chrome, FF, Safari, Edge on MAC and Linux) handle this correctly, but I have no information on other browsers or legacy versions.
Symbol.toStringTag is a very nice touch, but not required. Most browsers use the value returned for this symbol to identify the sub-classed promise in the console, but, beware, FF does not - this could easily be confusing. In all browsers, however, new MyPromise('mine').toString() yields "[object MyPromise]".
All of this is also unproblematic if you author in Typescript.
As noseratio points out, a primary use-case for extending Promises is the wrapping of (legacy) APIs that support abort or cancel logic (FileReader, fetch, ...).
You have to make it thenable by implementing the then method.
Otherwise, that of the superclass, Promise, will be called, and it’ll try to create another Promise with your MyPromise’ constructor, which is not compatible with the original Promise constructor.
The thing is, it’s tricky to properly implement the then method that works just like Promise’s does. You’ll likely end up having an instance of Promise as a member, not as a superclass.
Summarizing the above into a short tl;dr for those who just want to get something working and move on, you just need to add this to your class body:
static get [Symbol.species]() {
return Promise;
}
A full TypeScript example:
class MyPromise extends Promise<string> {
constructor(name: string) {
super((resolve) => {
setTimeout(() => {
resolve(name)
}, 1000)
})
this.name = name;
}
static get [Symbol.species]() {
return Promise;
}
}
const p = new MyPromise('hi');
p.name === 'hi'
const x: string = await p;
x === 'hi'
That's all you need.
Forgoing Symbol.toStringTag may make MyPromise just look like a Promise in some debugging contexts, and you won't be able to do MyPromise.race or MyPromise.all, but that's fine: you can use Promise.all with a list of MyPromises.

reading a returned Promise value

New to Promises in serverside (Node js). Here is my question
I have code in FileA.js
incoming_form = client_services.pullForm('vsl_video1.mp4');
incoming_form.resolve().then(function(results) {
return console.log(results);
});
The incoming_form returns a Promise something like this in FileB.js
incoming_form () {
return Promise (function (resp, rej) {
var myArray = ['fudge', 'fgfdgdf'];
return resp(myArray);
});
}
How can I read my 'myArray' value in FileA.js? when I ran my FileA.js, I am getting this error
TypeError: incoming_form.resolve is not a function
I think you may have misunderstood the internal mechanisms by which Promise objects operate. This is how your code should look:
function incoming_form () {
return new Promise (function (resolve, reject) {
resolve(['fudge', 'fgfdgdf']);
});
}
incoming_form().then(function(results){
console.log ("Results" + results");
})
Note how the promise resolves internally, as opposed in a function call. Whenever a promise resolves, operation (and the arguments that the promise resolves with, in this case an array) is deferred to the closest subsequent then() clause.
Hope this clears some things up!
Use response.json() and then to return the value from promise object.
fetch('http://localhost:3100/comments')
.then(response => response.json())
.then(comments => console.log(comments));

Passing an extra parameter in the middle of a Promise chain

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.

Categories

Resources