Confirm createRenditions() does not work using await?

Can someone confirm that createRenditions is working when using the await keyword?

I’ve created a test function to get the ArrayBuffer after exporting a rendition to png:

/**
 * Get the image Array Buffer from scene node
 * @param {SceneNode} element scene node
 * @param {Number} scale scale of image. default is 2 to maintain quality
 * @param {String} type type of image, png or jpg
 * @param {Number} quality quality of image. number from 1 to 100. only for jpg
 * @returns {Object}
 **/
async function getArrayBufferFromSceneNode(element, scale = 2, type = "png", quality = 100) {
  const application = require("application");
  const filesystem = require("uxp").storage;
  var folder = await filesystem.localFileSystem.getTemporaryFolder();
  var file = await folder.createFile(element.guid + "." + type, { overwrite: true });
  var definition = {};

  definition.node = element;
  definition.outputFile = file;
  definition.type = type;
  definition.scale = scale;
  definition.quality = quality;

  const renditionResults = await application.createRenditions([definition]);
  const renditionsFiles = renditionResults.map(a => a.outputFile);
  const renditionsFile = renditionsFiles[0];
  const arrayBuffer = await renditionsFile.read({ format: filesystem.formats.binary });
  arrayBuffer.length = arrayBuffer.byteLength;
  return arrayBuffer;
}

Here is how to test it:

 console.log("exporting");
 var renditionResults = await getArrayBufferFromSceneNode(scenenode);

 console.log("after first export");
 var renditionResults = await getArrayBufferFromSceneNode(scenenode);
 console.log("after second export");

Would a forEach() loop break await?

item.children.forEach(async function(item, i) {
	await getBase64DataModel(item, model, artboardModel);
})

I think I figured it out!

This is what I was using in an recursive async function:

async function getBase64DataModel(item, model, artboardModel) {
  
	if (condition) {
		await setEmbedValue(item, model, artboardModel);
	}

	if (item.isContainer) {
		
		item.children.forEach(async function(item, i) {
			await getBase64DataModel(item, model, artboardModel);
		})
	}

	return model;
}

I changed it to this and it seems to be working:

async function getBase64DataModel(item, model, artboardModel) {

	if (condition) {
		await setEmbedValue(item, model, artboardModel);
	}

	if (item.isContainer) {
		var numberOfItems = item.children.length;

		for (var i=0;i<numberOfItems;i++) {
			await getBase64DataModel(item.children.at(i), model, artboardModel);
		}
	}

	return model;
}

Right, I learned the hard wait that you can’t use .forEach with async functions, or you’ll return before they’ve all finished, and you’re just collecting promises.

Perhaps you could map to a promises array and then use Promise.all on that array, but I think this is simpler and clearer.

(Hat tip to @kerrishotts who helped me debug this a while back.)

2 Likes

I also had this problem (not particularly with createRenditions() but with an async forEach). I used this asyncForEach function:

async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array);
  }
}

https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404

2 Likes