0

I am iterating over an array of assets, I need to load each of these assets to gpu (using third party library for this). Loader provided by such third party library has a callback function that is executed when asset is loaded i.e. right now I have something like this

assetsArr.forEach(asset => {
   myLoader.upload(asset, () => {
      // Go to next loop / iteration here
   })
});

Since this callback is not executed right away I am currently in a situation where my loop finishes before my assets are actually loaded leading to some issues in my app.

Is there a way to loop over assetsArr, but only go to next iteration / loop once that callback is executed?

Minimog
  • 129
  • 1
  • 6

2 Answers2

1

You could do this by wrapping myLoader in a Promise. As I dont have the code for myLoader I'll simulate it with a delay which just waits a few seconds.

async function dummyUpload(asset){
    return new Promise(resolve => {
         console.log("dummyUpload",asset);
         setTimeout(resolve,3000);
    });
}

async function test(assets){
    for(var i=0;i<assets.length;i++){
        var asset = assets[i];
        console.log("starting",asset);
        await dummyUpload(asset);
        console.log("finished",asset);
    };
}
var assets = [1,2,3];
test(assets);

The way to wrap your upload function is fairly simple:

async function loaderFunction(asset){
    return new Promise( resolve => {
        myLoader.upload(asset, resolve);
    });
}

You may also want to check if your "loader" supports a Promise-based interface which would be better than wrapping in another Promise.

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • I love wrapping things in Promises and using `async`/`await` approach. It doesn't get any cleaner that this. Synchronous code style is the most convenient one, always. – Robo Robok Aug 05 '20 at 09:36
  • @RoboRobok Yes just note my last line, so you dont fall into the [promise-wrapping anti-pattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) – Jamiec Aug 05 '20 at 09:37
  • That was an interesting read, thanks. Always keen on learning another anti-pattern :D – Robo Robok Aug 05 '20 at 09:45
0

Create function loader like below and call it with loader(assetsArr, 0);. Inside callback function at the end add code index++; and check if (index < assetsArr.length) then loader(assetsArr, index);.

Test it below. For testing I have added custom code for myLoader.

let myLoader = {
  upload : (asset, callback) => setTimeout(callback, 1000)
};

let assetsArr = [1, 2, 3];

function loader(assetsArr, index) {
  let asset = assetsArr[index];
  myLoader.upload(asset, () => {
    console.log(index);
    // Go to next loop / iteration here      
    index++;
    if (index < assetsArr.length) {
      loader(assetsArr, index);
    }
  })
}

loader(assetsArr, 0);
Karan
  • 12,059
  • 3
  • 24
  • 40
  • 1
    If OP needs to perform some other task after all the assets are uploaded, you may need to either accept a callback from the `loader` function or `loader` function should return a promise. Once the last asset is loaded (`else` branch of your `if`), that callback should be invoked or the promise should be resolved. – Udith Gunaratna Aug 05 '20 at 09:30