Requesting Function Response in another function - javascript

I have those two functions where i call "http" from "Count" the "http" return promise. I want to use the return value of "http" in "Count". What I receive now is Undefined !!!
What I'm missing ?
Count Function :
Parse.Cloud.define('count', function(request, response) {
var query = new Parse.Query('MyS');
query.equalTo("Notify", true);
query.notEqualTo ("MainEventCode", '5');
query.find({
success: function(results) {
Parse.Cloud.run('http', {params : results}).then(
function(httpResponse) {
console.log('httpResponse is : ' + httpResponse.length);
response.success('Done !');
}, function(error) {
console.error(error);
});
},
error: function(error) {
response.error(error);
}
});
});
http Function :
Parse.Cloud.define('http', function(request, response) {
var query = new Parse.Query(Parse.Installation);
.
.
.
}

Relying on calling your own functions through an external interface is not a very good practice.
Now that you've realized you're going to need the same code for a different purpose, you should take the time to refactor your code such that you don't need to call the 'http' handler through Parse.Cloud.run():
function doHttp(params) {
// original implementation here
}
Parse.Cloud.define('http', function(request, response) {
doHttp(request.params)
.then(response.success)
.fail(response.error);
}
Parse.Cloud.define('count', function(request, response)) {
var query = new Parse.Query('MyS');
query.equalTo("Notify", true);
query.notEqualTo ("MainEventCode", '5');
query.find()
.then(doHttp) // doHttp will receive the results from `query` as its parameter
.then(function(httpResponses) {
// httpResponses is an array-like object as per the other question:
httpResponses = Array.prototype.slice.call(httpResponses);
httpResponses.forEach(function (response) {
console.log('httpResponse is : ' + response.length);
});
}).fail(response.error);
}
I've taken a look at the other question and as far as the implementation of count goes, I believe you're missing the point that 'http' is returning arguments, which is only an Array-like object.
This should be okay if Parse.Cloud.run runs your function on another virtual machine, but this kind of weird behaviour is another symptom of not refactoring and reusing your code through an external call (an HTTP request inside their infrastructure with JSON passing! It might greatly reduce performance and count against your requests/second quota). If Parse instead does some magic to call your function directly as if it was defined on the same environment, you're going to have problems with it not being an actual Array.
You should modify that function to return a proper array if possible. Parse CloudCode has a version of the Underscore library:
// on http
var _ = require('underscore');
Parse.Promise.when(promises).then(function() {
var results = _.toArray(arguments) // equivalent to Array.prototype.slice above
response.success(results);
}

I think what you're asking is how to use an externally callable cloud function as a step in a bigger cloud procedure. Here's how to do it: (#paolobueno has it essentially correct, with only a couple mistakes in the details).
First, let's convert that 'http' cloud function to a regular JS function. All we need to do is factor out the request and response objects. (#paolobueno has a very good idea to use underscorejs, but I won't here because its another new thing to learn).
// for each object passed in objects, make an http request
// return a promise to complete all of these requests
function makeRequestsWithObjects(objects) {
// underscorejs map() function would make this an almost one-liner
var promises = [];
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
promises.push(makeRequestWithObject(object));
}
return Parse.Promise.when(promises);
};
// return a promise to do just one http request
function makeRequestWithObject(object) {
var url = 'http://185.xxxxxxx'+ object +'&languagePath=en';
return Parse.Cloud.httpRequest({ url:url });
}
It looks like you want the updated cloud function -- rather than use params from the client -- to first make a query and use the results of that query as parameters to the http calling function. Here's how to do that. (Again, using #paolobueno's EXCELLENT practice of factoring into promise-returning functions...)
// return a promise to find MyS instances
function findMyS() {
var query = new Parse.Query('MyS');
query.equalTo("Notify", true);
query.notEqualTo ("MainEventCode", '5');
return query.find();
}
Now we have everything needed to make a clear, simple public function...
Parse.Cloud.define('count', function(request, response) {
findMyS().then(function(objects) {
return makeRequestsWithObjects(objects);
}).then(function(result) {
response.success(result);
} , function(error) {
response.error(error);
});
});

Related

sails.js node.js Parse JSON on controller

In my controller called MapController I'm doing a function to do a parse of remote json files, and from an if-else structure add some values in an array called "parsewebservice", apparently everything is working fine but console.log ( parsewebservice); is not returning the values that were passed to the array "parsewebservice" in the place where it is returning it empty. But when I put it inside the forEach it returns, but everything cluttered and repeated then is not the right way.
I wanted to know why the values that were passed to the array "parsewebservice" are not going along with the variable after populada and what would be the correct way to do it?
Here is my code below:
/**
* MapController
*
* #description :: Server-side logic for managing Maps
* #help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
module.exports = {
index: function(req, res, next) {
Data.find(function foundData(err, datas) {
if (err) return next(err);
var parsewebservice = [];
datas.forEach(function(data, index) {
var req = require("request");
var url = data.address + "?f=pjson";
req(url, function(err, res, retorno) {
if (err) {
console.log(err);
} else {
var camadas = JSON.parse(retorno);
if (camadas.mapName) {
camadas.layers.forEach(function(campo, i) {
if (campo.subLayerIds != null) {
} else if (campo.subLayerIds == null) {
parsewebservice.push([i, "dynamicMapLayer", campo.name, data.address]);
}
});
} else if (camadas.serviceDataType) {
parsewebservice.push([null, "imageMapLayer", camadas.name, data.address]);
} else if (camadas.type) {
parsewebservice.push([null, "featureLayer", camadas.name, data.address]);
}
}
});
});
console.log(parsewebservice);
});
},
};
My first comment has to be that you should not combine function(req, res) with var req = require('request')... you lose your access to the original req object!
So, you need to run a list of async tasks, and do something when they are all complete. That will never be entirely easy, and no matter what, you will have to get used to the idea that your code does not run from top to bottom as you've written it. Your console.log at the bottom runs before any of the callbacks (functions you pass in) you pass to your external requests.
The right way to do this is to use promises. It looks like you are using this request library, whose returned requests can only accept callbacks, not be returned as promises. You can create your own promise wrapper for them, or use an alternative library (several are recommended on the page).
I don't want to write a whole intro-to-promises right here, so what I will do is give you a less pretty, but maybe more understandable way to run some code at the completion of all your requests.
Data.find(function foundData(err, datas) {
if (err) return next(err);
var parsewebservice = [];
// here we will write some code that we will run once per returned data
var processResponse = function(resp) {
parsewebservice.push(resp);
if(parsewebservice.length >= datas.length) {
// we are done, that was the final request
console.log(parsewebservice);
return res.send({data: parsewebservice)}); // or whatever
}
};
datas.forEach(function(data, index) {
var request = require("request");
var url = data.address + "?f=pjson";
request(url, function(err, res, retorno) {
// do some processing of retorno...
// call our function to handle the result
processResponse(retorno);
});
});
console.log(parsewebservice); // still an empty array here
});
I solved the problem.
the "request" module is asynchronous so we need to wait for it to respond and then send the response to the view.
To do this we created a function called "foo" to contain the foreach and the request, we made a callback of that function and finally we made the response (res.view) within that function, so that the controller response would only be sent after the response of the "foo" function to the callback. So we were able to parse.json the data from the "data" collection using foreach and the "request" module and send the objects to the view.
Many thanks to all who have helped me, my sincere thanks.

In parse object.save(); doesnt return anything why?

Here is my code, it loops through forEach and prints out '1' but never returns from object.save() & never prints out 2, 3 or anything else. I have tried a bunch of other ways but none seems to work.
Note: response.succes(or error) is not being called anywhere, the code is definitely waiting for object.save() to be completed.
var promise = new Parse.Promise();
var query = new Parse.Query("SomeClass");
query.find().then(function(results) {
var promises = [];
results.forEach(function(object) {
object.set("SomeColumnName", true);
console.log('1');
promises.push(object.save(null, {
success: function(result) {
alert('2');
return ;
},
error: function(result, error) {
alert('3');
return ;
}
}));
});
Parse.Promise.when(promises).then(function() {
console.log('inside resolve');
promise.resolve();
}, function() {
console.log('inside reject');
promise.reject();
});
});
return promise;
You're on the right track, but you should take advantage of the fact that most of the sdk functions create and return promises for you. With those, you can substantially simplify the code:
// very handy utility library that provides _.each among many other things
// www.underscorejs.org
var _ = require('underscore');
// answer a promise to modify all instances of SomeClass
function changeSomeClass() {
var query = new Parse.Query("SomeClass");
// if there are more than 100 rows, set query.limit up to 1k
return query.find().then(function(results) { // find returns a promise
_.each(results, function(result) {
result.set("SomeColumnName", true);
});
return Parse.Object.saveAll(results); // and saveAll returns a promise
});
}
Wrap it in a cloud function and call success/error like this:
Parse.Cloud.define("changeSomeClass", function(request, response) {
changeSomeClass().then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
You can only have one Parse request happening at a time for each object. If multiple requests are sent, all but the first are ignored. You're probably trying to do this while other threads are making Parse requests for those objects. I know that if you save an object, it also saves it's child objects, so you could be hitting a problem with that. Make sure you do as much as you can in background threads with completion blocks, or use saveEventually / fetchEventually where possible.

Make jquery jqxhr act like already sending request

i have SendRequest object and that class has a function like
request: function(args)
{
return $.ajax.apply(null, args);
};
then a lot of class use SendRequest object to get server response
var prom = SendRequest.request(
{
type: 'GET',
url: _this.uri
});
return $.when(prom).done(function(response)
{
.... do something
});
My goal is in SendRequest.request need to check on window.localStorage first.
Whether already has a value or not, if has not any value before then send the request.
Otherwise, if already value on localStorage then return $.ajax() object with that saved value before.
request: function(args)
{
var ls = window.localStorage;
var savedResponse = ls.getItem(args.url);
if (savedResponse !=== null)
{
var result = $.ajax();
result.responseText = savedResponse;
result.readyState = 4;
result.status = 'OK';
return result;
}
else
{
return $.ajax.apply(null, args);
}
};
but unfortunately its did not work :(
I've been looking but can not find some case like me
I already try this way to
how to fool jqXHR to succeed always
but its not help much
The reason this doesn't work is that although you've created a fake jqXHR object that's the response from $.ajax, that object isn't actually the parameter that's supplied to the .done callback - it's actually the third parameter.
Also, IMHO you shouldn't really use $.when to "promisify" a single non-promise object. It's intended to handle synchronisation between multiple promises and the fact that it wraps each non-promise into a new promise is just a side effect.
Instead, you should create a new promise that is already "resolved" with the appropriate data:
if (savedResponse != null) {
return $.Deferred(function() {
// retrieve relevant fields from localStorage
...
this.resolve([data, textStatus, jqXHR]);
}).promise();
} else {
// perform real AJAX request
return $.ajax.apply($, args);
}
Alternatively, consider just memoizing the return data itself (for successful calls), not the whole response triple.
You may also find this presentation that I gave at jQuery UK 2013 of use - http://www.slideshare.net/RayBellis/memoizing-withindexeddb

Structuring promises within angularjs

I have done a lot of reading around this, but ultimately the tutorials and guides I have found differ too much for me to get a decent grasp on this concept.
This is what I want to achieve:
1) Simple http request from our server [Any API for demonstration]
2) Run a function with data from (1). [Remove a property from the object]
3) Use result and length of (2) to run a loop of $http requests to our server. [Or any server]
4) This will result in 6 different objects. Run a function on these 6 objects. [Add a property]
5) Once ALL of this is done, run a separate function [Log "finished"]
How can this be achieved using promises? How do I pass data from (1) via a promise to (2)? Is this the right way to achieve what I need to do?
If anyone can show me how this should be structured it would be immensely helpful; I have kept the functions as simple as possible for this question.
Yes, promises are very nice to structure solutions for this kind of problems.
Simplified solution (more or less pseudo-code):
$http(...)
.then(function(response) {
// do something with response, for example:
var list = reponse.data.list;
// return it so that you can use it in the next 'then'.
return list;
})
.then(function(list) {
var promises = [];
angular.forEach(list, function(item) {
// perform a request for each item
var promise = $http(...).then(function(itemResponse) {
itemResponse.extraProperty = true;
return itemResponse;
});
// we make an array of promises
promises.push(promise);
});
// combine all promises into one and return it for the next then()
return $q.all(promises);
})
.then(function(itemsList) {
// itemsList is now an array of all parsed item responses.
console.log(itemsList);
});
(Hopefully this is right, I did not tested it.)
As you can see, you can return values in a callback to pass it to the next then(), or you can pass a promise, and this will result in calling the next callback when it resolves. $q.all() is used to combine multiple promises into one and resolve if all are resolved.
Edit: I realised that you can optionally leave out these three lines:
return list;
})
.then(function(list) {
But it is nice syntax though, because the separation of tasks is more visible.
Check code below, it could contains syntax error, the important is the structure. Step3 contains multiple(6) $http requests, it waits until the last request response to return a unique response object (array) containing response for each $http requets.
//Step 1
var Step1 = function () {
$http.get('api/controller').success(function (resp) {
var object1 = resp;
Step2(object1);
Step3(object1).then(function (resp) {
//resp.data is an array containing the response of each $http request
Step4(resp);
Step5();
});
});
}
//Step2
var Step2 = function(obj){
//do whatever with the object
}
//Step3
var Step3 = function (object1) {
var call = $q.defer();
var get1 = $http.get(object1[0].url);
var get2 = $http.get(object[1].url2);
//...
var get6 = $http.get(object[5].url6);
$q.all([get1, get2,..get6]).then(function (resp) {
call.resolve(resp);
});
return call.promise;
}
//Step4
var Step4 = function (resp) {
for (var i=0; i<resp.data.lenght;i++){
DoWhatEver(resp.data[i]);
};
}
//Step5
var Step5 = function () {
alert("Finished");
}
Step1(); //Call Step1 function
Don't know why you have difficulty implementing this, but maybe $q.all() is what you're missing:
var config1={method:'GET',url:'/api/...'};
$http(config1).success(function(resultsFrom1){
functionForResultsOf1(resultsFrom1);
})
var functionForResultsOf1 = function(resultsOf1){
//remove something from the result, assuming this is a synchronous operation
resultsOf1.splice()...;
var promises=makePromises(*pass whatever you want*);
$q.all(promises).then(function(aggregateOfAllCallsToServer){
angular.forEach(aggregateOfAllCallsToServer,function(data){
//do something to data from each call to the server
})
console.log("finished");
})
}
var makePromises = function(serverUrls){
var promises = [];
angular.forEach(serverUrls, function(url) {
var promise=$http({
url : '/api/'+url,
method: 'GET',
})
promises.push(promise);
});
return $q.all(promises);
}

How to fetch an object in Parse Cloud Code

I am working on a parse cloud code function which performs a query and filters the results afterwards. These are my first lines of code written in JavaScript, so I have no clue how to solve the following problem.
The problem is, that my filter predicate needs some elements stored in the someArray variable. All elements of someArray aren't fetched yet. But fetching an an Parse.Object is a asynchronous call, so I have no chance to return trueor false expected by filter().
How can I solve this problem?
Or I am misinterpreting the fact, that when I don't fetch the arrayElement
console.log("arrayElement with name: ".concat(typeof(arrayElement), arrayElement.get("name")));
prints
arrayElement with name:objectundefiend
although I know that Object represented by arrayElment has a name-column which is always defined?
//The cloud code
Parse.Cloud.define("search", function(request, response) {
var query = new Parse.Query("Location");
query.withinKilometers("gps", request.params.searchLocation, request.params.searchRadius / 1000);
query.find({
success: function(results) {
// results is an array of Parse.Object.
var locations = results.filter(function(location) {
console.log("Location with name: ".concat(location.get("name")));
var someArray = location.get("someArray");
if (someArray instanceof Array) {
console.log("The array of this location has ".concat(someArray.length, " elements."));
someArray.forEach(function(arrayElement) {
arrayElement.fetch().then(
function(fetchedArrayElement) {
// the object was fetched successfully.
console.log("arrayElement with name: ".concat(typeof(fetchedArrayElement), fetchedArrayElement.get("name")));
if (menuItem) {};
return true;
},
function(error) {
// the fetch failed.
console.log("fetch failed");
});
});
}
});
response.success(locations);
},
error: function(error) {
// error is an instance of Parse.Error.
response.error(error);
}
});
});
some useful links:
Parse JavaScript SDK API
Parse Cloud Code Guide
If I'm reading this right, you've got an array column of Parse Objects. You should use the include method on your query so that the objects are fetched in the initial query.
query.include('someArray');
I don't think you'll want to use a filter, and should take a look at the Promises documentation here: https://parse.com/docs/js_guide#promises
You're right that since it's asynchronous, you need to wait for everything to be done before calling response.success which doesn't currently happen in the code. Promises and defining your own async functions that use Promises is a great way of chaining functionality and waiting for groups of functions to complete before going forward.
If all you wanted to do what include that column, the whole thing should just be:
Parse.Cloud.define("search", function(request, response) {
var query = new Parse.Query("Location");
query.include('someArray');
query.withinKilometers("gps", request.params.searchLocation, request.params.searchRadius / 1000);
query.find().then(function(results) {
response.success(locations);
}, function(error) {
response.error(error);
});
});

Categories

Resources