Skip to content

Allow "defer after await" at any time before notification triggered #79

@natevw

Description

@natevw

I realized today that some utility scripts I wrote are no longer working since the current version explicitly checks for and throws on defer after await. Reviewing when/why this might have gotten enforced it looks like I have a history of beating this drum already!

My use case boils down to essentially cases of "pagination" or "following linked lists asyncronously". I.e. the task I'm enqueuing does some work and only in the process of doing said work determines whether more work needs to be done. Thus my pattern is to create a queue, defer the initial task, and immediately awaitAll the eventual results.

My current workaround is to hack around the assertion:

const {queue:q} = require('d3-queue');

const _actualDefer = q.prototype.defer;
q.prototype.defer = function () {
  var _origCall = this._call;
  this._call = null;
  var result = _actualDefer.apply(this, arguments);
  this._call = _origCall;
  return result;
};

My proposal would be that defer can be called at any time before the notification actually happens. Likely implementation would be something like:

const TOMBSTONE = Symbol("await called"); // NOTE: `Object.create(null);` for older JS engines would suffice

function maybeNotify(q) {
  if (!q._active && q._call) {
    var d = q._data;
    q._data = undefined; // allow gc
    q._call(q._error, d);
    q._call = TOMBSTONE;
  }
}

and replacing

if (this._call) throw new Error("defer after await");

with

if (this._call === TOMBSTONE) throw new Error("defer after await called");`

I can submit a PR including any ancillary doc/test changes if you'd be amenable to this behavior change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions