Skip to content

Instantly share code, notes, and snippets.

@lsmith
Last active December 23, 2015 16:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lsmith/6664382 to your computer and use it in GitHub Desktop.
Save lsmith/6664382 to your computer and use it in GitHub Desktop.
Custom event hacked up to support defaultFn that can return a promise to delay after subscribers. POC, mostly untested, so YMMV.
/*global SM:true*/
'use strict';
// Publish a very special, promise-compatible event that supports the default
// function behavior to chain on internally created promises before executing
// the after() subs. on() subs can still e.preventDefault(), which will
// reject the promise and thus skip the default behavior and after() subs.
var asyncEvent = eventTarget.publish('foo');
asyncEvent._firing = new Y.Promise(function (resolve) { resolve(); });
asyncEvent.fire = function (data) {
var event = this,
args = Y.Array(arguments, 0, true);
event._firing = event._firing.then(function () {
event.details = args;
// Execute on() subscribers
var subs = event._subscribers,
e = event._createFacade(data),
i, len;
if (subs) {
for (i = 0, len = subs.length; i < len; ++i) {
// TODO: try/catch?
subs[i].fn.call(subs[i].context, e);
}
}
// Resolve the _firing promise with either false if it was prevented, or with a promise for
// the result of the defaultFn followed by the execution of the after subs.
return e.prevented ?
false : // Doesn't support preventedFn, but could
Y.when(event.defaultFn.call(event.context || event, e)).then(function (e) {
// Execute after() subscribers
subs = event._afters;
if (subs) {
for (i = 0, len = subs.length; i < len; ++i) {
subs[i].fn.call(subs[i].context, e);
}
}
// Catch errors/preventions and reset the promise state to fulfilled for
// the next call to fire();
}).then(null, function (err) {
Y.log("Error in defaultFn or after subscriber: " + (err && (err.message || err)), 'error');
return false;
});
});
};
asyncEvent._fire = function (args) {
return this.fire(args[0]);
};
@ItsAsbreuk
Copy link

Wow, Luke, this is great code!
You really should bring this in the core of CustomEvent in order to make promise-defFn's working by default.

Regards,
Marco

@ItsAsbreuk
Copy link

e    = event._createFacade(data),

needs to be changed into:

args = [],
e = event._createFacade(args.push.apply(args, data)),

@ItsAsbreuk
Copy link

Hmmm, for some reason, the eventobject gets lost when calling event._createFacade. It is on the data-object thought.
Gotta search out why.

@ItsAsbreuk
Copy link

Luke, could you help me out?

I need to pass an eventobject as well. Without altering the code (as described above), the code will hang at https://github.com/yui/yui3/blob/master/src/event-custom/js/event-facade.js#l401

But with the adjustements, there is no event-data, because this.details is undefined at https://github.com/yui/yui3/blob/master/src/event-custom/js/event-facade.js#l378

  • Marco

@ItsAsbreuk
Copy link

Luke, need some more help:

The event cannot be targetted to another EventTarget instance.

var someTarget = new Y.EventTarget();
myobject.addTarget(myTarget);
myTarget.on('*:foo', function() {
    ... <-- nothing happens
});
myobject.fire('foo');

@ItsAsbreuk
Copy link

Luke, thanks!

I got the final code working: created Y.Model.prototype.publishAsync
https://gist.github.com/ItsAsbreuk/6712217

@ItsAsbreuk
Copy link

One small bugfix:

line 40-42 should be arrounded by:

if (subs) {
}

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