Create renditions by same order as in "selection'

Hello there, it’s been a while :smiley: I got stuck with the following problem and need help: I want to create renditions of few selected artboards, and the order of the returned renditions is quite important for this case.

I know we shouldn’t rely on selection.items order, but I’d like the renditions to be returned in the same order as in the selection. Now they are being returned in random order, which I can assume is something with not waiting the promise to be resolved while creating each file.

Here is the function from the following sample: https://github.com/AdobeXD/plugin-samples/tree/master/ui-panel-show-renditions

async function createRenditions() {
    const folder = await fs.localFileSystem.getTemporaryFolder();
    const arr = await selection.items.map(async item => {
        const file = await folder.createFile(`${item.guid}.png`, { overwrite: true });
        let obj = {};
        obj.node = item;
        obj.outputFile = file;
        obj.type = "png";
        obj.scale = 2;
        return obj
    })
    const renditions = await Promise.all(arr);
    const renditionResults = await application.createRenditions(renditions);
    const renditionsFiles = renditionResults.map(a => a.outputFile);
    return renditionsFiles;
}

awaiting an Array#map / Promise.all doesn’t guarantee that each callback is executed one at a time – instead, they’re all kicked off at the same time, and you’re down to completion time as to when each promise is resolved.

You’ll want to use a for loop here. It feels strange when trying to do some functional-style code, but it’s the best way to guarantee that you’ll get the order you expect.

1 Like

Saving the day as always, thanks @kerrishotts :raised_hands:

If anyone is interested here is the modified function:

async function createRenditions() {
    const folder = await fs.localFileSystem.getTemporaryFolder();
    let arr = [];
    for(var i = 0; i < selection.items.length; i++){
        await folder.createFile(`${selection.items[i].guid}.png`, { overwrite: true }).then(file => {
            let obj = {};
            obj.node = selection.items[i];
            obj.outputFile = file;
            obj.type = "png";
            obj.scale = 2;
            arr.push(obj);
        });
    }
    const renditionResults = await application.createRenditions(arr);
    const renditionsFiles = renditionResults.map(a => a.outputFile);
    return renditionsFiles;
}

I had to also modify the drawing of the renditions in the plugin’s panel, again changing from async array mapping to for loop:

const renditionsFiles = await createRenditions();
const images = document.querySelector("#images");

for(var i = 0; i < renditionsFiles.length; i++){
    const arrayBuffer = await renditionsFiles[i].read({ format: fs.formats.binary });
    const image = document.createElement("img");
    const base64 = base64ArrayBuffer(arrayBuffer);
    image.setAttribute("src", `data:image/png;base64,${base64}`);
    images.appendChild(image);
}
1 Like