Last active
September 1, 2017 01:40
-
-
Save jokemmy/f21ad379d793e7281bbe99fcb1939ce4 to your computer and use it in GitHub Desktop.
requestAnimFrame shim for ssr and csr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// rAF-shim for ssr and csr | |
export const requestAnimationFrame = ( function() { | |
try { | |
let lastTime = 0; | |
window.requestAnimationFrame = | |
window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function( callback ) { | |
const currTime = new Date().getTime(); | |
const timeToCall = Math.max( 0, 16.7 - ( currTime - lastTime )); | |
const id = window.setTimeout(() => { | |
callback( currTime + timeToCall ); | |
}, timeToCall ); | |
lastTime = currTime + timeToCall; | |
return id; | |
}; | |
return window.requestAnimationFrame; | |
} catch ( e ) { | |
return () => { return 0; }; | |
} | |
}()); | |
export const cancelAnimationFrame = ( function() { | |
try { | |
window.cancelAnimationFrame = | |
window.cancelAnimationFrame || | |
window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame || | |
window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame || | |
function( id ) { | |
clearTimeout( id ); | |
}; | |
return window.cancelAnimationFrame; | |
} catch ( e ) { | |
return () => {}; | |
} | |
}()); | |
export const cancelAnimFrame = ( id ) => { | |
invariant( | |
itis.Number( id ), | |
'Draft-Richer: Expecting id of cancelAnimFrame is an number.' | |
); | |
return cancelAnimationFrame( id ); | |
}; | |
// 返回 cancel 方法,直接运行可以停止调用 | |
export const requestAnimFrame = ( callback ) => { | |
invariant( | |
itis.Function( callback ), | |
'Draft-Richer: Expecting callback of requestAnimFrame is an function.' | |
); | |
let id; | |
const cancel = () => cancelAnimFrame( id ); | |
id = requestAnimationFrame( function frameCallback( time ) { // eslint-disable-line | |
callback( time, cancel ); | |
id = requestAnimationFrame( frameCallback ); | |
}); | |
return { cancel }; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import itis from 'whatitis'; | |
import invariant from 'invariant'; | |
import now from 'performance-now'; | |
const root = typeof window === 'undefined' ? global : window; | |
const vendors = [ 'moz', 'webkit' ]; | |
const suffix = 'AnimationFrame'; | |
let raf = root[`request${suffix}`]; | |
let caf = root[`cancel${suffix}`] || root[`cancelRequest${suffix}`]; | |
for ( let i = 0; !raf && i < vendors.length; i++ ) { | |
const prefix = vendors[i]; | |
raf = root[`${prefix}Request${suffix}`]; | |
caf = root[`${prefix}Cancel${suffix}`] | |
|| root[`${prefix}CancelRequest${suffix}`]; | |
} | |
// Some versions of FF have rAF but not cAF | |
if ( !raf || !caf ) { | |
let chain; | |
let id = 0; | |
let lastTime = 0; | |
const handles = {}; | |
const frameDuration = 1000 / 60; | |
const throwError = ( err ) => () => { | |
throw err; | |
}; | |
const compose = ( callback1, callback2 ) => ( lastTime ) => { | |
return callback1( callback2( lastTime )); | |
}; | |
const handler = ( handle, next ) => ( lastTime ) => { | |
if ( handles[handle] !== false ) { | |
next( lastTime ); | |
} else { | |
handles[handle] = null; | |
} | |
return lastTime; | |
}; | |
const next = ( handled ) => { | |
chain = chain ? compose( handled, chain ) : handled; | |
}; | |
const toCall = function() { | |
const cp = chain; | |
// Clear chain here to prevent | |
// callbacks from appending listeners | |
// to the current frame's chain | |
chain = null; | |
try { | |
cp( lastTime ); | |
} catch ( e ) { | |
setTimeout( throwError( e ), 0 ); | |
} | |
}; | |
raf = function( callback ) { | |
if ( !chain ) { | |
const currTime = now(); | |
const timeToCall = Math.max( 0, frameDuration - ( currTime - lastTime )); | |
lastTime = timeToCall + currTime; | |
root.setTimeout( toCall, Math.round( timeToCall )); | |
} | |
next( handler( ++id, callback )); | |
return id; | |
}; | |
caf = function( arg ) { | |
handles[arg] = false; | |
}; | |
} | |
export default function polyfill() { | |
root.requestAnimationFrame = raf; | |
root.cancelAnimationFrame = caf; | |
return { | |
requestAnimationFrame: root.requestAnimationFrame, | |
cancelAnimationFrame: root.cancelAnimationFrame | |
}; | |
} | |
const { requestAnimationFrame, cancelAnimationFrame } = polyfill(); | |
export function requestAnimFrame( callback ) { | |
invariant( | |
itis.Function( callback ), | |
'Expecting callback of requestAnimFrame is a function.' | |
); | |
let id; | |
const getFrameHandler = () => id; | |
const cancel = () => cancelAnimationFrame( id ); | |
id = requestAnimationFrame( function frameCallback( time ) { | |
callback( Math.round( time * 10 ) / 10, cancel ); | |
id = requestAnimationFrame( frameCallback ); | |
}); | |
return { cancel, getFrameHandler }; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment