Skip to content

Instantly share code, notes, and snippets.

@jokemmy
Last active September 1, 2017 01:40
Show Gist options
  • Save jokemmy/f21ad379d793e7281bbe99fcb1939ce4 to your computer and use it in GitHub Desktop.
Save jokemmy/f21ad379d793e7281bbe99fcb1939ce4 to your computer and use it in GitHub Desktop.
requestAnimFrame shim for ssr and csr
// 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 };
};
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