mde*_*erk 7 javascript promise deferred
问题1:在给定时间只允许一个API请求,因此真实的网络请求排队,而尚未完成的请求.应用程序可以随时调用API级别并期望获得回报.当API调用排队时,将在未来的某个时刻创建网络请求的承诺 - 返回应用程序的内容是什么?这就是如何通过延迟的"代理"承诺来解决它:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
问题2:某些API调用被去抖动,因此要发送的数据会随着时间的推移而累积,然后在达到超时时批量发送.调用API的应用程序期待作为回报的承诺.
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;
}
Run Code Online (Sandbox Code Playgroud)
由于deferred被认为是反模式,(参见何时需要创建延迟?),问题是 - 是否可以new Promise(function (resolve, reject) {outerVar = [resolve, reject]});使用标准的Promise API 实现相同的事情而不会延迟(或等效的hacks ) ?
尚未创建的承诺的承诺
...通过将then调用与创建承诺的回调链接起来很容易构建,承诺表示将来创建它的可用性。
如果您要为承诺做出承诺,则永远不应使用延迟模式。Promise当且仅当您想要等待一些异步操作,并且它尚未涉及 promises 时,您才应该使用 deferreds 或构造函数。在所有其他情况下,您应该组合多个承诺。
当你说
当 API 调用排队时,网络请求的承诺将在未来的某个时刻创建
那么你不应该创建一个延迟,你可以在创建后用承诺解决它(或者更糟的是,一旦承诺解决,就用承诺结果解决它),而是你应该得到一个未来点的承诺将进行网络请求。基本上你要写
return waitForEndOfQueue().then(makeNetworkRequest);
Run Code Online (Sandbox Code Playgroud)
当然,我们需要分别改变队列。
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;
}
Run Code Online (Sandbox Code Playgroud)
这有额外的好处,您需要显式处理队列中的错误。在这里,一旦一个请求失败,每个调用都会返回一个被拒绝的承诺(你可能想要改变它)——在你的原始代码中,queue刚刚卡住了(你可能没有注意到)。
第二种情况有点复杂,因为它确实涉及setTimeout调用。这是一个异步原语,我们需要为它手动构建一个承诺——但仅限于超时,没有别的。同样,我们将获得超时承诺,然后简单地将我们的 API 调用链接到该承诺以获取我们想要返回的承诺。
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);
}
Run Code Online (Sandbox Code Playgroud)
您可以在这里看到 a) 如何完全排除去抖动逻辑callAPI2(这可能不是必需的,但提出了一个很好的观点)和 b) 承诺构造函数如何只关心超时而不关心其他任何事情。它甚至不需要resolve像延迟那样“泄漏”函数,它唯一可供外部使用的是renew允许扩展计时器的函数。
| 归档时间: |
|
| 查看次数: |
780 次 |
| 最近记录: |