How can i access a returned value from then() in JavaScript?
I have the following function:
function getResult(){
var promise = _myService.getAge();
var getResultPromise = promise.then(function(age){
return age;
})
return getResultPromise; //How do i get the age (value) here? *see image*
}
Or how would i access the value in the $$state object below?
How about this:
//The simple solution, this is how to use a Promise:
let _myService = {
getAge: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(3)
}, 500);
})
}
};
function getResult() {
_myService.getAge().then(function(age) {
console.log(age);
});
}
getResult();
//OR, maybe closer to OP's intended implementation, put the value in an outer state:
let outerState = {
age: 0
};
setTimeout(function() {
console.log(outerState)
}, 450);
let _myService2 = {
getAge: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(8)
}, 750);
})
}
};
function addAgeToOuterState() {
pState = new Promise(function(resolve, reject) {
_myService2.getAge().then(function(newAge) {
outerState.age = newAge;
resolve(outerState);
});
});
pState.then(function() {
console.log(outerState);
});
return pState;
}
addAgeToOuterState()
//for fun
.then(function(outer) {
console.log(outer); //state is still here
});
Related
Here's the code
console.log("Before");
const p = getUser(1);
p.then(user => {
console.log(user);
getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
console.log("after");
function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
I'm having trouble with consuming the promise returned by getRepositories() function. Above is my implementation but it doesn't work and returns undefined (instead of the array [repo1, repo2, repo3]).
Here's the output:
I want the array to return after logging "Calling Api for Zain" but the undefined is shown before it, but I don't know why, so I need help regarding this.
You need a return statement in your first .then:
p.then(user => {
console.log(user);
return getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”. It’s surprisingly easy to understand and use.
async function init() {
console.log("Before");
const user = await getUser(1);
console.log(user);
const repos = await getRepositories(user.github);
console.log(repos);
console.log("after");
}
init();
async function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
async function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
For more information: https://javascript.info/async-await
This question already has answers here:
JS ES6 Promise Chaining
(5 answers)
Closed 4 years ago.
I'm trying to make a game using promises and call them only on mouse click (down and up), passing the state of the game from the first promise (A) to the last one (C), updating it. If promise B executes properly, promise C does not execute at all. Is it possible to chain several promises and execute them only when the event is triggered?
class A {
static draw() {
return new Promise((resolve) => {
const state = {name: 'Alex'};
resolve(state);
})
}
}
class B {
static draw(state) {
const div = document.querySelector('.app');
div.addEventListener('mousedown', () => {
return new Promise((resolve) => {
state.lastname = 'Johnson';
console.log('state with ln ' + state)
resolve(state);
})
})
}
}
class C {
static draw(state) {
const div = document.querySelector('.app');
div.addEventListener('mouseup', () => {
return new Promise((resolve) => {
state.age = '23';
console.log('state with age ' + state)
resolve(state);
})
})
}
}
A.draw()
.then(res => {
B.draw(res)
.then(res => C.draw(res))
})
Your promises are back to front. They need to be created in the scope of your draw functions (and returned by those functions) and then resolved within the callbacks, e.g.:
class B {
static draw(state) {
const div = document.querySelector('.app');
return new Promise((resolve) => {
div.addEventListener('mousedown', () => {
state.lastname = 'Johnson';
console.log('state with ln ' + state)
resolve(state);
});
});
}
}
However, such a Promise can only be resolved once, which rather begs the question as to whether promises are even the right model for what you're trying to achieve.
Heres a quick snippet on chaining promises
var firstMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('first method completed');
resolve({data: '123'});
}, 2000);
});
return promise;
};
var secondMethod = function(someStuff) {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('second method completed');
resolve({newData: someStuff.data + ' some more data'});
}, 2000);
});
return promise;
};
var thirdMethod = function(someStuff) {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('third method completed');
resolve({result: someStuff.newData});
}, 3000);
});
return promise;
};
firstMethod()
.then(secondMethod)
.then(thirdMethod);
I want to create promises chain and then dynamically add as many promises to it as it's needed. These additions could be in some cycle with dynamic number of steps so that I can't use chain like .then().then().then... Code bellow works improperly but you'll get the idea. Result should be a console logged 3000, 4000, 5000 numbers in 3, 4 and 5 seconds consequently but actually doesn't work that way. Any ideas?
let launchChain = function(delay)
{
return new Promise((resolve: Function, reject: Function) => {
setTimeout(() => {
console.log(delay);
resolve();
}, delay)
})
}
let chain = launchChain(3000);
chain.then(function () {
return launchChain(4000);
})
chain.then(function () {
return launchChain(5000);
})
So used reduce and this site
var delays = [0, 1000, 2000, 3000, 4000];
function workMyCollection(arr) {
return arr.reduce(function(promise, item) {
return promise.then(function() {
return launchChain(item);
});
// uses this orignal promise to start the chaining.
}, Promise.resolve());
}
function launchChain(delay) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(delay);
resolve();
}, delay);
});
}
workMyCollection(delays);
[EDIT] : Another way
var delays = [0, 1000, 2000, 3000, 4000];
var currentPromise = Promise.resolve();
for (let i = 0; i < delays.length; i++) {
// let makes i block scope .. var would not have done that
currentPromise = currentPromise.then(function() {
return launchChain(delays[i]);
});
}
function launchChain(delay) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(delay);
resolve();
}, delay);
});
}
Do let me know if this worked for you :)
thanks to this question I learned a lot!
function run(delay){
let chain = launchChain(delay);
chain.then(function() {
run(delay+1000);
});
}
run(3000);
Thanks sinhavartika! It works! But I actually took example from here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
and changed it a bit and now I use it in my project in the following way:
/**
* Runs promises from promise array in chained manner
*
* #param {array} arr - promise arr
* #return {Object} promise object
*/
function runPromiseInSequense(arr) {
return arr.reduce((promiseChain, currentPromise) => {
return promiseChain.then((chainedResult) => {
return currentPromise(chainedResult)
.then((res) => res)
})
}, Promise.resolve());
}
var promiseArr = [];
function addToChain(delay)
{
promiseArr.push(function (delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(delay);
resolve();
}, delay)
});
}.bind(this, delay))
}
addToChain(1000);
addToChain(2000);
addToChain(3000);
addToChain(4000);
runPromiseInSequense(promiseArr);
I am trying to make two separate DB calls in a promise chain, although for testing purposes, the first call is replaced by a simple string that gets passed along.
My problem is that I can't access the variable msg in my second promise (where I try to set context.foo = msg.
router.route("/")
.get(function(request, response) {
var session = request.session;
return new Promise(function(resolve, reject) {
resolve("h!");
}).then(function(msg){
return new Promise(function(resolve, reject) {
Snippet.find({}, function(error, data) {
let context = {
snippets: data.map(function(snippet) {
return {
name: snippet.name,
snippet: snippet.snippet,
createdAt: snippet.createdAt,
user: snippet.user,
id: snippet._id
};
}),
foo: msg
};
resolve(context);
});
});
}).then(function(context){
response.render("start/index", context);
}).catch(function(err){
response.end(err);
});
});
Another attempt, here trying to bind the router to the promise...
router.route("/")
.get(function(request, response) {
var session = request.session;
return new Promise(function(resolve, reject) {
resolve("hi!");
}).then(function(msg){
router.msg = msg;
return new Promise(function(resolve, reject) {
Snippet.find({}, function(error, data) {
let context = {
snippets: data.map(function(snippet) {
return {
name: snippet.name,
snippet: snippet.snippet,
createdAt: snippet.createdAt,
user: snippet.user,
id: snippet._id
};
}),
foo: this.msg
};
resolve(context);
}.bind(router));
});
A third attempt...
router.route("/")
.get(function(request, response) {
var session = request.session;
return new Promise(function(resolve, reject) {
context.msg = "hi!";
resolve(context);
}).then(function(context){
return new Promise(function(resolve, reject) {
Snippet.find({}, function(error, data) {
context.snippets = {
snippets: data.map(function(snippet) {
return {
name: snippet.name,
snippet: snippet.snippet,
createdAt: snippet.createdAt,
user: snippet.user,
id: snippet._id
};
}),
};
resolve(context);
});
});
}).then(function(context){
response.render("start/index", context);
}).catch(function(err){
response.end(err);
});
});
So the basic problem is always, how can I "inject" or make use of a variable inside the Promise scope, when I have no surrounding object, no "this" to attaach it to =)
Using bluebird's powerful Promise.coroutine():
router.route("/")
.get(Promise.coroutine(function*(request, response) {
try {
const dbResult1 = yield getValueFromDatabaseAsync(/* w/e */);
const dbResult2 = yield getValueFromDatabaseAsync(/* w/e, can be dbResult1 */);
const context = {...}; // use dbResult1 and dbResult2 here normally
response.render("start/index", context);
} catch (err) {
response.end(err);
}
}));
it seems the following works without throwing an error:
var p = new Promise (function (resolve, reject) {
window.setTimeout(function() {
reject('ko');
}, 1000);
});
p.then(function (value) { console.log(value); })
.catch(function () { console.log('catched'); });
// → 'catched'
But this throws an error:
var p = new Promise (function (resolve, reject) {
window.setTimeout(function() {
p.catch(function () { console.log('catched'); });
reject('ko');
}, 1000);
});
p.then(function (value) { console.log(value); });
// → 'catched'
// Uncaught (in promise) ko
Any wild guesses to why ?
The .catch must be directly chained after .then. Even if you write it this way, it will still report uncaught:
var p = new Promise(function(resolve, reject) {
window.setTimeout(function() {
//p.catch(function () { console.log('catched'); });
console.log(p)
reject('ko');
}, 1000);
});
p.then(function(value) {
console.log(value);
});
p.catch(function() {
console.log('catched');
});
The reason for this is that if you don't chain it like that, the .catch function doesn't receive the return value that gets generated when you call .then