Minimog
Minimog

Reputation: 159

How to create a loop that can be programatically iterated when inner callback is executed?

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?

Upvotes: 0

Views: 53

Answers (2)

Jamiec
Jamiec

Reputation: 136154

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.

Upvotes: 1

Karan
Karan

Reputation: 12629

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);

Upvotes: 0

Related Questions