Skip to content

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

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.

Activity

  1. natevw commented on Jul 1, 2020

    @natevw
    Author

    (Additional background)

    The original discussions are all mixed up in some ancient stuff about zalgo and this passing, but for posterity:

    The concern seemed to be primarily a documentation/specification issue. I guess outlawing the use case entirely simplifies that, but it prevents advanced usage. (Note: current me is not super sold on my original proposal where "the await/awaitAll callback is called every time the number of remaining tasks goes to 0" either as it would indeed be a pain to explain at best…)

  2. mbostock commented on Jul 2, 2020

    @mbostock
    Member

    I’m not maintaining this library anymore. I recommend using promises and async/await.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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