Skip to content

Commit

Permalink
Removing animation frame from api (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreardon authored Jul 17, 2018
1 parent f312759 commit 0374268
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 653 deletions.
145 changes: 0 additions & 145 deletions .eslintrc

This file was deleted.

7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "all",
"semi": true,
"tabWidth": 2,
"useTabs": false,
"singleQuote": true
}
70 changes: 26 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@

A scheduler based on [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). It throttles calls to a function and only invokes it with the latest argument in the frame period.


[![Build Status](https://travis-ci.org/alexreardon/raf-schd.svg?branch=master)](https://travis-ci.org/alexreardon/raf-schd) [![dependencies](https://david-dm.org/alexreardon/raf-schd.svg)](https://david-dm.org/alexreardon/raf-schd) [![npm](https://img.shields.io/npm/v/raf-schd.svg)](https://www.npmjs.com/package/raf-schd) [![SemVer](https://img.shields.io/badge/SemVer-2.0.0-brightgreen.svg)](http://semver.org/spec/v2.0.0.html)


```js
import rafSchedule from 'raf-schd';
import rafSchd from 'raf-schd';

const expensiveFn = (arg) => {
const expensiveFn = arg => {
//...
console.log(arg);
}
};

const schedule = rafSchedule(expensiveFn);
const schedule = rafSchd(expensiveFn);

schedule('foo');
schedule('bar');
Expand Down Expand Up @@ -56,13 +54,13 @@ window.addEventListener('scroll', function(e) {
### With `raf-schd`

```js
import rafSchedule from 'raf-schd';
import rafSchd from 'raf-schd';

function doSomething(scroll_pos) {
// do something with the scroll position
}

const schedule = rafSchedule(doSomething);
const schedule = rafSchd(doSomething);

window.addEventListener('scroll', function() {
schedule(window.scrollY);
Expand All @@ -71,32 +69,32 @@ window.addEventListener('scroll', function() {

## Types

### `rafSchduler`
### `rafSchedule`

```js
type rafSchedule = (fn: Function) => ResultFn
type rafSchedule = (fn: Function) => ResultFn;

// Adding a .cancel property to the WrapperFn

type WrapperFn = (...arg: any[]) => number;
type WrapperFn = (...arg: mixed[]) => void;
type CancelFn = {|
cancel: () => void,
|};
type ResultFn = WrapperFn & CancelFn;
```

At the top level `raf-schd` accepts any function a returns a new `ResultFn` (a function that wraps your original function). When executed, the `ResultFn` returns a `number`. This number is the animation frame id. You can cancel a frame using the `.cancel()` property on the `ResultFn`.
At the top level `raf-schd` accepts any function a returns a new `ResultFn` (a function that wraps your original function).

The `ResultFn` will execute your function with the **latest arguments** provided to it on the next animation frame.

### Throttled with latest argument

```js
import rafSchedule from 'raf-schd';
import rafSchd from 'raf-schd';

const doSomething = () => {...};

const schedule = rafSchedule(doSomething);
const schedule = rafSchd(doSomething);

schedule(1, 2);
schedule(3, 4);
Expand All @@ -107,14 +105,12 @@ schedule(5, 6);
// do something called with => '5, 6'
```

### Cancelling a frame

#### `.cancel`
### Cancelling a frame with `.cancel`

`raf-schd` adds a `.cancel` property to the `ResultFn` so that it can be easily cancelled. The frame will only be cancelled if it has not yet executed.

```js
const scheduled = rafSchedule(doSomething);
const scheduled = rafSchd(doSomething);

schedule('foo');

Expand All @@ -123,37 +119,23 @@ scheduled.cancel();
// now doSomething will not be executed in the next animation frame
```

#### `cancelAnimationFrame`

You can use [`cancelAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame) directly to cancel a frame if you like. You can do this because you have the `frameId`.

```js
const scheduled = rafSchedule(doSomething);

const frameId = schedule('foo');

cancelAnimationFrame(frameId);

// now doSomething will not be executed in the next animation frame
```

## Is this a `throttle`, `debounce` or something else?

`raf-schd` is closer to `throttle` than it is `debounce`. It is not like `debounce` because it does not wait for a period of quiet before firing the function.
`raf-schd` is very close to a regular `throttle` function. However, rather than waiting for a fixed period of time before the wrapped function is called (such as `20ms`), `raf-schd` waits for an animation frame.

Lets take a look at the characteristics of this library:
### Differences to `throttle`

### Similarities to `throttle`
- No leading function call. The wrapped function is not called on the first call.

- It batches multiple calls into a single event
- It only executes the wrapped function with the latest argument
- It will not execute anything if the function is not invoked
- One invokation of a scheduled function always results in at least one function call, unless canceled. This is `throttle` with tail calls enabled.
```js
const scheduled = rafSchd(console.log);

### Differences to `throttle`
schedule('foo');
// function not called yet

- Rather than throttling based on time (such as `200ms`, this library throttles based on `requestAnimationFrame`. This allows the browser to control how many frames to provide per second to optimise rendering.
- Individual frames of `raf-schd` can be canceled using `cancelAnimationFrame` as it returns the frame id.
// after an animation frame
// => console.log('foo');
```

## Testing your code

Expand All @@ -174,13 +156,13 @@ npm install raf-schd --save
### ES6 module

```js
import rafSchedule from 'raf-schd';
import rafSchd from 'raf-schd';
```

### CommonJS

If you are in a CommonJS environment (eg [Node](https://nodejs.org)), then **you will need add `.default` to your import**:

```js
const rafSchedule = require('raf-schd').default;
const rafSchd = require('raf-schd').default;
```
12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
"requestAnimationFrame",
"cancelAnimationFrame"
],
"config": {
"prettier_target": "*.{js,md,json} src/**/*.{js,md,json} test/**/*.{js,md,json}"
},
"scripts": {
"build": "yarn run build:clean && yarn run build:dist && yarn run build:flow",
"test": "jest",
"validate": "yarn run lint && yarn run typecheck",
"lint": "eslint src test",
"validate": "yarn run prettier:check && yarn run typecheck",
"prettier:check": "prettier --debug-check $npm_package_config_prettier_target",
"prettier:write": "prettier --write $npm_package_config_prettier_target",
"typecheck": "flow check",
"build:clean": "rimraf dist",
"build:dist": "rollup -c",
Expand All @@ -39,11 +43,9 @@
"babel-preset-env": "^1.7.0",
"babel-preset-flow": "6.23.0",
"cross-env": "^5.2.0",
"eslint": "5.0.1",
"eslint-plugin-flowtype": "^2.49.3",
"eslint-plugin-jest": "21.17.0",
"flow-bin": "0.75.0",
"jest": "23.2.0",
"prettier": "^1.13.7",
"raf-stub": "2.0.2",
"rimraf": "^2.6.2",
"rollup": "^0.62.0",
Expand Down
13 changes: 6 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
// @flow
type WrapperFn = (...arg: any[]) => AnimationFrameID;

type WrapperFn = (...args: mixed[]) => void;
type CancelFn = {|
cancel: () => void,
|};
type ResultFn = WrapperFn & CancelFn;

export default (fn: Function): ResultFn => {
let lastArgs: any[] = [];
let lastArgs: mixed[] = [];
let frameId: ?AnimationFrameID = null;

const wrapperFn: WrapperFn = (...args: any): AnimationFrameID => {
const wrapperFn: WrapperFn = (...args: mixed[]): void => {
// Always capture the latest value
lastArgs = args;

// There is already a frame queued
if (frameId) {
return frameId;
return;
}

// Schedule a new frame
frameId = requestAnimationFrame(() => {
frameId = null;
fn(...lastArgs);
});

return frameId;
};

// Adding cancel property to result function
Expand All @@ -40,4 +39,4 @@ export default (fn: Function): ResultFn => {
const resultFn: ResultFn = (wrapperFn: any);

return resultFn;
};
};
Loading

0 comments on commit 0374268

Please sign in to comment.