1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Queue of pending requests from an origin.
11 * Represents a queued request. Once given a token, call complete() once the
12 * request is processed (or dropped.)
15 function QueuedRequestToken() {}
17 /** Completes (or cancels) this queued request. */
18 QueuedRequestToken.prototype.complete = function() {};
21 * @param {!RequestQueue} queue The queue for this request.
22 * @param {function(QueuedRequestToken)} beginCb Called when work may begin on
24 * @param {RequestToken} opt_prev Previous request in the same queue.
25 * @param {RequestToken} opt_next Next request in the same queue.
27 * @implements {QueuedRequestToken}
29 function RequestToken(queue, beginCb, opt_prev, opt_next) {
30 /** @private {!RequestQueue} */
32 /** @type {function(QueuedRequestToken)} */
33 this.beginCb = beginCb;
34 /** @type {RequestToken} */
36 /** @type {RequestToken} */
38 /** @private {boolean} */
39 this.completed_ = false;
42 /** Completes (or cancels) this queued request. */
43 RequestToken.prototype.complete = function() {
44 if (this.completed_) {
45 // Either the caller called us more than once, or the timer is firing.
46 // Either way, nothing more to do here.
49 this.completed_ = true;
50 this.queue_.complete(this);
53 /** @return {boolean} Whether this token has already completed. */
54 RequestToken.prototype.completed = function() {
55 return this.completed_;
61 function RequestQueue() {
62 /** @private {RequestToken} */
64 /** @private {RequestToken} */
69 * Inserts this token into the queue.
70 * @param {RequestToken} token Queue token
73 RequestQueue.prototype.insertToken_ = function(token) {
74 if (this.head_ === null) {
78 if (!this.tail_) throw 'Non-empty list missing tail';
79 this.tail_.next = token;
80 token.prev = this.tail_;
86 * Removes this token from the queue.
87 * @param {RequestToken} token Queue token
90 RequestQueue.prototype.removeToken_ = function(token) {
92 token.next.prev = token.prev;
95 token.prev.next = token.next;
97 if (this.head_ === token && this.tail_ === token) {
98 this.head_ = this.tail_ = null;
100 if (this.head_ === token) {
101 this.head_ = token.next;
102 this.head_.prev = null;
104 if (this.tail_ === token) {
105 this.tail_ = token.prev;
106 this.tail_.next = null;
109 token.prev = token.next = null;
113 * Completes this token's request, and begins the next queued request, if one
115 * @param {RequestToken} token Queue token
117 RequestQueue.prototype.complete = function(token) {
118 var next = token.next;
119 this.removeToken_(token);
125 /** @return {boolean} Whether this queue is empty. */
126 RequestQueue.prototype.empty = function() {
127 return this.head_ === null;
131 * Queues this request, and, if it's the first request, begins work on it.
132 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
134 * @param {Countdown} timer Countdown timer
135 * @return {QueuedRequestToken} A token for the request.
137 RequestQueue.prototype.queueRequest = function(beginCb, timer) {
138 var startNow = this.empty();
139 var token = new RequestToken(this, beginCb);
140 // Clone the timer to set a callback on it, which will ensure complete() is
141 // eventually called, even if the caller never gets around to it.
142 timer.clone(token.complete.bind(token));
143 this.insertToken_(token);
145 window.setTimeout(function() {
146 if (!token.completed()) {
147 token.beginCb(token);
157 function OriginKeyedRequestQueue() {
158 /** @private {Object.<string, !RequestQueue>} */
163 * Queues this request, and, if it's the first request, begins work on it.
164 * @param {string} appId Application Id
165 * @param {string} origin Request origin
166 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
168 * @param {Countdown} timer Countdown timer
169 * @return {QueuedRequestToken} A token for the request.
171 OriginKeyedRequestQueue.prototype.queueRequest =
172 function(appId, origin, beginCb, timer) {
173 var key = appId + origin;
174 if (!this.requests_.hasOwnProperty(key)) {
175 this.requests_[key] = new RequestQueue();
177 var queue = this.requests_[key];
178 return queue.queueRequest(beginCb, timer);