resolving values after promise has resolved - javascript

I have a code like this.. I want to fetch some contents and after all have loaded, do something.
So I use Promise.all and access resolved values later. but it is giving values but like Promise {' content here'}. (See console.log..)
I was gonna use Regex to extract it but then i check its type which isnt string but object with no keys? Why?
var request=require('request');
var urls=['someurl','someurl2','someurl3'];
var contents=[];
urls.forEach(function (u) {
contents.push(getContent(u) );
});
Promise.all(contents)
.then(function () {
// All should be loaded by now?
// Promises which are resolved are fulfiled, and values can be accessed later right?
contents.forEach(function (promise) {
var content = Promise.resolve(promise);
console.log(content); // Promise {'test'} ??
console.log(typeof content,Object.keys(content));
// object [] ???
});
}).
catch(function(err) {
//handle error here
});
function getContent(url) {
return new Promise ( function (resolve,reject) {
/** commented and stripped out for testing
request(url, function (err,response, data) {
if(err) {
reject(Error(err));
}
}); **/
resolve("test");
});
}

contents still only holds promises.
You can never directly extract the value of a promise; you can only consume it from a then() callback.
Instead, Promise.all() return a promise for the array of results.
Change your then() call to take that array as a callback parameter and use it directly.

First of all, you're accessing the results in the wrong way:
Promise.all(contents).then( function(data) {
// data holds an array with the return values of the promises
console.log(data);
});
Second thing: you're not creating a Promise correctly, essentially, you're never resolving them in your getContent() function, so you'll never get the data you want!
function getContent(url) {
return new Promise ( function (resolve,reject) {
request(url, function (err,response, data) {
if(err) {
// reject the promise in case of error
reject(Error(err));
} else {
// resolve the promise with the output you need
resolve(data);
}
});
When you call resolve(), the promise gets resolved and the input you give it is passed on.
When all promises you specified in Promise.all() are resolved, the callback will be executed and you'll be able to access the data returned with resolve().

Related

Javascript (NodeJS) promise pending?

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

q- When to return like "defer.resolve(myData); return defer.promise;" VS simply "return myData" in promise chain

I've been trying to write better code on my node.js server and after reading some blog posts like the following:
http://www.codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong/ (angular specific but same concept)
http://bahmutov.calepin.co/linking-promises.html
I am still not sure if I'm returning my data down the promise chain the "right way".
I cannot tell when it's appropriate to return or pass data down a promise like this
case 1
var promise = function () {
var defer = q.defer();
var myData = "hi"
defer.resolve(myData);
return d.promise;
};
or like this.
case 2
var promise = function () {
var myData = "hi"
return myData;
};
I'm assuming is that if I know something will be returned where it's not possible for the promise chain to break then use case 2 but if their is a change it could fail (i.e. it's returning data from a network call but the user is offline) then use case 1 so it can handle both cases. Is that correct or do I have a misunderstanding about how this flow/process works.
In both cases you are returning a result which is instantly known or computed, while you are wrapping it in a promise in the first case. Whether or not you want to do this depends on whether it should be transparent for the caller of your function if the result is computed asynchronously or not. If you return a promise you are free to change the implementation of your function later to compute or retrieve the result asynchronously.
Two hints:
You are not using a promise in case 2 so don't call your function promise.
In the first case you can just return q("hi"); to wrap the literal in a promise.
promise is for those who engage callback hell, which means your jobs are Asynchronous and chained
for a simple case like $.ajax().success(callback1).fail(callback2) is type of promise
3.your case is not Asynchronous, it might be like this:
var promise1 = function() {
//async get file name
}
var promise2 = function(filename) {
var defer = q.defer();
var myData = "hi"
//async
fs.readFile(filename, 'utf-8', function(err, data) {
if (err) {
defer.reject(err);
} else {
defer.resolve(myData);
}
}
}
return d.promise;
};
var promise3 = function(data) {
//use data do something
}
var onError(err) {
console.log(err);
}
var onDone(result) {
console.log(result)
}
//your logic might look like
promise1.then(promise2).then(promise3).catch(onError).done(onDone);

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

Promise.map not waiting for resolution before proceeding to .then()

I've had a problem trying to wrap my mind around JavaScript promises. Here is my lately frustration:
var rp = require('request-promise');
function process1000() {
//gets 1000 objects from DB to process
get1000objects()
.then(function (docs) {
Promise.map(docs, addApiData)
})
.then(function (objects) {
console.log(objects)
})
}
function addApiData(element) {
return rp(url).then(function (res) {
resolve(res);
})
.catch(console.error);
}
When rp(url) is called in addApiData(), it doesn't wait until the function is resolved before beginning the next item in the array that I'm passing to Promise.map in process1000(). As soon as rp(url) is called in addApiData, addApiData is called on the next item in the array. The second .then() function in process1000 is then called, prematurely before everything has had a chance to resolve in Promise.map. I've tried a few different libraries to make my GET request but they're all having this same issue. What am I doing wrong here? Any help would be greatly appreciated.
I think you're looking for something more like this:
var rp = require('request-promise');
function process1000() {
//gets 1000 objects from DB to process
get1000objects()
.then(function (docs) {
return Promise.map(docs, addApiData)
})
.then(function (objects) {
console.log(objects);
})
}
function addApiData(element) {
return rp(url)
.catch(console.error);
}
The main point here is that you need to make sure you're returning the promises, or the next then won't know what to do with its value.
Also, try to avoid the Promise constructor antipattern.
In other words, if you return a promise, you don't need to return then as well.
These two are equivalent:
return rp(url).then(function(res) { return res; });
// and
return rp(url);
They both return a promise (rp(url) returns a promise, and rp(url).then( /* ... */) returns a promise).

Immediately return a resolved promise using AngularJS

I'm trying to get my head around promises in JavaScript (in particular AngularJS).
I have a function in a service, let's call it fooService, that checks if we've loaded some data. If it has, I just want it to return, and if we haven't, we need to load the data and return a promise:
this.update = function(data_loaded) {
if (data_loaded) return; // We've loaded the data, no need to update
var promise = Restangular.all('someBase').customGet('foo/bar').then(function(data) {
// Do something with the data here
}
return promise;
}
I have another function that then calls the update function of fooService like so:
fooService.update(data_loaded).then(function() {
// Do something here when update is finished
})
My issue here is that if we don't need to load the data in the update function, a promise isn't returned, so the .then() is not called in my other function. What should the approach be here - basically I want to return a resolved promise immediately from the update() function if we do not need to get data from the Restangular call?
As your promise use the same syntax as the JavaScript native one, you could use and return an already resolved JavaScript promise : Promise.resolve()
return(Promise.resolve("MyReturnValue"));
The current accepted answer is overly complicated, and abuses the deferred anti pattern. Here is a simpler approach:
this.update = function(data_loaded) {
if (data_loaded) return $q.when(data); // We've loaded the data, no need to update
return Restangular.all('someBase').customGet('foo/bar')
.then(function(data) {
// Do something with the data here
});
};
Or, even further:
this._updatep = null;
this.update = function(data_loaded) { // cached
this._updatep = this._updatep || Restangular.all('someBase') // process in
.customGet('foo/bar'); //.then(..
return this._updatep;
};
AngularJS's $q service will help you here. It is much like Kris Kowal's Q promise library.
When you have an async method that may return a promise or value use the $q.when method. It will take what ever is passed to it, be it a promise or a value and create a promise that will be resolved/rejected based on the promise passed, or resolved if a value is passed.
$q.when( fooService.update(data_loaded) ).then(function(data){
//data will either be the data returned or the data
//passed through from the promise
})
and then in your update function return the data instead of just returning
if (data_loaded) return data_loaded;
Similar to Elo's answer, you can return an already resolved promise using the async/await syntax:
this.update = async (data_loaded) => {
if (data_loaded)
return await null; // Instead of null, you could also return something else
// like a string "Resolved" or an object { status: 200 }
else
return await OtherPromise();
}
You could use the $q.defer() like this:
this.update = function (data_loaded) {
var deferred = $q.defer();
if (data_loaded) {
deferred.resolve(null); // put something that your callback will know the data is loaded or just put your loaded data here.
} else {
Restangular.all('someBase').customGet('foo/bar').then(function(data) {
// Do something here when update is finished
deferred.resolve(data);
}
}
return deferred.promise;
};
Hope this helps.

Categories

Resources