-1

I loop throw a list of files in Firebase storage and I would like to modify a string while looping,

Here is what I tried to do:

 var str;

 storage.bucket().file(...).download((err, content) => {
    str=content.toString();

    storage.bucket().getFiles(...).then(results => {
        const files = results[0];
        var promise = new Promise(function(resolve,reject){
           files.forEach(file => {
               ...
               str=str.replace("t","a");
           });
           resolve(str);
      });

      Promise.all(promise).then(function(str) {
        console.log(str); //NOT OKAY, the value is still "test" 

        file.save(str, function(err) { ... });
     });

I tried also :

promise.then(function(result) {

but it's the same result:(

UPDATE : I edited the code above but it still doesn't work :

enter image description here

Any idea?

UPDATE 2 :

enter image description here

it still doesn't work:(

Julien
  • 3,743
  • 9
  • 38
  • 67
  • Please edit the question to show the code in its entirety. The way you're showing it now, there's no guarantee that the promise you create in the first block of code is the same as the promise you pass to Promise.all(). It could be out of scope. – Doug Stevenson Dec 15 '18 at 20:49
  • Don't use `forEach` if you are doing something asynchronous inside. If you are not doing something asynchronous, do not use a promise. – Bergi Dec 15 '18 at 20:58
  • Why are you using `Promise.all`? You don't have multiple promises, do you? – Bergi Dec 15 '18 at 20:58
  • 1
    Your `promise` variable is created inside the `then` callback, you cannot use it outside. But `then` already creates a promise for the return value of the callback, just use that! – Bergi Dec 15 '18 at 20:59
  • @Bergi so what to use instead of Promise.all ? or how to do without forEach? I'm a bit lost.. – Julien Dec 15 '18 at 21:03
  • @Bergi it still doesn't work, indeed there is another line above and I don't know how should be the promise, I updated the question with a screenshot of the code, any idea? – Julien Dec 15 '18 at 21:54
  • @DougStevenson I edited the question with the entirely code, any idea? – Julien Dec 15 '18 at 21:56
  • @Julien Better put code as text, not paintings. – Bergi Dec 15 '18 at 22:05
  • @Julien Looks like you need to `return` the promise from the outer `then` callback. Also it's really weird that `.download()` both takes a callback and returns a promise. – Bergi Dec 15 '18 at 22:05
  • @Bergi I think you're right, download() doesn't return a promise, how to do then? – Julien Dec 15 '18 at 22:12
  • Wrap it in a `new Promise` so that you get a promise for the result. But wrap only the `download(…)` call, nothing else! See [How do I convert an existing callback API to promises?](https://stackoverflow.com/q/22519784/1048572) for details – Bergi Dec 15 '18 at 22:14
  • @Bergi I tried but it still doesn't work:( I updated the question with what I tried.. – Julien Dec 15 '18 at 22:43
  • Don't forget to call `reject` when there's an `err`, but otherwise this looks fine. What doesn't work? – Bergi Dec 15 '18 at 22:48
  • @Bergi now the cloud functions suddently doesn't return any error, but "result" in the promise.then doesn"t have the value modified by str.replace – Julien Dec 15 '18 at 23:00
  • @Bergi that goes directly to the promise.then and result is "undefined" – Julien Dec 15 '18 at 23:13
  • @Julien If my answer helped, you might want to upvote it. – Bergi Dec 16 '18 at 14:16
  • @Bergi any idea Bergi about https://stackoverflow.com/questions/53881350/flutter-retrieve-firebase-key ? – Julien Dec 21 '18 at 08:34

2 Answers2

0

If it can be usefull for someone, here is the solution I found:

var promises = [];
var str="string containing data to replace with signed url";

storage.bucket().getFiles({ prefix: folderPath }).then(results => {
  const files = results[0];
  files.forEach(function(file) {

     promises.push( //the trick was here

       file.getSignedUrl(signedUrlConfig).then(signedUrls => {
         ...
         surl = signedUrls[0];
         str=str.replace("a",surl); //eg: replace with signed url.
         return str;
       });
     );
  });
  Promise.all(promises).then(() => {
    console.log(str); //str contains all signed url
  });
});
Julien
  • 3,743
  • 9
  • 38
  • 67
  • WTH? You had no `file.getSignedUrl(signedUrlConfig)` promise call in the code in your question, there was no way we could have come up with this solution. – Bergi Dec 16 '18 at 14:16
  • I wrote "that goes directly to the promise.then and result is "undefined": that could only means that sthg didn't have time to be executed before, so we could guess there was sthg asynchronous even if the async code was not written, and that's how I comed up with the solution. – Julien Dec 17 '18 at 09:27
-1

It seems you are looking for

const promise = storage.bucket().file().download().then(str => {
//    ^^^^^^^^^                                   ^^^^^
    return storage.bucket().getFiles().then(results => {
//  ^^^^^^
        const files = results[0];
        for (const file of files) {
            …
            str = str.replace("t","a");
        }
        return str;
    //  ^^^^^^
    });
});

promise.then(str => { /*
^^^^^^^^^^^^ */
    console.log(str);
    return file.save(str); // should return a promise
});

You need neither new Promise nor Promise.all here. You might use the latter though to remove the nesting and potentially even run getFiles() and download() concurrently, see How do I access previous promise results in a .then() chain?.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • async/await is often a pleasant choice as well. Node 8 runtime is required (and supported) for Firebase Functions. Promise.all best though for parallel operation. – Ronnie Royston Dec 16 '18 at 04:45