Iterable, Cancellable RPCs in Nymph.js

I made something really cool today that’s still boggling my mind. Iterable and cancellable remote procedure calls in my JavaScript ORM Nymph.js!

Wow, that’s a lot of tech jargon. The problem is that when you empty your trash folder in Port87 Mail, that runs on the server, and it could take a long time if you have a lot of trash. So I want to show a progress bar and let you cancel it.

Nymph already lets you run remote procedure calls on the server, but it only returns a value once the procedure completes. So if it took 20 minutes to empty your trash, you’d just see a loading spinner for 20 minutes. That’s bad. It also doesn’t pay any mind to if the connection is terminated, so there’s no way to cancel if you realized there’s an important email in your trash.

I had an idea the other day to fix both of those issues with one cool new feature! I’ve been fascinated lately by Iterators and Generators in JavaScript, and I’ve wanted to test out Async Generators. This was a perfect use case, and if I pulled it off right, the code would be elegant and simple!

I used Server Sent Events to implement this new feature. (Though there was an issue with the native API, so I used a custom approach.) Now I can implement an iterator that runs remotely on the server with just a few lines of code!

public static async *deleteTrash() {
  const total = await countItemsInTrash();
  let deleted = 0;
  let aborted = yield { deleted, total };
  while (!aborted && deleted < total) {
    await deleteNext50Emails();
    deleted += 50;
    aborted = yield { deleted, total };
static deleteTrash() {
  return this.serverCallStaticIterator('deleteTrash', []);
let iterator;

async function emptyTrash() {
  iterator = await Mail.deleteTrash();
  for await (let status of iterator) {
    updateProgress(status.deleted /;

function cancelEmptyTrash() {
  if (iterator) {

As you can see, this approach makes it really easy to implement real progress bars on long running remote procedure calls in Nymph.js.

I still can’t get over how simple and elegant that code is!

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.