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.
12 * Represents a queued request. Once given a token, call complete() once the
13 * request is processed (or dropped.)
16 function QueuedRequestToken() {}
18 /** Completes (or cancels) this queued request. */
19 QueuedRequestToken
.prototype.complete = function() {};
22 * @param {!RequestQueue} queue The queue for this request.
23 * @param {number} id An id for this request.
24 * @param {function(QueuedRequestToken)} beginCb Called when work may begin on
26 * @param {RequestToken} opt_prev Previous request in the same queue.
27 * @param {RequestToken} opt_next Next request in the same queue.
29 * @implements {QueuedRequestToken}
31 function RequestToken(queue
, id
, beginCb
, opt_prev
, opt_next
) {
32 /** @private {!RequestQueue} */
34 /** @private {number} */
36 /** @type {function(QueuedRequestToken)} */
37 this.beginCb
= beginCb
;
38 /** @type {RequestToken} */
40 /** @type {RequestToken} */
42 /** @private {boolean} */
43 this.completed_
= false;
46 /** Completes (or cancels) this queued request. */
47 RequestToken
.prototype.complete = function() {
48 if (this.completed_
) {
49 // Either the caller called us more than once, or the timer is firing.
50 // Either way, nothing more to do here.
53 this.completed_
= true;
54 this.queue_
.complete(this);
57 /** @return {boolean} Whether this token has already completed. */
58 RequestToken
.prototype.completed = function() {
59 return this.completed_
;
65 function RequestQueue() {
66 /** @private {RequestToken} */
68 /** @private {RequestToken} */
70 /** @private {number} */
75 * Inserts this token into the queue.
76 * @param {RequestToken} token Queue token
79 RequestQueue
.prototype.insertToken_ = function(token
) {
80 console
.log(UTIL_fmt('token ' + this.id_
+ ' inserted'));
81 if (this.head_
=== null) {
85 if (!this.tail_
) throw 'Non-empty list missing tail';
86 this.tail_
.next
= token
;
87 token
.prev
= this.tail_
;
93 * Removes this token from the queue.
94 * @param {RequestToken} token Queue token
97 RequestQueue
.prototype.removeToken_ = function(token
) {
99 token
.next
.prev
= token
.prev
;
102 token
.prev
.next
= token
.next
;
104 if (this.head_
=== token
&& this.tail_
=== token
) {
105 this.head_
= this.tail_
= null;
107 if (this.head_
=== token
) {
108 this.head_
= token
.next
;
109 this.head_
.prev
= null;
111 if (this.tail_
=== token
) {
112 this.tail_
= token
.prev
;
113 this.tail_
.next
= null;
116 token
.prev
= token
.next
= null;
120 * Completes this token's request, and begins the next queued request, if one
122 * @param {RequestToken} token Queue token
124 RequestQueue
.prototype.complete = function(token
) {
125 console
.log(UTIL_fmt('token ' + this.id_
+ ' completed'));
126 var next
= token
.next
;
127 this.removeToken_(token
);
133 /** @return {boolean} Whether this queue is empty. */
134 RequestQueue
.prototype.empty = function() {
135 return this.head_
=== null;
139 * Queues this request, and, if it's the first request, begins work on it.
140 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
142 * @param {Countdown} timer Countdown timer
143 * @return {QueuedRequestToken} A token for the request.
145 RequestQueue
.prototype.queueRequest = function(beginCb
, timer
) {
146 var startNow
= this.empty();
147 var token
= new RequestToken(this, ++this.id_
, beginCb
);
148 // Clone the timer to set a callback on it, which will ensure complete() is
149 // eventually called, even if the caller never gets around to it.
150 timer
.clone(token
.complete
.bind(token
));
151 this.insertToken_(token
);
153 window
.setTimeout(function() {
154 if (!token
.completed()) {
155 token
.beginCb(token
);
165 function OriginKeyedRequestQueue() {
166 /** @private {Object<!RequestQueue>} */
171 * Queues this request, and, if it's the first request, begins work on it.
172 * @param {string} appId Application Id
173 * @param {string} origin Request origin
174 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
176 * @param {Countdown} timer Countdown timer
177 * @return {QueuedRequestToken} A token for the request.
179 OriginKeyedRequestQueue
.prototype.queueRequest
=
180 function(appId
, origin
, beginCb
, timer
) {
181 var key
= appId
+ ' ' + origin
;
182 if (!this.requests_
.hasOwnProperty(key
)) {
183 this.requests_
[key
] = new RequestQueue();
185 var queue
= this.requests_
[key
];
186 return queue
.queueRequest(beginCb
, timer
);