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?

6
  • A generator might be good here, where the .next() function does the upload and returns true when there are assets left to upload. Commented Aug 5, 2020 at 9:15
  • 1
    @Gavin this is not what generators are for. Commented Aug 5, 2020 at 9:16
  • Does this upload() function use Promises? Commented Aug 5, 2020 at 9:18
  • Or promises. Commented Aug 5, 2020 at 9:20
  • @RoboRobok unfortunately no Commented Aug 5, 2020 at 9:23

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
@RoboRobok Yes just note my last line, so you dont fall into the promise-wrapping anti-pattern
That was an interesting read, thanks. Always keen on learning another anti-pattern :D
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);

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.