Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: chrome/browser/resources/google_now/utility.js

Issue 19967005: Simplifying using tasks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More comments. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 // TODO(vadimt): Remove alerts. 7 // TODO(vadimt): Remove alerts.
8 8
9 /** 9 /**
10 * @fileoverview Utility objects and functions for Google Now extension. 10 * @fileoverview Utility objects and functions for Google Now extension.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 */ 54 */
55 function buildTaskManager(areConflicting) { 55 function buildTaskManager(areConflicting) {
56 /** 56 /**
57 * Queue of scheduled tasks. The first element, if present, corresponds to the 57 * Queue of scheduled tasks. The first element, if present, corresponds to the
58 * currently running task. 58 * currently running task.
59 * @type {Array.<Object.<string, function(function())>>} 59 * @type {Array.<Object.<string, function(function())>>}
60 */ 60 */
61 var queue = []; 61 var queue = [];
62 62
63 /** 63 /**
64 * Name of the current step of the currently running task if present, 64 * Count of unfinished callbacks of the current task.
65 * otherwise, null. For diagnostics only. 65 * @type {number}
66 * It's set when the task is started and before each asynchronous operation.
67 */ 66 */
68 var stepName = null; 67 var taskPendingCallbackCount = 0;
68
69 /**
70 * Required callbacks that are not yet called. Includes both task and non-task
71 * callbacks. This is a map from unique callback id to the stack at the moment
72 * when the callback was wrapped. This stack identifies the callback.
73 * Used only for diagnostics.
74 * @type {Object.<number, string>}
75 */
76 var pendingCallbacks = {};
77
78 /**
79 * True if currently executed code is a part of a task.
80 * @type {boolean}
81 */
82 var isInTask = false;
69 83
70 /** 84 /**
71 * Starts the first queued task. 85 * Starts the first queued task.
72 */ 86 */
73 function startFirst() { 87 function startFirst() {
74 verify(queue.length >= 1, 'startFirst: queue is empty'); 88 verify(queue.length >= 1, 'startFirst: queue is empty');
89 verify(!isInTask, 'startFirst: already in task');
90 isInTask = true;
75 91
76 // Start the oldest queued task, but don't remove it from the queue. 92 // Start the oldest queued task, but don't remove it from the queue.
77 verify( 93 verify(
78 stepName == null, 94 taskPendingCallbackCount == 0,
79 'tasks.startFirst: stepName is not null: ' + stepName + 95 'tasks.startFirst: still have pending task callbacks: ' +
80 ', queue = ' + JSON.stringify(queue)); 96 taskPendingCallbackCount +
97 ', queue = ' + JSON.stringify(queue) +
98 ', pendingCallbacks = ' + JSON.stringify(pendingCallbacks));
81 var entry = queue[0]; 99 var entry = queue[0];
82 stepName = entry.name + '-initial';
83 console.log('Starting task ' + entry.name); 100 console.log('Starting task ' + entry.name);
84 entry.task(finish); 101
102 entry.task(function() {}); // TODO(vadimt): Don't pass parameter.
103
104 verify(isInTask, 'startFirst: not in task at exit');
105 isInTask = false;
106 if (taskPendingCallbackCount == 0)
arv (Not doing code reviews) 2013/07/24 23:10:19 if (!taskPendingCallbackCount)
vadimt 2013/07/25 00:25:10 Respectfully disagree. It's shorter, but makes cod
107 finish();
85 } 108 }
86 109
87 /** 110 /**
88 * Checks if a new task can be added to the task queue. 111 * Checks if a new task can be added to the task queue.
89 * @param {string} taskName Name of the new task. 112 * @param {string} taskName Name of the new task.
90 * @return {boolean} Whether the new task can be added. 113 * @return {boolean} Whether the new task can be added.
91 */ 114 */
92 function canQueue(taskName) { 115 function canQueue(taskName) {
93 for (var i = 0; i < queue.length; ++i) { 116 for (var i = 0; i < queue.length; ++i) {
94 if (areConflicting(taskName, queue[i].name)) { 117 if (areConflicting(taskName, queue[i].name)) {
(...skipping 24 matching lines...) Expand all
119 if (queue.length == 1) { 142 if (queue.length == 1) {
120 startFirst(); 143 startFirst();
121 } 144 }
122 } 145 }
123 146
124 /** 147 /**
125 * Completes the current task and starts the next queued task if available. 148 * Completes the current task and starts the next queued task if available.
126 */ 149 */
127 function finish() { 150 function finish() {
128 verify(queue.length >= 1, 151 verify(queue.length >= 1,
129 'tasks.finish: The task queue is empty; step = ' + stepName); 152 'tasks.finish: The task queue is empty');
130 console.log('Finishing task ' + queue[0].name); 153 console.log('Finishing task ' + queue[0].name);
131 queue.shift(); 154 queue.shift();
132 stepName = null;
133 155
134 if (queue.length >= 1) 156 if (queue.length >= 1)
135 startFirst(); 157 startFirst();
136 } 158 }
137 159
138 /**
139 * Associates a name with the current step of the task. Used for diagnostics
140 * only. A task is a chain of asynchronous events; debugSetStepName should be
141 * called before starting any asynchronous operation.
142 * @param {string} step Name of new step.
143 */
144 function debugSetStepName(step) {
145 stepName = step;
146 }
147
148 // Limiting 1 error report per background page load. 160 // Limiting 1 error report per background page load.
149 var errorReported = false; 161 var errorReported = false;
150 162
151 /** 163 /**
152 * Sends an error report to the server. 164 * Sends an error report to the server.
153 * @param {Error} error Error to report. 165 * @param {Error} error Error to report.
154 */ 166 */
155 function sendErrorReport(error) { 167 function sendErrorReport(error) {
156 var filteredStack = error.stack.replace(/.*\n/, '\n'); 168 var filteredStack = error.stack.replace(/.*\n/, '\n');
157 var file; 169 var file;
(...skipping 22 matching lines...) Expand all
180 '&trace=' + encodeURIComponent(filteredStack); 192 '&trace=' + encodeURIComponent(filteredStack);
181 var request = buildServerRequest('jserror', 193 var request = buildServerRequest('jserror',
182 'application/x-www-form-urlencoded'); 194 'application/x-www-form-urlencoded');
183 request.onloadend = function(event) { 195 request.onloadend = function(event) {
184 console.log('sendErrorReport status: ' + request.status); 196 console.log('sendErrorReport status: ' + request.status);
185 }; 197 };
186 request.send(requestParameters); 198 request.send(requestParameters);
187 } 199 }
188 200
189 /** 201 /**
202 * Unique ID of the next callback.
203 * @type {number}
204 */
205 var nextCallbackId = 0;
206
207 /**
190 * Adds error processing to an API callback. 208 * Adds error processing to an API callback.
191 * @param {Function} callback Callback to instrument. 209 * @param {Function} callback Callback to instrument.
210 * @param {boolean=} opt_dontRequire True if the callback is not required to
211 * be invoked.
192 * @return {Function} Instrumented callback. 212 * @return {Function} Instrumented callback.
193 */ 213 */
194 function wrapCallback(callback) { 214 function wrapCallback(callback, opt_dontRequire) {
215 verify(!(opt_dontRequire && isInTask), 'Unrequired callback in a task.');
216 var callbackId = nextCallbackId++;
217 var isTaskCallback = isInTask;
218 if (isTaskCallback)
219 ++taskPendingCallbackCount;
220 if (!opt_dontRequire)
221 pendingCallbacks[callbackId] = new Error().stack;
222
195 return function() { 223 return function() {
196 // This is the wrapper for the callback. 224 // This is the wrapper for the callback.
197 try { 225 try {
198 return callback.apply(null, arguments); 226 if (isTaskCallback) {
227 verify(!isInTask, 'wrapCallback: already in task');
228 isInTask = true;
229 }
230 if (!opt_dontRequire)
231 delete pendingCallbacks[callbackId];
232
233 // Call the original callback.
234 callback.apply(null, arguments);
235
236 if (isTaskCallback) {
237 verify(isInTask, 'wrapCallback: not in task at exit');
238 isInTask = false;
239 if (--taskPendingCallbackCount == 0)
240 finish();
241 }
199 } catch (error) { 242 } catch (error) {
200 var message = 'Uncaught exception:\n' + error.stack; 243 var message = 'Uncaught exception:\n' + error.stack;
201 console.error(message); 244 console.error(message);
202 if (!errorReported) { 245 if (!errorReported) {
203 errorReported = true; 246 errorReported = true;
204 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) { 247 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) {
205 if (isEnabled) 248 if (isEnabled)
206 sendErrorReport(error); 249 sendErrorReport(error);
207 }); 250 });
208 alert(message); 251 alert(message);
(...skipping 17 matching lines...) Expand all
226 alert('Cannot instrument ' + functionName); 269 alert('Cannot instrument ' + functionName);
227 270
228 namespace[functionName] = function() { 271 namespace[functionName] = function() {
229 // This is the wrapper for the API function. Pass the wrapped callback to 272 // This is the wrapper for the API function. Pass the wrapped callback to
230 // the original function. 273 // the original function.
231 var callback = arguments[callbackParameter]; 274 var callback = arguments[callbackParameter];
232 if (typeof callback != 'function') { 275 if (typeof callback != 'function') {
233 alert('Argument ' + callbackParameter + ' of ' + functionName + 276 alert('Argument ' + callbackParameter + ' of ' + functionName +
234 ' is not a function'); 277 ' is not a function');
235 } 278 }
236 arguments[callbackParameter] = wrapCallback(callback); 279 arguments[callbackParameter] = wrapCallback(
280 callback, functionName == 'addListener');
237 return originalFunction.apply(namespace, arguments); 281 return originalFunction.apply(namespace, arguments);
238 }; 282 };
239 } 283 }
240 284
241 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); 285 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0);
242 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); 286 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0);
243 287
244 chrome.runtime.onSuspend.addListener(function() { 288 chrome.runtime.onSuspend.addListener(function() {
289 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks);
245 verify( 290 verify(
246 queue.length == 0, 291 queue.length == 0 && stringifiedPendingCallbacks == '{}',
arv (Not doing code reviews) 2013/07/24 23:10:19 !queue.length
vadimt 2013/07/25 00:25:10 Same.
247 'Incomplete task when unloading event page, queue = ' + 292 'Incomplete task or pending callbacks when unloading event page,' +
248 JSON.stringify(queue) + ', step = ' + stepName); 293 ' queue = ' + JSON.stringify(queue) +
249 verify( 294 ', pendingCallbacks = ' + stringifiedPendingCallbacks);
250 stepName == null,
251 'Step name not null when unloading event page, queue = ' +
252 JSON.stringify(queue) + ', step = ' + stepName);
253 }); 295 });
254 296
255 return { 297 return {
256 add: add, 298 add: add,
257 // TODO(vadimt): Replace with instrumenting callbacks. 299 debugSetStepName: function() {}, // TODO(vadimt): remove
258 debugSetStepName: debugSetStepName,
259 instrumentApiFunction: instrumentApiFunction, 300 instrumentApiFunction: instrumentApiFunction,
260 wrapCallback: wrapCallback 301 wrapCallback: wrapCallback
261 }; 302 };
262 } 303 }
263 304
264 var storage = chrome.storage.local; 305 var storage = chrome.storage.local;
265 306
266 /** 307 /**
267 * Builds an object to manage retrying activities with exponential backoff. 308 * Builds an object to manage retrying activities with exponential backoff.
268 * @param {string} name Name of this attempt manager. 309 * @param {string} name Name of this attempt manager.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 chrome.alarms.clear(alarmName); 372 chrome.alarms.clear(alarmName);
332 storage.remove(currentDelayStorageKey); 373 storage.remove(currentDelayStorageKey);
333 } 374 }
334 375
335 /** 376 /**
336 * Plans for the next attempt. 377 * Plans for the next attempt.
337 * @param {function()} callback Completion callback. It will be invoked after 378 * @param {function()} callback Completion callback. It will be invoked after
338 * the planning is done. 379 * the planning is done.
339 */ 380 */
340 function planForNext(callback) { 381 function planForNext(callback) {
341 tasks.debugSetStepName('planForNext-get-storage');
342 storage.get(currentDelayStorageKey, function(items) { 382 storage.get(currentDelayStorageKey, function(items) {
343 console.log('planForNext-get-storage ' + JSON.stringify(items)); 383 console.log('planForNext-get-storage ' + JSON.stringify(items));
344 scheduleNextAttempt(items[currentDelayStorageKey]); 384 scheduleNextAttempt(items[currentDelayStorageKey]);
345 callback(); 385 callback();
346 }); 386 });
347 } 387 }
348 388
349 chrome.alarms.onAlarm.addListener(function(alarm) { 389 chrome.alarms.onAlarm.addListener(function(alarm) {
350 if (alarm.name == alarmName) 390 if (alarm.name == alarmName)
351 attempt(); 391 attempt();
352 }); 392 });
353 393
354 return { 394 return {
355 start: start, 395 start: start,
356 planForNext: planForNext, 396 planForNext: planForNext,
357 stop: stop 397 stop: stop
358 }; 398 };
359 } 399 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698