Saving data using promises - javascript

On Parse.com I have the following function, and my question follows:
function myFunction(array, value) {
var logMessage;
logMessage = "array: " + array.length.toString();
console.log(logMessage);
if (!array.length) return;
if (!value) value = Math.min(10, array.length);
if (array[array.length - 1].get("advertisePointNumber") >= value) return;
var classPromise;
array[array.length - 1].set("advertisePointNumber", value);
logMessage = "(BIS)array: " + array.length.toString();
console.log(logMessage);
classPromise = (array[array.length - 1].save(null, {}).then(function (object) {
logMessage = "HERE I AM!!!";
console.log(logMessage);
if (array.length == 1) return;
array.splice(array.length - 1, 1);
return myFunction(array, value);
}, function (error) {
// saving the object failed.
console.log("error:" + error);
}));
logMessage = "(TER)array: " + array.length.toString();
console.log(logMessage);
return Parse.Promise.when(classPromise);
}
The question is what am I missing? I never see the message "HERE I AM!!!" (and no error either) in the logs and as a consequence the recursive call that I wish is not working.
I have successfully used similar code in the past, when reading data. Here I am saving data. I must be doing something the wrong way. What is it?
Update to the question:
Calling this function with the following line of code:
myFunction(myArray, 0);
I get the log below:
I2015-06-22T07:05:34.160Z]myArray: 2 // Number of elements in the initial Array.
I2015-06-22T07:05:34.161Z]array: 2
I2015-06-22T07:05:34.162Z](BIS)array: 2
I2015-06-22T07:05:34.163Z](TER)array: 2
I would expect to see :
I2015-06-22T07:0.....]array: 1
after the above but I do not see anything.

Instead of going for recursive, you can try this:
classPromise = array.map(function(obj){ return obj.save();});
in es6, same thing can be:
classPromise = array.map(obj => obj.save());
Edit
You can reduce the whole function to:
function myFunction(array, value) {
if ( !array || !array.length) return;
console.log("array: " + array.length);
if (!value) value = Math.min(10, array.length);
var pSave=[], i = array.length, v2=(value)? value : Math.min(10, i);
while(i>0 && array[i-1].get("advertisePointNumber") >= value){
array[i - 1].set("advertisePointNumber", value);
pSave.push(array[i - 1].save());
console.log("(BIS)array: " + i);
i--;
v2=(value)? value : Math.min(10, i);
}
return Parse.Promise.when(pSave);
}
if you wanted it to be saved sequentially,
...
var pSave = Parse.Promise.as(1),
...
pSave.then(function(){
return array[i-1].save();
});
...
return pSave;
}

You don't need to pass null as the 1st parameter
You don't need to use both save with options (2nd parameter), and save with promises chain (.then)
So, just remove both the first and the second parameter of save function as follows
array[array.length - 1].save().then(...
Updated Answer
You should use multiple save calls in promises chain instead of recursive one like the below
function myFunction(array, value) {
var logMessage;
logMessage = "array: " + array.length.toString();
console.log(logMessage);
if (!array.length) return;
if (!value) value = Math.min(10, array.length);
var savePromises = Parse.Promise.as();
array.map(function(element, index) {
// Calculate value based on your needs
if(element.get("advertisePointNumber") < value) {
element.set("advertisePointNumber", value);
}
savePromises = savePromises.then(function() {
return element.save();
});
});
return savePromises.then(function (object) {
logMessage = "HERE I AM!!!";
console.log(logMessage);
}, function (error) {
// saving the object failed.
console.log("error:" + error);
});
}
OR if you have the option to make cloud code to save them in one request, you should do, to reduce network requests

Related

Sorting a list based on user input on a webpage

I'm attempting to write a webpage that presents the user with two options from a list and asks them which is better. I repeat this until the list is sorted. I am having trouble understanding how I can do this in javascript. I've tried a few things, but none of them have worked yet.
If this was in, say, C++, I would just write a class and then overload the < operator to ask for user input via cin or whatever, but that doesn't really work in a webpage. I'm attempting something similar with:
class Character {
constructor(initName, initPicture, initColor) {
this.name = initName;
this.picture = initPicture;
this.color = initColor;
}
async set1() {
console.log("should display " + this.name);
document.getElementById("pic1").src = this.picture;
document.getElementById("name1").innerHTML = this.name;
document.getElementById("character1").style.background = this.color;
console.log("displayed " + this.name);
}
async set2() {
console.log("should display " + this.name);
document.getElementById("pic2").src = this.picture;
document.getElementById("name2").innerHTML = this.name;
document.getElementById("character2").style.background = this.color;
console.log("displayed " + this.name);
}
}
var decision = false;
async function compare(a, b) {
console.log("comparing " + a.name + " to " + b.name);
a.set1();
b.set2();
console.log("after display");
const nameA = a.name;
const nameB = b.name;
/*while (!decision) {
}*/
// var result = prompt("Who is better, " + a.name + " or " + b.name
+ "?");
let comparison = 0;
if (result === nameA) {
comparison = 1;
}
else if (result === nameB) {
comparison = 0;
}
console.log(comparison);
return comparison;
}
Essentially, the two commented lines were two ways of trying to see what would happen if the function was stalled. When this happens, nothing is rendered to the screen via set1 or set2 (which I know are called because of the console.log).
Eventually, I plan to store the result of the comparison in a database and check to see if the comparison has already been made first. The user will choose through clicking on one of the divs (not implemented yet).
I'm not really looking to 'debug' my code per-se since it technically works; I'm just not sure how to approach this problem. I don't think that the way I am doing it now is the best.
By the way, I'm not using the library sort function since it doesn't like async functions.
What kind of algorithm/srtucture would you use to write a webpage that sorts a list based on the user choosing which is greater?
Everything you do in javascript is somehow async (except promt), so you just have to make it possible to await the user clicking one of the divs. For that we just build a Promise that resolves when the click event occurs on a certain element:
function wasClicked(el) {
return new Promise((resolve) => {
el.addEventListener("click", function handler() {
el.removeEventListener("click", handler);
resolve(el);
});
});
}
Then you can change your comparison to:
static async function compare(a, b) { // <- should be static
console.log("comparing " + a.name + " to " + b.name);
a.set1();
b.set2();
console.log("after display");
const pic1 = document.getElementById("pic1");
const pic2 = document.getElementById("pic2");
const choice = await Promise.race(wasClicked(pick), wasClicked(pic2));
return choice === pic1 ? 1 : -1;
}
Now we only need a way to sort an array asynchronoulsy, but thats quite easy:
async function asyncSort(array, comparator) {
for(let i = 0; i < array.length - 1; i++) {
if(await comparator(array[i], array[i + 1]) < 0) {
([array[i], array[i + 1]] = [[array[i + 1], array[i]]);
i -= 2;
}
}
}
So you can now do:
asyncSort(someArray, Character.compare);
PS: classes should by convention just contain methods that are "traits" of the class, e.g. Character.speak(), neither set1 nor set2 do that so they should not be methods of Character

Executing callback in ascending order

Attached is the problem and the solution code I wrote. Basically callback should console log the output in ascending order not the order in which it received.
function processRequest(i, callback) {
setTimeout(function() {
callback('Action processed ' + i);
}, Math.random() * 1000);
}
callAction(6);
callAction(count) {
//write code here
}
expected output>>
Action processed 1
Action processed 2
Action processed 3
Action processed 4
Action processed 5
Action processed 6
I know this is not the best way to solve this. Can someone rate my solution and possibly suggest a better way? Something Async I am guessing?
Much appreciated! Thanks.
function processRequest(i, callback) {
setTimeout(function() {
callback('Action processed ' + i);
}, Math.random() * 1000);
}
callAction(6);
function callAction(count) {
const arr = [];
let counter = 0;
for (let i = 1; i <= count; i++) {
arr[i - 1] = i;
}
for (let i = 1; i <= count; i++) {
processRequest(i, function(str) {
counter++;
let currentActionNum = parseInt(str.match(/\d+/g));
let message = str.substr(0, str.indexOf(currentActionNum));
if (currentActionNum === arr[0]) {
console.log(message + currentActionNum);
arr.shift();
}
if (counter === count) {
for (let i = arr[0]; i <= count; i++) {
console.log(message + i);
}
}
});
}
}
Your task is not to use super-complicated processing to rewrite the outputs to appear in the correct order, but to ensure that the 6 processes run sequentially. You can do that with a simple recursive approach:
function callAction(count) {
if (count > 1)
processRequest(7 - count, result => {
// ^^^^^^^^^ ok, that part is a bit weird
console.log(result);
callAction(count - 1);
});
}
I think what the interviewer want you to do is to make sure these processes would run in the right order (the 'real-life' process would be different, not just print some string). So, here is a better solution:
function callAction(count){
i = 1;
cb = function(str){
console.log(str)
count-i++ && processRequest(i, cb) //'same' as: if (count-i++>0) then ...
}
processRequest(1, cb)
}
Just out of curiosity, may I ask if it is a face to face interview? Do you have access to a computer? How long do you have to solve this? If I dont have a computer with me to try and test then I might do worst than that...

Create function to iterate through object key

I am playing around with binance API, im very new to javascript, the first section in my code
binance.prices((error, ticker) => {
console.log("prices()", ticker);
console.log("Price of BTC: ", ticker.BTCUSDT);
});
above code outputs:
ETHBTC: '0.07421500',
LTCBTC: '0.01994000',
BNBBTC: '0.00110540',
NEOBTC: '0.00853400',
QTUMETH: '0.02604400',
the code below runs a check on an selected key (GTOBTC), I cant seem to be able to create a loop which takes the name from the keys above.
binance.depth("GTOBTC", (error, depth, symbol) => {
a = 0;
b = 0;
for (value in depth.bids){
a += Number(value);
};
for (value in depth.asks){
b += Number(value);
};
var c = a - b;
var d = (c / a) * 100;
if (d >= 2.0){
console.log(symbol + " Percent ok");
console.log(d);
} else {
console.log(symbol + " percentage not sufficient");
}
})
output for code above:
GTOBTC percentage not sufficient
Any help would be great thanks.
You can use Object.keys as below:
Object.keys(object).map((key) => {
console.log(object[key])
});
or when you have jquery in web, u can use this:
$.each(object, function(key, value) {
console.log(key + ' ' + value);
});

depth first traversal of a graph - javascript

I am trying to learn graphs well and implemented the following depth-first search in javascript. The DFS function is working ok, but the checkRoutes function is the source of my troubles. The checkRoutes function accepts two inputs and returns true if there is a possible path between two nodes/vertices, and false if not. it does this by starting at a node, checking the adjacency list, and then checking the adjacency lists of every item in the adjacency list via recursion.
My solution works for only one case - when you check two vertices once, but due to the way I'm storing the possibleVertices array globally, "possibleVertices" doesn't get cleared out each time. how could I push and store to the "possibleToVisit" array inside "checkRoute" instead of globally in this class? Would it be better to have this array stored on the constructor?
var possibleToVisit = [];
function dfs(v) {
this.marked[v] = true;
if (this.adj[v] !== undefined) {
console.log("visited vertex " + v);
}
for (var i = 0; i < this.adj[v].length; i++) {
var w = this.adj[v][i];
if (!this.marked[w]) {
possibleToVisit.push(w)
this.dfs(w);
}
}
console.log(possibleToVisit);
}
function checkRoute(v, v2) {
this.dfs(v);
if (possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(2, 4);
// g.showGraph();
// g.dfs(0);
console.log(g.checkRoute(0, 4));//true
console.log(g.checkRoute(0, 5));//false
https://jsfiddle.net/youngfreezy/t1ora6ab/3/#update
You can write a DFS "starter" function, which will reset all variables, and return something if necessary:
function Graph(v) {
this.startDfs = startDfs;
this.possibleToVisit = [];
}
// ...
function startDfs(v) {
this.possibleToVisit = []; // here, you can reset any values
this.dfs(v);
return true; // here, you can return a custom object containing 'possibleToVisit'
}
And call it only using startDfs:
function checkRoute(v, v2) {
this.startDfs(v);
if (this.possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
Here is the updated JSFiddle.
Arrays in Javascript get passed as reference, so something like
function fill(a,l){
for(var i = 0;i<l;i++)
a.push(i + 10);
}
function check(idx, max){
var arr = [];
fill(arr,max);
console.log(arr[idx]); // 14
}
check(4,10)
would work and everytime check gets called arr is fresh and clean.
You can use a marked[] array (which is filled up during the dfs() call) to determine whether a particular vertex can be reached from a known vertex s.
Please take a look at the depth first search implementation in the following library:
https://github.com/chen0040/js-graph-algorithms
It provides an object oriented approach to the graph creation as well as the depth first search algorithm.
The sample code for its depth first search algorithm is given here:
var jsgraphs = require('js-graph-algorithms');
var g = new jsgraphs.Graph(6);
g.addEdge(0, 5);
g.addEdge(2, 4);
g.addEdge(2, 3);
g.addEdge(1, 2);
g.addEdge(0, 1);
g.addEdge(3, 4);
g.addEdge(3, 5);
g.addEdge(0, 2);
var starting_vertex = 0;
var dfs = new jsgraphs.DepthFirstSearch(g, starting_vertex);
for(var v=1; v < g.V; ++v) {
if(dfs.hasPathTo(v)) {
console.log(s + " is connected to " + v);
console.log("path: " + dfs.pathTo(v));
} else {
console.log('No path from ' + s + ' to ' + v);
}
}

(FunctionReturn() - 1) fails but (-1 + FunctionReturn()) succeeds?

I have a getter/setter function that returns an absolute value. So I presumed that JavaScript would allow me to perform arithmetic with it. But it only works in a certain order...
NOTE: pos.get("log", pos.get("log") + 1) always returns 1 in these examples.
console.log("initial log: " + (-1 + pos.get("log", pos.get("log") + 1)));
// PSEUDO-CODE: -1 + (log += 1)
// RESULT: 0
The above code works as expected. But switch around the order and it all changes... Despite pos.get() always returning an absolute value of the same type. (Number)
console.log("initial log: " + (pos.get("log", pos.get("log") + 1) - 1));
// PSEUDO-CODE: (log += 1) - 1
// RESULT: 1
If log was equal to 0 from the beginning, the first console.log() prints 0. However, the second prints 1. I get no errors in the console whatsoever. Took me a while to figure out that the "- 1" was just being completely disregarded.
Why?
EDIT: Definition of pos.get()
get: function(str, val) {
switch(str) {
case "start": {
if(val != undefined) {
start = val;
}
return start;
}
case "log": {
if(val != undefined) {
log = val;
}
return log;
}
case "offset": {
if(val != undefined) {
offset = val;
}
return offset;
}
}
}
Be sure that your function returns a number (e.g. float), eventually with parseFloat(). Now, I think the js parser doesn't know.
With 1 - yourFunction() the js parser suggests that the return value of your function is numeric.

Categories

Resources