Skip to content

Updating foundation-section for async/await #7721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: dev-2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions lib/addons/p5.sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -2945,11 +2945,10 @@ function () {
}();
/**
* loadSound() returns a new p5.SoundFile from a specified
* path. If called during preload(), the p5.SoundFile will be ready
* to play in time for setup() and draw(). If called outside of
* preload, the p5.SoundFile will not be ready immediately, so
* loadSound accepts a callback as the second parameter. Using a
* <a href="https://github.com/processing/p5.js/wiki/Local-server">
* path. If used with asynchronous setup (via `async`/`await`), the p5.SoundFile
* will be ready to play in time for `setup()` and `draw()`. If called outside of an async context,
* the p5.SoundFile will not be ready immediately, so loadSound accepts a callback as the second
* parameter. Using a <a href="https://github.com/processing/p5.js/wiki/Local-server">
* local server</a> is recommended when loading external files.
*
* @method loadSound
Expand Down
9 changes: 6 additions & 3 deletions src/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import * as constants from './constants';
* a p5 sketch. It expects an incoming sketch closure and it can also
* take an optional node parameter for attaching the generated p5 canvas
* to a node. The sketch closure takes the newly created p5 instance as
* its sole argument and may optionally set <a href="#/p5/preload">preload()</a>,
* <a href="#/p5/setup">setup()</a>, and/or
* <a href="#/p5/draw">draw()</a> properties on it for running a sketch.
* its sole argument and may optionally set an asynchronous function
* using `async/await`, along with the standard <a href="#/p5/setup">setup()</a>,
* and/or <a href="#/p5/setup">setup()</a>, and/or <a href="#/p5/draw">draw()</a>
* properties on it for running a sketch.
*
* A p5 sketch can run in "global" or "instance" mode:
* "global" - all properties and methods are attached to the window
Expand Down Expand Up @@ -465,6 +466,8 @@ for (const k in constants) {
* <a href="#/p5/draw">draw()</a> begins looping. If the
* <a href="#/p5/preload">preload()</a> is declared, then `setup()` will
* run immediately after <a href="#/p5/preload">preload()</a> finishes
*
*
* loading assets.
*
* Note: `setup()` doesn’t have to be declared, but it’s common practice to do so.
Expand Down
99 changes: 99 additions & 0 deletions src/core/reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,105 @@
* </div>
*/


/**
* Asynchronous Asset Loading with Async/Await.
*
* The keywords `async` and `await` let you write asynchronous code in a more
* straightforward, linear style. Instead of nesting callbacks or juggling
* multiple promise chains, you can pause execution at `await` while waiting
* for a promise to resolve. This makes your code flow more naturally, as if
* it were synchronous.
*
* When you mark a function with the `async` keyword—like `async function setup() {...}`—it
* signals that the function contains asynchronous operations and will return a
* promise. Any time you use the `await` keyword inside this function, JavaScript
* will pause the function’s execution until the awaited promise settles.
*
* In p5.js, you can use `async/await` to handle media loading functions such as
* `loadImage()`, `loadJSON()`, `loadSound()`, and so on. This allows you to:
* - load files in a more readable, top-to-bottom manner
* - decide when the assets are fully available before proceeding
* - avoid nested callbacks often referred to as "callback hell"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great and much needed documentation! Two notes here:

  1. I believe it would be best not to use the phrase "callback hell" here. This is because the people familiar with this term are not likely to be the majority of the documentation readers. Instead, spell out in 1 or 2 additional sentences: that nested callbacks require managing additional information and behavior, and lazy loading can be helpful but it also requires you to design your sketch around that.

  2. Please me sure to have a separate paragraph here of 1-3 sentences explaining that callbacks can still be used as they were before, since this has come up a few times in past Q&A

Thank you so much!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, i can update this ASAP. Thanks for the review @ksen0

*
* In the example below, `setup()` is declared as an async function. We `await`
* the completion of both `loadImage()` and `loadJSON()` before calling
* `createCanvas()`. Only then does the sketch proceed, guaranteeing the assets
* are available for immediate use.
*
* ```js
* let img, data;
*
* async function setup() {
* // Wait until the image and JSON data have fully loaded.
* img = await loadImage("./my-image.png");
* data = await loadJSON("./my-data.json");
*
* // Once the assets are loaded, create the canvas.
* createCanvas(400, 400);
* }
* ```
*
* @property async_await
* @example
* <div>
* <code>
* // Click and drag the mouse to view the scene from different angles.
*
* let shape;
*
* // Load the file and create a p5.Geometry object.
* async function setup() {
* shape = await loadModel('/assets/teapot.obj');
*
* createCanvas(100, 100, WEBGL);
*
* describe('A white teapot drawn against a gray background.');
* }
*
* function draw() {
* background(200);
*
* // Enable orbiting with the mouse.
* orbitControl();
*
* // Draw the shape.
* model(shape);
* }
* </code>
* </div>
*
* <div>
* <code>
* let font;
*
* async function setup() {
* // Load a font for WebGL mode.
* font = await loadFont('assets/inconsolata.otf');
*
* createCanvas(100, 100, WEBGL);
*
* describe(
* "A gray square. The mouse's x- and y-coordinates are displayed as the user moves the mouse."
* );
* }
*
* function draw() {
* background(200);
*
* // Style the text.
* textAlign(CENTER);
* textSize(16);
* textFont(font);
* fill(0);
*
* // Display the mouse's coordinates.
* text(`x: ${mouseX} y: ${mouseY}`, 0, 0);
* }
* </code>
* </div>
*/

/**
* A list that keeps several pieces of data in order.
*
Expand Down
9 changes: 4 additions & 5 deletions src/utilities/time_date.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,10 @@ function timeDate(p5, fn){
*
* If a sketch has a
* <a href="#/p5/setup">setup()</a> function, then `millis()` begins tracking
* time before the code in <a href="#/p5/setup">setup()</a> runs. If a
* sketch includes a <a href="#/p5/preload">preload()</a> function, then
* `millis()` begins tracking time as soon as the code in
* <a href="#/p5/preload">preload()</a> starts running.
*
* time before the code in <a href="#/p5/setup">setup()</a> runs. If a
* sketch includes asynchronous loading using `async`/`await`, then
* `millis()` begins tracking time as soon as the asynchronous code
* starts running.
* @method millis
* @return {Number} number of milliseconds since starting the sketch.
*
Expand Down