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 3 // found in the LICENSE file. 4 5 'use strict'; 6 7 base.require('base.utils'); 8 9 base.exportTo('base', function() { 10 // Setting this to true will cause stack traces to get dumped into the 11 // tasks. When an exception happens the original stack will be printed. 12 // 13 // NOTE: This should never be set committed as true. 14 var recordRAFStacks = false; 15 16 var pendingPreAFs = []; 17 var pendingRAFs = []; 18 var currentRAFDispatchList = undefined; 19 20 var rafScheduled = false; 21 22 function scheduleRAF() { 23 if (rafScheduled) 24 return; 25 rafScheduled = true; 26 window.webkitRequestAnimationFrame(processRequests); 27 } 28 29 function onAnimationFrameError(e, opt_stack) { 30 if (opt_stack) 31 console.log(opt_stack); 32 33 if (e.message) 34 console.error(e.message, e.stack); 35 else 36 console.error(e); 37 } 38 39 function runTask(task) { 40 try { 41 task.callback.call(task.context); 42 } catch (e) { 43 base.onAnimationFrameError(e, task.stack); 44 } 45 } 46 47 function processRequests() { 48 rafScheduled = false; 49 50 var currentPreAFs = pendingPreAFs; 51 currentRAFDispatchList = pendingRAFs; 52 pendingPreAFs = []; 53 pendingRAFs = []; 54 55 for (var i = 0; i < currentPreAFs.length; i++) 56 runTask(currentPreAFs[i]); 57 58 while (currentRAFDispatchList.length > 0) 59 runTask(currentRAFDispatchList.shift()); 60 currentRAFDispatchList = undefined; 61 } 62 63 function getStack_() { 64 if (!recordRAFStacks) 65 return ''; 66 67 var stackLines = base.stackTrace(); 68 // Strip off getStack_. 69 stackLines.shift(); 70 return stackLines.join('\n'); 71 } 72 73 function requestPreAnimationFrame(callback, opt_this) { 74 pendingPreAFs.push({ 75 callback: callback, 76 context: opt_this || window, 77 stack: getStack_()}); 78 scheduleRAF(); 79 } 80 81 function requestAnimationFrameInThisFrameIfPossible(callback, opt_this) { 82 if (!currentRAFDispatchList) { 83 requestAnimationFrame(callback, opt_this); 84 return; 85 } 86 currentRAFDispatchList.push({ 87 callback: callback, 88 context: opt_this || window, 89 stack: getStack_()}); 90 return; 91 } 92 93 function requestAnimationFrame(callback, opt_this) { 94 pendingRAFs.push({ 95 callback: callback, 96 context: opt_this || window, 97 stack: getStack_()}); 98 scheduleRAF(); 99 } 100 return { 101 onAnimationFrameError: onAnimationFrameError, 102 requestPreAnimationFrame: requestPreAnimationFrame, 103 requestAnimationFrame: requestAnimationFrame, 104 requestAnimationFrameInThisFrameIfPossible: 105 requestAnimationFrameInThisFrameIfPossible 106 }; 107 }); 108