Last active
August 29, 2015 14:05
-
-
Save grncdr/de2e0a17faec9a98b571 to your computer and use it in GitHub Desktop.
Promise-based generic deferred proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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