Skip to content

[p5.js 2.0 RFC Proposal]: Async/Await setup() #6767

Closed
@limzykenneth

Description

@limzykenneth

Increasing access

Adopting async/await can help with sketch authors' adoption of modern JavaScript syntax and best practices, making their skills more generally transferrable. The overall syntax may be considered to be simpler than the need to use the preload() function as well.

Which types of changes would be made?

  • Breaking change (Add-on libraries or sketches will work differently even if their code stays the same.)
  • Systemic change (Many features or contributor workflows will be affected.)
  • Overdue change (Modifications will be made that have been desirable for a long time.)
  • Unsure (The community can help to determine the type of change.)

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

What's the problem?

Taking directly from the current RFC

The async setup() function eliminates the need to have the preload() function. As such the data loading codebase will be refactored to remove preload() related code, while documentation around data loading should be updated accordingly.

What's the solution?

Data loading functions will all be updated to be fully async using promises (with async/await) while keeping the callback syntax if necessary. setup() will be awaited in the runtime and if the user define it as async functions, the promisified data loading functions can be awaited in them. With an async setup() function, the draw() loop will only start after the setup() function has resolved.

draw() can be defined as an async function as well, although this is not recommended because of the possible timing conflict it may have with requestAnimationFrame. (need more testing to confirm)


In terms of example code, in global mode, to load an image and display it:

let img;
async function setup(){
  createCanvas(400, 400);
  img = await loadImage("./Assets/cat.jpg");
  console.log(img);
}

function draw(){
  background(200);
  image(img, 300, 300, 100, 100);
}

In instance mode:

const sketch = function(p){
  let img;
  p.setup = async function(){
    p.createCanvas(400, 400);
    img = await p.loadImage("./Assets/cat.jpg");
  }

  p.draw = function(){
    p.background(200);
    p.image(img, 300, 300, 100, 100);
  }
};

new p5(sketch);

This will extend to all loading functions and can be used by addon libraries simply by making any asynchronous operation async.

For internal loading functions, the callback functions may be retained, eg. loadImage(imgSrc, successCallback, failureCallback), although a case can be made to not have this and just use the underlying promise instead, eg. loadimage(imgSrc).then(successCallback).catch(failureCallback).

A working example for this can be seen here.

Pros (updated based on community comments)

  • Semantic JavaScript syntax for asynchronous operations
  • Simpler and potentially more intuitive data loading
  • Better compatibility with other promises based API in JavaScript ecosystem

Cons (updated based on community comments)

  • Requiring some level of understanding of asynchronicity to start using
  • Existing addons with reliance on older preload() behaviour will likely stop working

Proposal status

Under review

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Completed

Relationships

None yet

Development

No branches or pull requests

Issue actions