schedule
Advanced tools
Comparing version 0.4.0 to 0.5.0-alpha.0
@@ -1,2 +0,2 @@ | ||
/** @license React v16.5.1 | ||
/** @license React v16.6.0-alpha.0 | ||
* schedule.development.js | ||
@@ -20,22 +20,198 @@ * | ||
var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); | ||
/* eslint-disable no-var */ | ||
/** | ||
* A scheduling library to allow scheduling work with more granular priority and | ||
* control than requestAnimationFrame and requestIdleCallback. | ||
* Current TODO items: | ||
* X- Pull out the scheduleWork polyfill built into React | ||
* X- Initial test coverage | ||
* X- Support for multiple callbacks | ||
* - Support for two priorities; serial and deferred | ||
* - Better test coverage | ||
* - Better docblock | ||
* - Polish documentation, API | ||
*/ | ||
// TODO: Currently there's only a single priority level, Deferred. Will add | ||
// additional priorities. | ||
var DEFERRED_TIMEOUT = 5000; | ||
// This is a built-in polyfill for requestIdleCallback. It works by scheduling | ||
// a requestAnimationFrame, storing the time for the start of the frame, then | ||
// scheduling a postMessage which gets scheduled after paint. Within the | ||
// postMessage handler do as much work as possible until time + frame rate. | ||
// By separating the idle call into a separate event tick we ensure that | ||
// Callbacks are stored as a circular, doubly linked list. | ||
var firstCallbackNode = null; | ||
var isPerformingWork = false; | ||
var isHostCallbackScheduled = false; | ||
var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function'; | ||
var timeRemaining; | ||
if (hasNativePerformanceNow) { | ||
timeRemaining = function () { | ||
// We assume that if we have a performance timer that the rAF callback | ||
// gets a performance timer value. Not sure if this is always true. | ||
var remaining = getFrameDeadline() - performance.now(); | ||
return remaining > 0 ? remaining : 0; | ||
}; | ||
} else { | ||
timeRemaining = function () { | ||
// Fallback to Date.now() | ||
var remaining = getFrameDeadline() - Date.now(); | ||
return remaining > 0 ? remaining : 0; | ||
}; | ||
} | ||
var deadlineObject = { | ||
timeRemaining: timeRemaining, | ||
didTimeout: false | ||
}; | ||
function ensureHostCallbackIsScheduled() { | ||
if (isPerformingWork) { | ||
// Don't schedule work yet; wait until the next time we yield. | ||
return; | ||
} | ||
// Schedule the host callback using the earliest timeout in the list. | ||
var timesOutAt = firstCallbackNode.timesOutAt; | ||
if (!isHostCallbackScheduled) { | ||
isHostCallbackScheduled = true; | ||
} else { | ||
// Cancel the existing host callback. | ||
cancelCallback(); | ||
} | ||
requestCallback(flushWork, timesOutAt); | ||
} | ||
function flushFirstCallback(node) { | ||
var flushedNode = firstCallbackNode; | ||
// Remove the node from the list before calling the callback. That way the | ||
// list is in a consistent state even if the callback throws. | ||
var next = firstCallbackNode.next; | ||
if (firstCallbackNode === next) { | ||
// This is the last callback in the list. | ||
firstCallbackNode = null; | ||
next = null; | ||
} else { | ||
var previous = firstCallbackNode.previous; | ||
firstCallbackNode = previous.next = next; | ||
next.previous = previous; | ||
} | ||
flushedNode.next = flushedNode.previous = null; | ||
// Now it's safe to call the callback. | ||
var callback = flushedNode.callback; | ||
callback(deadlineObject); | ||
} | ||
function flushWork(didTimeout) { | ||
isPerformingWork = true; | ||
deadlineObject.didTimeout = didTimeout; | ||
try { | ||
if (didTimeout) { | ||
// Flush all the timed out callbacks without yielding. | ||
while (firstCallbackNode !== null) { | ||
// Read the current time. Flush all the callbacks that expire at or | ||
// earlier than that time. Then read the current time again and repeat. | ||
// This optimizes for as few performance.now calls as possible. | ||
var currentTime = exports.unstable_now(); | ||
if (firstCallbackNode.timesOutAt <= currentTime) { | ||
do { | ||
flushFirstCallback(); | ||
} while (firstCallbackNode !== null && firstCallbackNode.timesOutAt <= currentTime); | ||
continue; | ||
} | ||
break; | ||
} | ||
} else { | ||
// Keep flushing callbacks until we run out of time in the frame. | ||
if (firstCallbackNode !== null) { | ||
do { | ||
flushFirstCallback(); | ||
} while (firstCallbackNode !== null && getFrameDeadline() - exports.unstable_now() > 0); | ||
} | ||
} | ||
} finally { | ||
isPerformingWork = false; | ||
if (firstCallbackNode !== null) { | ||
// There's still work remaining. Request another callback. | ||
ensureHostCallbackIsScheduled(firstCallbackNode); | ||
} else { | ||
isHostCallbackScheduled = false; | ||
} | ||
} | ||
} | ||
function unstable_scheduleWork(callback, options) { | ||
var currentTime = exports.unstable_now(); | ||
var timesOutAt; | ||
if (options !== undefined && options !== null && options.timeout !== null && options.timeout !== undefined) { | ||
// Check for an explicit timeout | ||
timesOutAt = currentTime + options.timeout; | ||
} else { | ||
// Compute an absolute timeout using the default constant. | ||
timesOutAt = currentTime + DEFERRED_TIMEOUT; | ||
} | ||
var newNode = { | ||
callback: callback, | ||
timesOutAt: timesOutAt, | ||
next: null, | ||
previous: null | ||
}; | ||
// Insert the new callback into the list, sorted by its timeout. | ||
if (firstCallbackNode === null) { | ||
// This is the first callback in the list. | ||
firstCallbackNode = newNode.next = newNode.previous = newNode; | ||
ensureHostCallbackIsScheduled(firstCallbackNode); | ||
} else { | ||
var next = null; | ||
var node = firstCallbackNode; | ||
do { | ||
if (node.timesOutAt > timesOutAt) { | ||
// The new callback times out before this one. | ||
next = node; | ||
break; | ||
} | ||
node = node.next; | ||
} while (node !== firstCallbackNode); | ||
if (next === null) { | ||
// No callback with a later timeout was found, which means the new | ||
// callback has the latest timeout in the list. | ||
next = firstCallbackNode; | ||
} else if (next === firstCallbackNode) { | ||
// The new callback has the earliest timeout in the entire list. | ||
firstCallbackNode = newNode; | ||
ensureHostCallbackIsScheduled(firstCallbackNode); | ||
} | ||
var previous = next.previous; | ||
previous.next = next.previous = newNode; | ||
newNode.next = next; | ||
newNode.previous = previous; | ||
} | ||
return newNode; | ||
} | ||
function unstable_cancelScheduledWork(callbackNode) { | ||
var next = callbackNode.next; | ||
if (next === null) { | ||
// Already cancelled. | ||
return; | ||
} | ||
if (next === callbackNode) { | ||
// This is the only scheduled callback. Clear the list. | ||
firstCallbackNode = null; | ||
} else { | ||
// Remove the callback from its position in the list. | ||
if (callbackNode === firstCallbackNode) { | ||
firstCallbackNode = next; | ||
} | ||
var previous = callbackNode.previous; | ||
previous.next = next; | ||
next.previous = previous; | ||
} | ||
callbackNode.next = callbackNode.previous = null; | ||
} | ||
// The remaining code is essentially a polyfill for requestIdleCallback. It | ||
// works by scheduling a requestAnimationFrame, storing the time for the start | ||
// of the frame, then scheduling a postMessage which gets scheduled after paint. | ||
// Within the postMessage handler do as much work as possible until time + frame | ||
// rate. By separating the idle call into a separate event tick we ensure that | ||
// layout, paint and other browser work is counted against the available time. | ||
@@ -45,22 +221,40 @@ // The frame rate is dynamically adjusted. | ||
// We capture a local reference to any global, in case it gets polyfilled after | ||
// this module is initially evaluated. | ||
// We want to be using a consistent implementation. | ||
// this module is initially evaluated. We want to be using a | ||
// consistent implementation. | ||
var localDate = Date; | ||
// This initialization code may run even on server environments | ||
// if a component just imports ReactDOM (e.g. for findDOMNode). | ||
// Some environments might not have setTimeout or clearTimeout. | ||
// However, we always expect them to be defined on the client. | ||
// https://github.com/facebook/react/pull/13088 | ||
// This initialization code may run even on server environments if a component | ||
// just imports ReactDOM (e.g. for findDOMNode). Some environments might not | ||
// have setTimeout or clearTimeout. However, we always expect them to be defined | ||
// on the client. https://github.com/facebook/react/pull/13088 | ||
var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : undefined; | ||
var localClearTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined; | ||
// We don't expect either of these to necessarily be defined, | ||
// but we will error later if they are missing on the client. | ||
// We don't expect either of these to necessarily be defined, but we will error | ||
// later if they are missing on the client. | ||
var localRequestAnimationFrame = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : undefined; | ||
var localCancelAnimationFrame = typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : undefined; | ||
var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function'; | ||
// requestAnimationFrame does not run when the tab is in the background. If | ||
// we're backgrounded we prefer for that work to happen so that the page | ||
// continues to load in the background. So we also schedule a 'setTimeout' as | ||
// a fallback. | ||
// TODO: Need a better heuristic for backgrounded work. | ||
var ANIMATION_FRAME_TIMEOUT = 100; | ||
var rAFID; | ||
var rAFTimeoutID; | ||
var requestAnimationFrameWithTimeout = function (callback) { | ||
// schedule rAF and also a setTimeout | ||
rAFID = localRequestAnimationFrame(function (timestamp) { | ||
// cancel the setTimeout | ||
localClearTimeout(rAFTimeoutID); | ||
callback(timestamp); | ||
}); | ||
rAFTimeoutID = localSetTimeout(function () { | ||
// cancel the requestAnimationFrame | ||
localCancelAnimationFrame(rAFID); | ||
callback(exports.unstable_now()); | ||
}, ANIMATION_FRAME_TIMEOUT); | ||
}; | ||
exports.unstable_now = void 0; | ||
if (hasNativePerformanceNow) { | ||
@@ -77,76 +271,42 @@ var Performance = performance; | ||
exports.unstable_scheduleWork = void 0; | ||
exports.unstable_cancelScheduledWork = void 0; | ||
var requestCallback; | ||
var cancelCallback; | ||
var getFrameDeadline; | ||
if (!canUseDOM) { | ||
var timeoutIds = new Map(); | ||
exports.unstable_scheduleWork = function (callback, options) { | ||
// keeping return type consistent | ||
var callbackConfig = { | ||
scheduledCallback: callback, | ||
timeoutTime: 0, | ||
next: null, | ||
prev: null | ||
}; | ||
var timeoutId = localSetTimeout(function () { | ||
callback({ | ||
timeRemaining: function () { | ||
return Infinity; | ||
}, | ||
didTimeout: false | ||
}); | ||
}); | ||
timeoutIds.set(callback, timeoutId); | ||
return callbackConfig; | ||
if (typeof window === 'undefined') { | ||
// If this accidentally gets imported in a non-browser environment, fallback | ||
// to a naive implementation. | ||
var timeoutID = -1; | ||
requestCallback = function (callback, absoluteTimeout) { | ||
timeoutID = setTimeout(callback, 0, true); | ||
}; | ||
exports.unstable_cancelScheduledWork = function (callbackId) { | ||
var callback = callbackId.scheduledCallback; | ||
var timeoutId = timeoutIds.get(callback); | ||
timeoutIds.delete(callbackId); | ||
localClearTimeout(timeoutId); | ||
cancelCallback = function () { | ||
clearTimeout(timeoutID); | ||
}; | ||
getFrameDeadline = function () { | ||
return 0; | ||
}; | ||
} else if (window._schedMock) { | ||
// Dynamic injection, only for testing purposes. | ||
var impl = window._schedMock; | ||
requestCallback = impl[0]; | ||
cancelCallback = impl[1]; | ||
getFrameDeadline = impl[2]; | ||
} else { | ||
{ | ||
if (typeof console !== 'undefined') { | ||
if (typeof localRequestAnimationFrame !== 'function') { | ||
console.error("This browser doesn't support requestAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); | ||
} | ||
if (typeof localCancelAnimationFrame !== 'function') { | ||
console.error("This browser doesn't support cancelAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); | ||
} | ||
if (typeof console !== 'undefined') { | ||
if (typeof localRequestAnimationFrame !== 'function') { | ||
console.error("This browser doesn't support requestAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); | ||
} | ||
if (typeof localCancelAnimationFrame !== 'function') { | ||
console.error("This browser doesn't support cancelAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); | ||
} | ||
} | ||
var headOfPendingCallbacksLinkedList = null; | ||
var tailOfPendingCallbacksLinkedList = null; | ||
var scheduledCallback = null; | ||
var isIdleScheduled = false; | ||
var timeoutTime = -1; | ||
// We track what the next soonest timeoutTime is, to be able to quickly tell | ||
// if none of the scheduled callbacks have timed out. | ||
var nextSoonestTimeoutTime = -1; | ||
var isIdleScheduled = false; | ||
var isAnimationFrameScheduled = false; | ||
// requestAnimationFrame does not run when the tab is in the background. | ||
// if we're backgrounded we prefer for that work to happen so that the page | ||
// continues to load in the background. | ||
// so we also schedule a 'setTimeout' as a fallback. | ||
var animationFrameTimeout = 100; | ||
var rafID = void 0; | ||
var timeoutID = void 0; | ||
var scheduleAnimationFrameWithFallbackSupport = function (callback) { | ||
// schedule rAF and also a setTimeout | ||
rafID = localRequestAnimationFrame(function (timestamp) { | ||
// cancel the setTimeout | ||
localClearTimeout(timeoutID); | ||
callback(timestamp); | ||
}); | ||
timeoutID = localSetTimeout(function () { | ||
// cancel the requestAnimationFrame | ||
localCancelAnimationFrame(rafID); | ||
callback(exports.unstable_now()); | ||
}, animationFrameTimeout); | ||
}; | ||
var isPerformingIdleWork = false; | ||
@@ -160,123 +320,49 @@ var frameDeadline = 0; | ||
var frameDeadlineObject = { | ||
didTimeout: false, | ||
timeRemaining: function () { | ||
var remaining = frameDeadline - exports.unstable_now(); | ||
return remaining > 0 ? remaining : 0; | ||
} | ||
getFrameDeadline = function () { | ||
return frameDeadline; | ||
}; | ||
/** | ||
* Handles the case where a callback errors: | ||
* - don't catch the error, because this changes debugging behavior | ||
* - do start a new postMessage callback, to call any remaining callbacks, | ||
* - but only if there is an error, so there is not extra overhead. | ||
*/ | ||
var callUnsafely = function (callbackConfig, arg) { | ||
var callback = callbackConfig.scheduledCallback; | ||
var finishedCalling = false; | ||
try { | ||
callback(arg); | ||
finishedCalling = true; | ||
} finally { | ||
// always remove it from linked list | ||
exports.unstable_cancelScheduledWork(callbackConfig); | ||
if (!finishedCalling) { | ||
// an error must have been thrown | ||
isIdleScheduled = true; | ||
window.postMessage(messageKey, '*'); | ||
} | ||
} | ||
}; | ||
/** | ||
* Checks for timed out callbacks, runs them, and then checks again to see if | ||
* any more have timed out. | ||
* Keeps doing this until there are none which have currently timed out. | ||
*/ | ||
var callTimedOutCallbacks = function () { | ||
if (headOfPendingCallbacksLinkedList === null) { | ||
// We use the postMessage trick to defer idle work until after the repaint. | ||
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2); | ||
var idleTick = function (event) { | ||
if (event.source !== window || event.data !== messageKey) { | ||
return; | ||
} | ||
isIdleScheduled = false; | ||
var currentTime = exports.unstable_now(); | ||
// TODO: this would be more efficient if deferred callbacks are stored in | ||
// min heap. | ||
// Or in a linked list with links for both timeoutTime order and insertion | ||
// order. | ||
// For now an easy compromise is the current approach: | ||
// Keep a pointer to the soonest timeoutTime, and check that first. | ||
// If it has not expired, we can skip traversing the whole list. | ||
// If it has expired, then we step through all the callbacks. | ||
if (nextSoonestTimeoutTime === -1 || nextSoonestTimeoutTime > currentTime) { | ||
// We know that none of them have timed out yet. | ||
return; | ||
} | ||
// NOTE: we intentionally wait to update the nextSoonestTimeoutTime until | ||
// after successfully calling any timed out callbacks. | ||
// If a timed out callback throws an error, we could get stuck in a state | ||
// where the nextSoonestTimeoutTime was set wrong. | ||
var updatedNextSoonestTimeoutTime = -1; // we will update nextSoonestTimeoutTime below | ||
var timedOutCallbacks = []; | ||
// iterate once to find timed out callbacks and find nextSoonestTimeoutTime | ||
var currentCallbackConfig = headOfPendingCallbacksLinkedList; | ||
while (currentCallbackConfig !== null) { | ||
var _timeoutTime = currentCallbackConfig.timeoutTime; | ||
if (_timeoutTime !== -1 && _timeoutTime <= currentTime) { | ||
// it has timed out! | ||
timedOutCallbacks.push(currentCallbackConfig); | ||
var didTimeout = false; | ||
if (frameDeadline - currentTime <= 0) { | ||
// There's no time left in this idle period. Check if the callback has | ||
// a timeout and whether it's been exceeded. | ||
if (timeoutTime !== -1 && timeoutTime <= currentTime) { | ||
// Exceeded the timeout. Invoke the callback even though there's no | ||
// time left. | ||
didTimeout = true; | ||
} else { | ||
if (_timeoutTime !== -1 && (updatedNextSoonestTimeoutTime === -1 || _timeoutTime < updatedNextSoonestTimeoutTime)) { | ||
updatedNextSoonestTimeoutTime = _timeoutTime; | ||
// No timeout. | ||
if (!isAnimationFrameScheduled) { | ||
// Schedule another animation callback so we retry later. | ||
isAnimationFrameScheduled = true; | ||
requestAnimationFrameWithTimeout(animationTick); | ||
} | ||
// Exit without invoking the callback. | ||
return; | ||
} | ||
currentCallbackConfig = currentCallbackConfig.next; | ||
} | ||
if (timedOutCallbacks.length > 0) { | ||
frameDeadlineObject.didTimeout = true; | ||
for (var i = 0, len = timedOutCallbacks.length; i < len; i++) { | ||
callUnsafely(timedOutCallbacks[i], frameDeadlineObject); | ||
timeoutTime = -1; | ||
var callback = scheduledCallback; | ||
scheduledCallback = null; | ||
if (callback !== null) { | ||
isPerformingIdleWork = true; | ||
try { | ||
callback(didTimeout); | ||
} finally { | ||
isPerformingIdleWork = false; | ||
} | ||
} | ||
// NOTE: we intentionally wait to update the nextSoonestTimeoutTime until | ||
// after successfully calling any timed out callbacks. | ||
nextSoonestTimeoutTime = updatedNextSoonestTimeoutTime; | ||
}; | ||
// We use the postMessage trick to defer idle work until after the repaint. | ||
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2); | ||
var idleTick = function (event) { | ||
if (event.source !== window || event.data !== messageKey) { | ||
return; | ||
} | ||
isIdleScheduled = false; | ||
if (headOfPendingCallbacksLinkedList === null) { | ||
return; | ||
} | ||
// First call anything which has timed out, until we have caught up. | ||
callTimedOutCallbacks(); | ||
var currentTime = exports.unstable_now(); | ||
// Next, as long as we have idle time, try calling more callbacks. | ||
while (frameDeadline - currentTime > 0 && headOfPendingCallbacksLinkedList !== null) { | ||
var latestCallbackConfig = headOfPendingCallbacksLinkedList; | ||
frameDeadlineObject.didTimeout = false; | ||
// callUnsafely will remove it from the head of the linked list | ||
callUnsafely(latestCallbackConfig, frameDeadlineObject); | ||
currentTime = exports.unstable_now(); | ||
} | ||
if (headOfPendingCallbacksLinkedList !== null) { | ||
if (!isAnimationFrameScheduled) { | ||
// Schedule another animation callback so we retry later. | ||
isAnimationFrameScheduled = true; | ||
scheduleAnimationFrameWithFallbackSupport(animationTick); | ||
} | ||
} | ||
}; | ||
// Assumes that we have addEventListener in this environment. Might need | ||
@@ -313,108 +399,29 @@ // something better for old IE. | ||
exports.unstable_scheduleWork = function (callback, options) /* CallbackConfigType */{ | ||
var timeoutTime = -1; | ||
if (options != null && typeof options.timeout === 'number') { | ||
timeoutTime = exports.unstable_now() + options.timeout; | ||
} | ||
if (nextSoonestTimeoutTime === -1 || timeoutTime !== -1 && timeoutTime < nextSoonestTimeoutTime) { | ||
nextSoonestTimeoutTime = timeoutTime; | ||
} | ||
var scheduledCallbackConfig = { | ||
scheduledCallback: callback, | ||
timeoutTime: timeoutTime, | ||
prev: null, | ||
next: null | ||
}; | ||
if (headOfPendingCallbacksLinkedList === null) { | ||
// Make this callback the head and tail of our list | ||
headOfPendingCallbacksLinkedList = scheduledCallbackConfig; | ||
tailOfPendingCallbacksLinkedList = scheduledCallbackConfig; | ||
} else { | ||
// Add latest callback as the new tail of the list | ||
scheduledCallbackConfig.prev = tailOfPendingCallbacksLinkedList; | ||
// renaming for clarity | ||
var oldTailOfPendingCallbacksLinkedList = tailOfPendingCallbacksLinkedList; | ||
if (oldTailOfPendingCallbacksLinkedList !== null) { | ||
oldTailOfPendingCallbacksLinkedList.next = scheduledCallbackConfig; | ||
} | ||
tailOfPendingCallbacksLinkedList = scheduledCallbackConfig; | ||
} | ||
if (!isAnimationFrameScheduled) { | ||
requestCallback = function (callback, absoluteTimeout) { | ||
scheduledCallback = callback; | ||
timeoutTime = absoluteTimeout; | ||
if (isPerformingIdleWork) { | ||
// If we're already performing idle work, an error must have been thrown. | ||
// Don't wait for the next frame. Continue working ASAP, in a new event. | ||
window.postMessage(messageKey, '*'); | ||
} else if (!isAnimationFrameScheduled) { | ||
// If rAF didn't already schedule one, we need to schedule a frame. | ||
// TODO: If this rAF doesn't materialize because the browser throttles, we | ||
// might want to still have setTimeout trigger scheduleWork as a backup to ensure | ||
// might want to still have setTimeout trigger rIC as a backup to ensure | ||
// that we keep performing work. | ||
isAnimationFrameScheduled = true; | ||
scheduleAnimationFrameWithFallbackSupport(animationTick); | ||
requestAnimationFrameWithTimeout(animationTick); | ||
} | ||
return scheduledCallbackConfig; | ||
}; | ||
exports.unstable_cancelScheduledWork = function (callbackConfig /* CallbackConfigType */ | ||
) { | ||
if (callbackConfig.prev === null && headOfPendingCallbacksLinkedList !== callbackConfig) { | ||
// this callbackConfig has already been cancelled. | ||
// cancelScheduledWork should be idempotent, a no-op after first call. | ||
return; | ||
} | ||
/** | ||
* There are four possible cases: | ||
* - Head/nodeToRemove/Tail -> null | ||
* In this case we set Head and Tail to null. | ||
* - Head -> ... middle nodes... -> Tail/nodeToRemove | ||
* In this case we point the middle.next to null and put middle as the new | ||
* Tail. | ||
* - Head/nodeToRemove -> ...middle nodes... -> Tail | ||
* In this case we point the middle.prev at null and move the Head to | ||
* middle. | ||
* - Head -> ... ?some nodes ... -> nodeToRemove -> ... ?some nodes ... -> Tail | ||
* In this case we point the Head.next to the Tail and the Tail.prev to | ||
* the Head. | ||
*/ | ||
var next = callbackConfig.next; | ||
var prev = callbackConfig.prev; | ||
callbackConfig.next = null; | ||
callbackConfig.prev = null; | ||
if (next !== null) { | ||
// we have a next | ||
if (prev !== null) { | ||
// we have a prev | ||
// callbackConfig is somewhere in the middle of a list of 3 or more nodes. | ||
prev.next = next; | ||
next.prev = prev; | ||
return; | ||
} else { | ||
// there is a next but not a previous one; | ||
// callbackConfig is the head of a list of 2 or more other nodes. | ||
next.prev = null; | ||
headOfPendingCallbacksLinkedList = next; | ||
return; | ||
} | ||
} else { | ||
// there is no next callback config; this must the tail of the list | ||
if (prev !== null) { | ||
// we have a prev | ||
// callbackConfig is the tail of a list of 2 or more other nodes. | ||
prev.next = null; | ||
tailOfPendingCallbacksLinkedList = prev; | ||
return; | ||
} else { | ||
// there is no previous callback config; | ||
// callbackConfig is the only thing in the linked list, | ||
// so both head and tail point to it. | ||
headOfPendingCallbacksLinkedList = null; | ||
tailOfPendingCallbacksLinkedList = null; | ||
return; | ||
} | ||
} | ||
cancelCallback = function () { | ||
scheduledCallback = null; | ||
isIdleScheduled = false; | ||
timeoutTime = -1; | ||
}; | ||
} | ||
exports.unstable_scheduleWork = unstable_scheduleWork; | ||
exports.unstable_cancelScheduledWork = unstable_cancelScheduledWork; | ||
})(); | ||
} |
@@ -1,2 +0,2 @@ | ||
/** @license React v16.5.1 | ||
/** @license React v16.6.0-alpha.0 | ||
* schedule.production.min.js | ||
@@ -10,7 +10,8 @@ * | ||
'use strict';Object.defineProperty(exports,"__esModule",{value:!0});var d=!("undefined"===typeof window||!window.document||!window.document.createElement),f=Date,g="function"===typeof setTimeout?setTimeout:void 0,h="function"===typeof clearTimeout?clearTimeout:void 0,l="function"===typeof requestAnimationFrame?requestAnimationFrame:void 0,m="function"===typeof cancelAnimationFrame?cancelAnimationFrame:void 0,n="object"===typeof performance&&"function"===typeof performance.now; | ||
exports.unstable_now=void 0;if(n){var p=performance;exports.unstable_now=function(){return p.now()}}else exports.unstable_now=function(){return f.now()};exports.unstable_scheduleWork=void 0;exports.unstable_cancelScheduledWork=void 0; | ||
if(d){var q=null,r=null,t=-1,u=!1,v=!1,w=void 0,x=void 0,y=function(a){w=l(function(b){h(x);a(b)});x=g(function(){m(w);a(exports.unstable_now())},100)},z=0,A=33,B=33,C={didTimeout:!1,timeRemaining:function(){var a=z-exports.unstable_now();return 0<a?a:0}},E=function(a,b){var c=a.scheduledCallback,e=!1;try{c(b),e=!0}finally{exports.unstable_cancelScheduledWork(a),e||(u=!0,window.postMessage(D,"*"))}},D="__reactIdleCallback$"+Math.random().toString(36).slice(2);window.addEventListener("message",function(a){if(a.source=== | ||
window&&a.data===D&&(u=!1,null!==q)){if(null!==q){var b=exports.unstable_now();if(!(-1===t||t>b)){a=-1;for(var c=[],e=q;null!==e;){var k=e.timeoutTime;-1!==k&&k<=b?c.push(e):-1!==k&&(-1===a||k<a)&&(a=k);e=e.next}if(0<c.length)for(C.didTimeout=!0,b=0,e=c.length;b<e;b++)E(c[b],C);t=a}}for(a=exports.unstable_now();0<z-a&&null!==q;)a=q,C.didTimeout=!1,E(a,C),a=exports.unstable_now();null===q||v||(v=!0,y(F))}},!1);var F=function(a){v=!1;var b=a-z+B;b<B&&A<B?(8>b&&(b=8),B=b<A?A:b):A=b;z=a+B;u||(u=!0,window.postMessage(D, | ||
"*"))};exports.unstable_scheduleWork=function(a,b){var c=-1;null!=b&&"number"===typeof b.timeout&&(c=exports.unstable_now()+b.timeout);if(-1===t||-1!==c&&c<t)t=c;a={scheduledCallback:a,timeoutTime:c,prev:null,next:null};null===q?q=a:(b=a.prev=r,null!==b&&(b.next=a));r=a;v||(v=!0,y(F));return a};exports.unstable_cancelScheduledWork=function(a){if(null!==a.prev||q===a){var b=a.next,c=a.prev;a.next=null;a.prev=null;null!==b?null!==c?(c.next=b,b.prev=c):(b.prev=null,q=b):null!==c?(c.next=null,r=c):r= | ||
q=null}}}else{var G=new Map;exports.unstable_scheduleWork=function(a){var b={scheduledCallback:a,timeoutTime:0,next:null,prev:null},c=g(function(){a({timeRemaining:function(){return Infinity},didTimeout:!1})});G.set(a,c);return b};exports.unstable_cancelScheduledWork=function(a){var b=G.get(a.scheduledCallback);G.delete(a);h(b)}}; | ||
'use strict';Object.defineProperty(exports,"__esModule",{value:!0});var c=null,e=!1,f=!1,g="object"===typeof performance&&"function"===typeof performance.now,l={timeRemaining:g?function(){var a=h()-performance.now();return 0<a?a:0}:function(){var a=h()-Date.now();return 0<a?a:0},didTimeout:!1};function m(){if(!e){var a=c.timesOutAt;f?n():f=!0;p(q,a)}}function r(){var a=c,b=c.next;if(c===b)c=null;else{var d=c.previous;c=d.next=b;b.previous=d}a.next=a.previous=null;a=a.callback;a(l)} | ||
function q(a){e=!0;l.didTimeout=a;try{if(a)for(;null!==c;){var b=exports.unstable_now();if(c.timesOutAt<=b){do r();while(null!==c&&c.timesOutAt<=b)}else break}else if(null!==c){do r();while(null!==c&&0<h()-exports.unstable_now())}}finally{e=!1,null!==c?m(c):f=!1}} | ||
var t=Date,u="function"===typeof setTimeout?setTimeout:void 0,v="function"===typeof clearTimeout?clearTimeout:void 0,w="function"===typeof requestAnimationFrame?requestAnimationFrame:void 0,x="function"===typeof cancelAnimationFrame?cancelAnimationFrame:void 0,y,z;function A(a){y=w(function(b){v(z);a(b)});z=u(function(){x(y);a(exports.unstable_now())},100)}if(g){var B=performance;exports.unstable_now=function(){return B.now()}}else exports.unstable_now=function(){return t.now()};var p,n,h; | ||
if("undefined"===typeof window){var C=-1;p=function(a){C=setTimeout(a,0,!0)};n=function(){clearTimeout(C)};h=function(){return 0}}else if(window._schedMock){var D=window._schedMock;p=D[0];n=D[1];h=D[2]}else{"undefined"!==typeof console&&("function"!==typeof w&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!==typeof x&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")); | ||
var E=null,F=!1,G=-1,H=!1,I=!1,J=0,K=33,L=33;h=function(){return J};var M="__reactIdleCallback$"+Math.random().toString(36).slice(2);window.addEventListener("message",function(a){if(a.source===window&&a.data===M){F=!1;var b=exports.unstable_now();a=!1;if(0>=J-b)if(-1!==G&&G<=b)a=!0;else{H||(H=!0,A(N));return}G=-1;b=E;E=null;if(null!==b){I=!0;try{b(a)}finally{I=!1}}}},!1);var N=function(a){H=!1;var b=a-J+L;b<L&&K<L?(8>b&&(b=8),L=b<K?K:b):K=b;J=a+L;F||(F=!0,window.postMessage(M,"*"))};p=function(a, | ||
b){E=a;G=b;I?window.postMessage(M,"*"):H||(H=!0,A(N))};n=function(){E=null;F=!1;G=-1}}exports.unstable_scheduleWork=function(a,b){var d=exports.unstable_now();b=void 0!==b&&null!==b&&null!==b.timeout&&void 0!==b.timeout?d+b.timeout:d+5E3;a={callback:a,timesOutAt:b,next:null,previous:null};if(null===c)c=a.next=a.previous=a,m(c);else{d=null;var k=c;do{if(k.timesOutAt>b){d=k;break}k=k.next}while(k!==c);null===d?d=c:d===c&&(c=a,m(c));b=d.previous;b.next=d.previous=a;a.next=d;a.previous=b}return a}; | ||
exports.unstable_cancelScheduledWork=function(a){var b=a.next;if(null!==b){if(b===a)c=null;else{a===c&&(c=b);var d=a.previous;d.next=b;b.previous=d}a.next=a.previous=null}}; |
{ | ||
"name": "schedule", | ||
"version": "0.4.0", | ||
"version": "0.5.0-alpha.0", | ||
"description": "Cooperative scheduler for the browser environment.", | ||
@@ -22,4 +22,4 @@ "main": "index.js", | ||
"index.js", | ||
"tracking.js", | ||
"tracking-profiling.js", | ||
"tracing.js", | ||
"tracing-profiling.js", | ||
"cjs/", | ||
@@ -26,0 +26,0 @@ "umd/" |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
45587
17
1112