jayphelps/core-decorators

Return promises where appropriate

Closed this issue · 4 comments

Some decorators can turn synchronous function asynchronous, such as @debounce and @throttle. It would be nice to be able to do something like:

class Editor {

  content = '';

  @debounce(500)
  updateContent(content) {
    this.content = content;
  }

  updateAndRender(content) {
    this.updateContent(content).then(() => Renderer.render(this));
  }
}

Hmm, come to think about it, if updateAndRender is called twenty times, you would't want the callback to be executed twenty times once the debounced updateContent completes. Perhaps you could only fulfil the first promise returned and ignore the rest? But that might introduce race-conditions:

class Editor {

  content = '';

  @debounce(500)
  updateContent(content) {
    this.content = content;
  }

  updateAndRender(content) {
    this.updateContent(content).then(() => Renderer.render(this));
  }

  updateAndSomethingElse(content) {
    this.updateContent(content).then(() => somethingElse());
  }
}

Not sure what might be a good solution. I'll have to give it some more thought.

@RomkeVdMeulen hmm yeah, please think this one over some more and let me know your thoughts. My initial reaction is hesitation since promises are once-and-done but these functions you decorate are almost always not.

I've ended up with doing the administration myself in my current project. Something like this (TypeScript):

class ItemService {

    private queue: { [id: number]: Deferred<Item> } = {};

    @debounce(500)
    retrieve() {
        const batch = this.queue;
        this.queue = {};
        const query = "?id=" + Object.keys(batch).join("&id=");
        this.backend.getStream(this.getResourceUrl() + query, (item: Item) => {
            batch[item.id].resolve(item);
        });
    }

    getItem(id: number): Promise<Item> {
        if (!this.queue[id]) {
            this.queue[id] = new Deferred();
        }
        this.retrieve();
        return this.queue[id].promise;
    }
}

This way each call to getItem() stil gets a relevant promise, and the actual retrieval can be batched.

Though this is, I think, a useful pattern, it depends on too much case-specific information to somehow incorporate it into a decorator. I can't figure out any general solution either, so I'll just close this.

@RomkeVdMeulen thanks for clarifying! Let me know if you think of a way to include it while making everyone happy 👍