Parse.com
Cloud Code
asynchrony
JavaScript
backend development

How should asynchrony be handled in Cloud Code of Parse.com?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Parse.com itself was shut down years ago, but the same Cloud Code patterns still apply to Parse Server and to older codebases that were originally written for Parse.com. The main rule is simple: asynchronous work in Cloud Code should be expressed through promises or async and await, and the cloud function or trigger must return or await that work correctly.

If you start asynchronous operations and do not return the resulting promise, Parse may think your function is finished before the work actually completes. That is the core bug behind many “Cloud Code finished too early” problems.

Return the Promise from Cloud Functions

In older Parse code you often saw callback-heavy styles, but promise-based code is easier to reason about. A cloud function should either return a promise chain or be declared async.

javascript
1Parse.Cloud.define("countOpenTasks", async (request) => {
2  const query = new Parse.Query("Task");
3  query.equalTo("status", "open");
4
5  const results = await query.find({ useMasterKey: true });
6  return results.length;
7});

This is the clean modern pattern. The function stays asynchronous, but Parse knows to wait for the returned promise created by the async function.

Await Sequential Work Explicitly

If one step depends on the previous step, keep the operations sequential with await.

javascript
1Parse.Cloud.define("approveUser", async (request) => {
2  const userQuery = new Parse.Query("_User");
3  const user = await userQuery.get(request.params.userId, { useMasterKey: true });
4
5  user.set("approved", true);
6  await user.save(null, { useMasterKey: true });
7
8  return { approved: true };
9});

This is clearer than nesting callbacks and makes error handling much easier.

Run Independent Work in Parallel

If two async operations do not depend on each other, run them in parallel with Promise.all.

javascript
1Parse.Cloud.define("loadDashboard", async (request) => {
2  const commentsQuery = new Parse.Query("Comment");
3  const likesQuery = new Parse.Query("Like");
4
5  const [comments, likes] = await Promise.all([
6    commentsQuery.find({ useMasterKey: true }),
7    likesQuery.find({ useMasterKey: true })
8  ]);
9
10  return {
11    commentCount: comments.length,
12    likeCount: likes.length
13  };
14});

Parallel execution is usually faster than awaiting one query and then starting the next. Use it only when the operations are genuinely independent.

Handle Errors with try and catch

Cloud Code should fail clearly, not silently. Wrap awaited work in try and catch if you want to transform errors into a cleaner response or add logging.

javascript
1Parse.Cloud.define("safeDeletePost", async (request) => {
2  try {
3    const query = new Parse.Query("Post");
4    const post = await query.get(request.params.postId, { useMasterKey: true });
5    await post.destroy({ useMasterKey: true });
6    return { deleted: true };
7  } catch (error) {
8    throw new Error(`Could not delete post: ${error.message}`);
9  }
10});

If you do not catch the error yourself, Parse will still reject the promise, which is often acceptable. The important part is not swallowing failures.

Triggers Follow the Same Promise Rule

The same principle applies to beforeSave, afterSave, and other triggers. If the trigger must complete work before Parse considers it finished, return or await that work.

javascript
1Parse.Cloud.beforeSave("Invoice", async (request) => {
2  const amount = request.object.get("amount");
3  if (amount < 0) {
4    throw new Error("Amount cannot be negative");
5  }
6});

In an afterSave trigger, returning a promise means Parse waits for that asynchronous work. In some cases you may intentionally not return a promise because you want the client response to complete before the background work finishes, but that should be a deliberate choice rather than an accident.

Avoid Callback-Promise Mixing

Older Parse examples sometimes mix callbacks with promises in the same function. That usually makes control flow harder to follow and increases the chance of double responses or missed errors.

Prefer one style. In modern JavaScript, that style should almost always be async and await.

A Bad Pattern to Avoid

This kind of code is fragile:

javascript
1Parse.Cloud.define("badExample", (request) => {
2  const query = new Parse.Query("Task");
3  query.find().then((results) => {
4    console.log(results.length);
5  });
6
7  return "done";
8});

The function returns "done" immediately, before the query finishes. The async work is detached from the cloud function lifecycle.

The fix is to return the promise or await it:

javascript
1Parse.Cloud.define("goodExample", async (request) => {
2  const query = new Parse.Query("Task");
3  const results = await query.find();
4  return results.length;
5});

Common Pitfalls

The biggest mistake is starting asynchronous work and forgetting to return the promise. That makes Parse think the function finished successfully even though important work is still running.

Another issue is doing sequential awaits when the tasks could run in parallel. That does not usually break correctness, but it wastes time.

People also mix callback APIs, promise chains, and async functions in one code path. The result is harder to debug and easier to get wrong.

Finally, be intentional with triggers such as afterSave. Returning a promise means Parse waits. Not returning a promise means the work becomes effectively fire-and-forget.

Summary

  • In Parse Cloud Code, async work should normally be returned as a promise or handled with async and await.
  • Use await for dependent steps and Promise.all for independent work.
  • Do not let a cloud function return before its important asynchronous work finishes.
  • Handle errors clearly with try and catch or by letting the promise reject.
  • Prefer one async style, ideally async and await, instead of mixing callbacks and promises.

Course illustration
Course illustration

All Rights Reserved.