How to grab value of promise and fire function - javascript

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

Related

Rewrite promises function into async function

I'm trying to rewrite promises function into async function
While my promises work
function boxColor (time) {
return new Promise ((res, rej) => {
setTimeout(() => {
res(box.style.backgroundColor = randomColor())
}, time)
})}
I can't make it work with async
async function newBoxColor(time) {
try {
setTimeout(() =>{
return box.style.backgroundColor = randomColor()
}, time)
} catch (error) {
throw error
} }
What is my mistake here?
The async keyword has two effects:
It makes the function return a promise which resolves to the value returned from the function (your function doesn't have a return statement so that is undefined; the return value of the arrow function passed to setTimeout is in a different function).
It allows you to use the await keyword inside that function to make it go to sleep while waiting for another promise to resolve
It is a tool to manage existing promises. It isn't helpful in converting a function which expects a callback to one which returns a promise.
You need to continue to use new Promise to get a Promise which resolves after setTimeout is done.

Why can I await this code but not use .then?

Node.JS 10.15, serverless, lambdas, invoked locally
SAMPLE A) This Works:
export async function main(event) {
const marketName = marketIdToNameMap[event.marketId];
const marketObject = marketDirectory[marketName];
const marketClient = await marketObject.fetchClient();
const marketTime = await marketObject.getTime(marketClient);
console.log(marketTime);
}
SAMPLE B) and this works:
export function main(event) {
const marketName = marketIdToNameMap[event.marketId];
const marketObject = marketDirectory[marketName];
marketObject.fetchClient().then((marketClient)=>{
marketObject.getTime(marketClient).then((result) => {
console.log('<---------------> marker 1 <--------------->');
console.log(result);
});
});
}
SAMPLE C) but this does not:
export async function main(event) {
const marketName = marketIdToNameMap[event.marketId];
const marketObject = marketDirectory[marketName];
const marketClient = await marketObject.fetchClient();
console.log('<---------------> marker 1 <--------------->');
marketObject.getTime(marketClient).then((result) => {
console.log('<---------------> marker 22 <--------------->');
console.log(result);
});
}
the guts of getTime are for all examples:
function getTime(marketClient){
return new Promise((resolve, reject) => {
return marketClient.getTime((err, result) => {
if (err) {
reject(err);
}
resolve(result);
});
}).catch(err => {
throw err;
});
}
clearly, it seems to be an issue with mixing async/awaits with classic promise then-ables. I would expect SAMPLE C to work because getTime() is returning a promise. However, the code simply finishes silently, never hitting the second marker. I have to put the first marker there just to be sure any code is run at all. It feels like i should be able to mix async/await and thenables, but i must not be considering something here.
#adrian, nope
You're neither awaiting nor returning the promise from marketObject.getTime().then(), and this will result in that promise chain executing independently, the main function returning and the process closing. Remember.. then returns a promise too.
the solution is
await marketObject.getTime(marketClient).then(...
or
return marketObject.getTime(marketClient).then(...
either way chains the promise to the main function such that whatever executes it consistently waits for all promises to resolve (or reject).
I suspect Sample B works because the main is not async and Lambda will wait for the event-loop to complete. i.e. it will execute the promise chain even though main returned early.
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
If you don't use callback in your code, AWS Lambda will call it
implicitly and the return value is null. When the callback is called,
AWS Lambda continues the Lambda function invocation until the event
loop is empty.
... and I suspect if you return a Promise (as you do in Sample C) then Lambda will simply terminate the process immediately once it resolves, which is does because you don't await/return the .then() chain, and thus the floating promise chain you've created will not execute.

Promise behavior and printing order

I'm a bit new to JavaScript and i can't figure out why the printing order of the following code is Noam and then Amit and only them.
can someone clarify it?
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
});
}
myPromise().then(function(){thenCall()});
console.log('Noam');
Promise.resolve takes a result which is passed to the then. It does not call the function. Notice the callback to .then.
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
});
}
myPromise().then(function(fn){
console.log(fn); // notice
thenCall()
});
console.log('Noam');
The function inside Promise.resolve should be executed as it will wait for a result to return:
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
}());
}
myPromise().then(function(){thenCall()});
console.log('Noam');
Let's divide the question by the people you're trying to log
Noam
Noam is printed first, because there is no async process in the code. You do use a Promise but it instantly executes the resolve method.
Amit
When Promise.resolve gets invoked, the function in the .then method will be executed. Therefore Amit gets printed in the console correctly.
Yarden and Assaf
Promise.resolve immediately resolves a new Promise and calls therefore the .then method immediately. The argument given to Promise.resolve is the value that will be passed as an argument to the .then method.
To create an actual Promise that either resolves or rejects based on some logic, this should get you started:
var a = true;
function myPromise() {
return new Promise(function (resolve, reject) {
console.log('first');
if (a) {
return setTimeout(function () {
resolve('value_to_pass_to_then');
}, 1000);
}
return reject('value_to_pass_to_catch');
});
}
myPromise()
.then(function (val) { console.log('second'); })
.catch(function (val) {})
The Yarden function is what the promise returned by myPromise() resolves to. But you aren't doing anything with the resolve value:
myPromise().then(function(/* resolve value would go here */){thenCall()});
The value a promise resolves to is the first argument of the function passed to .then. But you don't have an argument there. If you wanted to run that function, you would have to use it as an argument and then call it explicitly (which would in turn call the function that prints Assaf):
function rc() {
console.log('Assaf');
}
function thenCall() {
console.log('Amit');
}
function myPromise() {
return Promise.resolve(function() {
console.log('Yarden');
rc();
});
}
myPromise().then(function(yardenFn) {
thenCall();
yardenFn();
});
console.log('Noam');

Javascript: Return a promise inside async function

Would it make any difference if I have:
async function test () {
const foo = await bar()
return Promise.all([promise1, promise2])
}
instead of:
async function test () {
const foo = await bar()
const [result1, result2] = await Promise.all([promise1, promise2])
// Given that I don't care about result1, result2 in this `test` function
return [result1, result2]
}
I get the same result if I do either. E.g. I can do this for either case:
test().then(([result1, result2]) => { ... })
but I am more curious about the underlying mechanism how they both behave the same.
In other words, how does async function handle it if inside the function I return a promise instead of a value?
I think you're effectively calling synchronous-like functions with await within the promise chain which, according to this answer:
You are perfectly free to call either synchronous functions within the
promise chain (from within .then() handlers) or asynchronous functions
that then return a new promise.
When you return something from a .then() handler, you can return
either a value (which becomes the resolved value of the parent
promise) or you can return another promise (which chains onto the
previous promise) or you can throw which works like returning a
rejected promise (the promise chain becomes rejected).
I would think the way async functions works in respect to the return value is it checks whether that value is wrapped in a Promise object, and if not, does it automatically. If you explicitly return a Promise, then the function does nothing with it. I tested this out by returning a new Promise inside an async function:
async function test(){
var duration = resolveAfter(500)
return new Promise((resolve, reject) =>{})
}
var neverresolved = test()
The result is neverresolved contains a Promise that's always in the pending state, as expected.
Both functions return a Promise.
const [result1, result2] = await Promise.all([promise1, promise2])
//HERE
return [result1, result2]
Where I wrote HERE you can access to result1 and result2 var that are the results of the promises.
await is an alternative to call then on Promise and its form is also more readable than
Promise.all([promise1, promise2]).then(function(results){
});
If you have multiple sequentially requests using await is a better choice
var response1= await promise1
var response2=await promise2
against
promise1.then(function(){
promise2.then(function(){
promise3.then(function(){
})
})
})
EDIT
In the first function the keyword async is useless, the function test will return a Promise
The second function will return a Promise where you see the keyword await. When the awaited promise will resolved the execution inside the function continue and you can access to result of the promise
EDIT 1
MaybeI understand what you mean, the async keyword encapsulate your return value into a promise that has as resolved value what you have returned

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