javascript - Promises for promises that are yet to be created without using the deferred [anti]pattern -
problem 1: 1 api request allowed @ given time, real network requests queued while there's 1 has not been completed yet. app can call api level anytime , expecting promise in return. when api call queued, promise network request created @ point in future - return app? that's how can solved deferred "proxy" promise:
var queue = []; function callapi (params) { if (api_available) { api_available = false; return dorealnetrequest(params).then(function(data){ api_available = true; continuerequests(); return data; }); } else { var deferred = promise.defer(); function makerequest() { api_available = false; dorealnetrequest(params).then(function(data) { deferred.resolve(data); api_available = true; continuerequests(); }, deferred.reject); } queue.push(makerequest); return deferred.promise; } } function continuerequests() { if (queue.length) { var makerequest = queue.shift(); makerequest(); } }
problem 2: api calls debounced data sent accumulated on time , sent in batch when timeout reached. app calling api expecting promise in return.
var queue = null; var timeout = 0; function callapi2(data) { if (!queue) { queue = {data: [], deferred: promise.defer()}; } queue.data.push(data); cleartimeout(timeout); timeout = settimeout(processdata, 10); return queue.deferred.promise; } function processdata() { callapi(queue.data).then(queue.deferred.resolve, queue.deferred.reject); queue = null; }
since deferred considered anti-pattern, (see when need create deferred?), question - possible achieve same things without deferred (or equivalent hacks new promise(function (resolve, reject) {outervar = [resolve, reject]});
), using standard promise api?
promises promises yet created
…are easy build chaining then
invocation callback creates promise promise represents availability create in future.
if making promise promise, should never use deferred pattern. should use deferreds or promise
constructor if , if there asynchronous want wait for, , it not involve promises. in other cases, should compose multiple promises.
when say
when api call queued, promise network request created @ point in future
then should not create deferred can later resolve promise once created (or worse, resolve promises results once promise settles), rather should promise point in future @ network reqest made. you're going write
return waitforendofqueue().then(makenetworkrequest);
and of course we're going need mutate queue respectively.
var queue_ready = promise.resolve(true); function callapi(params) { var result = queue_ready.then(function(api_available) { return dorealnetrequest(params); }); queue_ready = result.then(function() { return true; }); return result; }
this has additional benefit need explicitly deal errors in queue. here, every call returns rejected promise once 1 request failed (you'll want change that) - in original code, queue
got stuck (and didn't notice).
the second case bit more complicated, involve settimeout
call. asynchronous primitive need manually build promise - timeout, , nothing else. again, we're going promise timeout, , chain our api call promise want return.
function timeoutqueue(timeout) { var data = [], timer = 0; this.promise = new promise(resolve => { this.renew = () => { cleartimeout(timer); timer = settimeout(resolve, timeout); }; }).then(() => { this.constructor(timeout); // re-initialise return data; }); this.add = (datum) => { data.push(datum); this.renew(); return this.promise; }; } var queue = new timeoutqueue(10); function callapi2(data) { return queue.add(data).then(callapi); }
you can see here a) how debouncing logic factored out of callapi2
(which might not have been necessary makes nice point) , b) how promise constructor concerns timeout , nothing else. doesn't need "leak" resolve
function deferred would, thing makes available outside renew
function allows extending timer.
Comments
Post a Comment