1

So I'm having a very hard time figuring out how to create a function that will work for different firebase queries / different promises.

Consider this promise, that will turn an empty output array to the returned data of the query / promise.

//userKeys is an array with my 'queries' 
Promise.all(userKeys.map(function(key) {
        return database.child(key).once("value") //Returns a promise
    })).then(function(respond) {
        userData = respond;
    });

This works perfectly. So I thought I would create a function that will do just that for different queries, and thats where I just reached a dead end.

So I will just wrap my previous code in a function

function query(keys, array) {
    return Promise.all(keys.map(function(key) {
        return ref.child(key).once("value")
    })).then(function(respond) {
        array = respond; //This won't work
        return respond;
    });
}

So I tried returning the promise which I can then do this on

someQuery = query(queryKeys);
someQuery.then(function(data){ //Manual written array to store data here
queryResults = data})

I still need to store that data in an array programmatically, which I just cannot figure out.

So look back at my second snippet of code above (My function) The second parameter was meant to be an array that I want to pass, an array of my choice that will be filled with the data, but that won't work either. If I simplify my function even more I start seeing strange things.

output = [];
function modify(arrayName) {
    var data = ["1", "2", "3", "4"];
    arrayName = data;  //Doesnt work
    arrayName = data.slice() //Doesnt work
    arrayName.push(data) //Works, but I don't want to push I want to copy
}
modify(output); //Output will stay empty

Why does my output array stay empty? Is this normal? Also when I console log arrayName it returns an object, when its clearly an array. Can someone please elaborate ?

I have a feeling I will eventually have to write a promise manually for every query I will be making in the future, I just wonder if theres a more efficient way of doing that.

realappie
  • 4,656
  • 2
  • 29
  • 38

1 Answers1

1

In JavaScript any non-primitive value is passed by a "copy of reference" (more details in this answer).

You can update the contents of a given Array using Array#splice(), e.g.:

function mutate(arr) { arr.splice(0, arr.length, 1, 2, 3); }
var a = [];
mutate(a);
console.log(a); // [1,2,3]

The splice function is a bit inconvenient for your case, as it expects each new item to be passed as a separate argument. This can be worked around by using Function#apply() (or the spread operator in the modern JS):

function mutate(dest, src) { dest.splice.apply(dest, [0, dest.length].concat(src)); }
var arr = [1,2,3];
mutate(arr, [6]);
console.log(arr); // [ 6 ]

An easier way would be to pass an object, containing the array to your mutator function:

var myData = { array: [] };
function mutate(obj, newArray) {
  obj.array = newArray;
}
mutate(myData, [1,2,3]);

That said, are you sure you don't need the callback that the promises provide? If you use a helper function like you describe, you won't get any feedback about when/if the data is received. In other words, what was wrong with the "So I tried returning the promise which I can then do this on" step?

Community
  • 1
  • 1
Nickolay
  • 31,095
  • 13
  • 107
  • 185
  • 1
    But please, please don't. That's really not how promises are meant to be used. – Madara's Ghost Mar 13 '16 at 15:53
  • @MadaraUchiha are you referring to the first part of the answer, with splice and apply? – Nickolay Mar 13 '16 at 15:56
  • @MadaraUchiha Eventually once the data is loaded, it will be rendered in the view using angularJS. So what is Nickolay doing wrong? And Nickolay, the thing thats wrong with it is, I would have to do it for every promise separately. I can't think of a way to do that programmatically, I know I won't get any feedback, but I don't think I need it because I will be rendering it in my view as soon as its loaded anyway. – realappie Mar 13 '16 at 16:04
  • @5parc: I think another question on how to do this in angular could help you produce a better solution. Sounds like the generic promise you're trying to write shouldn't just store the results in a separate JS object, but also let angularJS update the view. If you go that route, I'm reasonably sure you won't need the snippets I posted here. – Nickolay Mar 13 '16 at 17:15
  • @Nickolay I mean using promises to mutate some higher scoped variable in hope of some other script to read it sometime in the future. – Madara's Ghost Mar 13 '16 at 17:36
  • @Nickolay So you think I should ask a similar question to this with clarification how to approach my problem the angular way? Because the solution you provided does work, but if it can be done more efficiently I'm definitely willing to go the extra mile. – realappie Mar 13 '16 at 17:46
  • @5parc: yes, I'm not familiar with Angular to know the specifics, but I'm pretty sure it shouldn't force you to bend promises like that. – Nickolay Mar 13 '16 at 17:49