Skip to content

Instantly share code, notes, and snippets.

@grncdr
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grncdr/de2e0a17faec9a98b571 to your computer and use it in GitHub Desktop.
Save grncdr/de2e0a17faec9a98b571 to your computer and use it in GitHub Desktop.
Promise-based generic deferred proxy
/**
* Create a proxy object with the given prototype that caches all method calls to be applied to a target later.
*
* Example of proxying an asynchronously obtained Result object
*
* function Client (transport) {
* this._transport = transport;
* }
*
* Client.prototype.query = function (query) {
* var resultSet = deferredProxy(ResultSet.prototype);
* this._transport.request('/query', query.toJSON()).then(
* function (data) { resultSet.become(new ResultSet(this, data)); }
* function (error) { resultSet.reject(error); }
* );
* return resultSet.proxy;
* }
*
* Using the above:
*
* var client = new Client(someTransport);
*
* // v--- map is called when findByType resolves to a real ResultSet
* client.query({type: 'chair'}).map(function (chair) {
* return client.query({type: 'person', chair: chair}).then(function (people) {
* return extend(chair, {people: people});
* })
* }).then(console.log);
*/
function deferredProxy (proto) {
var calls = [];
var deferreds = [];
var proxy = Object.create(proto);
var methods = Object.keys(proto).filter(function (method) {
return typeof proto[method] !== 'function';
});
methods.forEach(function (method) {
proxy[method] = function () {
calls.push([method, arguments]);
return new Promise(function (resolve, reject) {
deferreds.push([resolve, reject]);
});
};
});
return {
proxy: proxy,
apply: apply,
become: become,
reject: reject
};
function apply (target) {
for (var i = 0, len = calls.length; i < len; i++) {
var deferred = resolvers[i];
var called[0](target[call[0]].apply(target, call[1]));
} catch(err) {
deferred[1](err);
}
}
deferreds = calls = null;
}
function become (target) {
// replace deferred calls with direct calls
methods.forEach(function (method) {
proxy[method] = function () {
return new Promise(function (resolve, reject) {
try {
resolve(target[method].apply(proxy, arguments));
} catch (err) {
reject(err);
}
});
};
});
apply(target);
}
function reject (error) {
deferreds.forEach(function (deferred) {
deferred[1](error);
});
calls = deferreds = null;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment