{"id":21530958,"url":"https://github.com/ibrahimtanyalcin/rafx","last_synced_at":"2025-03-17T19:22:07.810Z","repository":{"id":47924148,"uuid":"212623332","full_name":"IbrahimTanyalcin/RafX","owner":"IbrahimTanyalcin","description":"requestAnimationFrame based `thenable` for animations and task management","archived":false,"fork":false,"pushed_at":"2021-08-27T14:43:12.000Z","size":11343,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-26T12:17:53.542Z","etag":null,"topics":["animation","async","css-animation","evergreen","ie9","javascript","js","performance","polyfill","promise","requestanimationframe","task","task-queue","task-runner","web-animations-api"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IbrahimTanyalcin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-03T16:12:39.000Z","updated_at":"2021-08-27T14:43:10.000Z","dependencies_parsed_at":"2022-08-12T14:20:38.099Z","dependency_job_id":null,"html_url":"https://github.com/IbrahimTanyalcin/RafX","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IbrahimTanyalcin%2FRafX","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IbrahimTanyalcin%2FRafX/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IbrahimTanyalcin%2FRafX/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IbrahimTanyalcin%2FRafX/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IbrahimTanyalcin","download_url":"https://codeload.github.com/IbrahimTanyalcin/RafX/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244094277,"owners_count":20397020,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","async","css-animation","evergreen","ie9","javascript","js","performance","polyfill","promise","requestanimationframe","task","task-queue","task-runner","web-animations-api"],"created_at":"2024-11-24T02:10:59.513Z","updated_at":"2025-03-17T19:22:07.787Z","avatar_url":"https://github.com/IbrahimTanyalcin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RafX\n\n[![Build Status](https://travis-ci.org/IbrahimTanyalcin/RafX.svg?branch=master)](https://travis-ci.org/IbrahimTanyalcin/RafX)\n[![Travis (.com) branch](https://img.shields.io/travis/com/IbrahimTanyalcin/RafX/master?label=travis-ci.com\u0026logo=travis)](https://app.travis-ci.com/github/IbrahimTanyalcin/RafX)\n[![NPM](https://nodei.co/npm/rafx.png)](https://nodei.co/npm/rafx/)\n[![DOI](https://zenodo.org/badge/212623332.svg)](https://zenodo.org/badge/latestdoi/212623332)\n![David](https://img.shields.io/david/IbrahimTanyalcin/rafx.svg)\n\nRafx is a *promise-like* implementation solely based on `window.requestAnimationFrame` (rAF)\n\n\u003cimg width=\"150\" alt=\"Gif\" style=\"border-radius:10px; display:block; margin:auto;\" src=\"./src/util/rafx.gif\"\u003e\n\n## Supported Browsers\n\nAnything equal to or above Internet Explorer 9.\n\n## Installation\n\u003chr\u003e\n\n### Server Side\n\n```\nnpm install rafx\n```\n ### Client Side\n\n#### jsDelivr\n\n##### latest minified version\n\n```\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/rafx\"\u003e\u003c/script\u003e\n```\n\n##### specific version\n\n```\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/rafx@0.0.20/dist/rafx.v0.0.20.dev.js\"\u003e\u003c/script\u003e\n```\n\n#### Distreau\n```\n\u003cscript src=\"https://distreau.com/rafx/js/rafx.v0.0.20.min.js\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\nYou can mix and match below patterns, in any way you want.\n\n### Thenable Pattern:\n\n```\n    rafx.async(\"mixedVariable\")\n\n    .then(function(mixed,args){\n        \n        //do something..\n\n        //return a 'thenable' if you like\n\n        return rafx\n                .async()\n                .then(..);\n\n    },\"passAdditionalArgs\")\n\n    .skipFrames(30) //wait half a second if you like\n\n    .then(..) //continue\n```\n\n### Observer Pattern:\n\n```\n    rafx.async(\"mixedVariable\")\n\n    .then(function(mixed,args){\n        \n        //do something..\n\n        //when done: true is observed, execution continues\n        return {\n            value:\"whatever\",\n            done: false\n        };\n    \n    },\"passAdditionalArgs\")\n\n    .skipFrames(30) //wait half a second if you like\n\n    .then(..) //continue\n```\n## Advantages\n\n- Unlike Promises, provides `break` which terminates chains.\n- Unites all `requestAnimationFrame` calls, under a single engine object.\n- Ability to catch errors without disturbing other items/animations.\n- Aggressive break function allowing any nested thenables to terminate.\n\n## Why don't you just..\n\nMost animations consist of:\n 1. layout calculation\n 2. remapping a value \"t\" between 0 - 1\n 3. moving the pieces according to the layout based the value of t\n 4. Rinse \u0026 repeat\n\nMany other tasks that have nothing to do with animations also require steps similar to 3 and 4. Tasks that need to follow each other usually don't require micro second level execution.\n\nAll above can be combined under a **single** `requestAnimationFrame` (`rAF`)call.\n\nRafX is an attempt to unify animations and general purpose scheduled tasks.\n\n## Testing\n\u003chr\u003e\n\nAfter installing rafx, install dev dependencies:\n```\nnpm install rafx --dev\n```\n\nTo run the tests sequentially:\n```\nnpm run testDevBand \u0026\u0026 npm run testMinBand\n```\n\nTo run them parallel:\n```\nnpm run testDev \u0026\u0026 npm run testMin\n```\n\n### Covarage\n\nUnfortunately it was not possible to get coverage reports when using puppeteer with jest. Almost all exposed methods are [tested](./src/test)\n\n## Examples\n\u003chr\u003e\n\nFollow below examples in order\n\n- Move an HTML element to left: [\\\u003cfiddle\\\u003e](https://jsfiddle.net/ibowankenobi/rj1y82f0/)\n- Move an HTML element to left,  wait 250ms, then move it down: [\\\u003cfiddle\\\u003e](https://jsfiddle.net/ibowankenobi/hqg8jkbf/)\n- Move an HTML element around a rectangle, and do it infinitely: [\\\u003cfiddle\\\u003e](https://jsfiddle.net/ibowankenobi/6tk0qepb/)\n- Move an HTML element infinitely, with an ability to pause: [\\\u003cfiddle\\\u003e](https://jsfiddle.net/ibowankenobi/9q3rxLny/)\n- Move an HTML element infinitely, with an ability to break: [\\\u003cfiddle\\\u003e](https://jsfiddle.net/ibowankenobi/kcfLhobt/)\n\n## Methods\n\n### *rafx.skipFrames(frameCount[, args])* [\\\u003cprt.skipFrames\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L377-L388)\n\u003chr\u003e\nWaits a certain amount of frames. If a number is passed, it is assumed to be frame count. For instance a frame count of 15 is approximately 250 ms (1 second ~= 60 frames)\n\nAn additional argument can be given to be passed to the next thenable:\n\n```\n    rafx\n    .skipFrames(20,{value:\"whatever\", done: false})\n    .then(function(v){ //v === \"whatever\"\n        ..\n    })\n```\n\nIf the passed argument does not have `value` or `done` properties, it is automatically wrapped with an object `{value: \"your argument\", done: true}` and passed on to the next thenable.\n\nIf no arguments are given, `undefined` is passed.\n\n#### Returns\n\n`Thenable`\n\n### *rafx.async(mixed[, args[, thisArg]])* [\\\u003cprt.async\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L703-L705)\n\u003chr\u003e\n\nPasses a mixed variable to be used within a `thenable` immediately. If the mixed variable is a function, then that function is executed with `args` and with this pointing to `thisArg`:\n\n```\nmixed.call(thisArg || null, rest)\n```\n\nIf the mixed is not a function, it is passed directly:\n\n```\nrafx.async(\"whatever\")\n    .then(function(v){\n        //v is \"whatever\"\n    });\n```\n\n#### Returns\n\n`Thenable`\n\n### *thenable.then(function[, args])* [\\\u003cprt.Thenable.prototype.then\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L405-L426)\n\u003chr\u003e\n\nExecutes the passed function with the arguments given, if any and `this` pointing out to the current thenable. You can return another `thenable` instance, use the observer pattern, or use any other mixed variable (refer to Usage section):\n\n```\nrafx.async() //returns a thenable, let's call it thenable 1 \n    .then(function(){\n        //here 'this' refers to thenable 1\n        return \"mixed\";\n    }) // returns a new thenable, let's call it thenable 2\n    .then(function(v){\n        //here 'this' refers to thenable 2\n        //v === \"mixed\"\n    })\n```\n\nYou can inspect `thenable.status` to receive information about its state which fluctuates between \"completed\", \"pending\" and \"idle\".\n\n#### Returns\n\n`Thenable`\n\n### *thenable.forceThen(function[, args[, options]])* \n### *thenable.force(function[, args[, options]])* \n### *thenable.fThen(function[, args[, options]])* \n### [\\\u003cprt.Thenable.prototype.fThen\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L431-L467)\n\u003chr\u003e\n\nExecutes the passed function with the arguments given, if any and `this` pointing out to the current thenable (the thenable that `force` is called from). You can return another `thenable` instance, use the observer pattern, or use any other mixed variable (refer to Usage section).\n\nThe difference between `force` and `then` is that `Error` objects thrown or returned from upstream or inside the `force` does not cause `catch` to trigger (if any catch is registered). The following `then` receives what is returned from `force` or the thrown `Error` encapsulated in an object of form `{value: ..}`\n\n```\nrafx.async(1)\n    .then(function(v){\n        return ++v;\n    })\n    .force(function(v){\n        //v === 2\n    })\n```\n\n```\nrafx.async(1)\n    .then(function(v){\n        throw new Error(\"this will not trigger catch, if any\");\n    })\n    .force(function(v){\n        //bypassed and upstream Error is encapsulated {value: Error}\n    })\n    .then(function(v){\n        v.value.message; //\"this will not trigger catch, if any\"\n    })\n```\n\nThe options objects accepts  `throw` property. This property, referring to another `Error`object, can override what is thrown by default:\n\n```\nrafx\n    .async(5)\n    .then(function(v){\n        throw new Error(\"wrong error\");\n    })\n    .filter(function(v){\n        return v \u003e 10;\n    }, null, {throw: new Error(\"right error\")})\n    .then(function(v){\n        //not executed\n    }).catch(function(e){\n        e.message; //\"right error\" \n    });\n```\n\n#### Returns\n\n`Thenable`\n\n### *thenable.filter(function[, args[, options]])* [\\\u003cprt.Thenable.prototype.filter\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L502-L534)\n\u003chr\u003e\n\nExecutes the passed function with the arguments given, if any and `this` pointing out to the current thenable (the thenable that `filter` is called from). You can return another `thenable` instance, use the observer pattern, or use any other mixed variable (refer to Usage section). If the function returns truthy, then rest of the `thenable` chain is executed, being passed the last return value immediately upstream of the filter clause, otherwise silently fails.\n\n```\nrafx.async()\n    .then(function(){\n        return 0;\n    })\n    .filter(function(v){\n        return v; //v === 0, not truthy, so next thenable is NOT executed\n    })\n    .then(function(v){\n        ..\n    })\n```\n\nThe options objects accepts 2 properties, `throw` and `done`. Normally the filter executes when the upstream thenable is complete (including all the nested thenables within), but the `done` property can point to another `thenable`'s status property, allowing the filter clause to execute when that thenable is complete:\n\n```\nconst = anotherThenable = rafx\n    .async()\n    .skipFrames(180);\n\nrafx\n    .async()\n    .then(function(){\n        return \"payload\";\n    })\n    .filter(function(v){ //this will execute after 180 frames (3 secs)\n        return v === \"payload\"; //truthy, so remaining chain will execute\n    },null,{done:anotherThenable.status})\n    .then(function(v){\n        //v is \"payload\"\n    });\n```\n\nYou can also override what to be thrown:\n\n```\nrafx\n    .async(5)\n    .then(function(v){return v;})\n    .filter(function(v){\n        return v \u003e 10;\n    },null,{throw: new Error(\"right error\")})\n    .then(function(v){\n        //not executed\n    }).catch(function(e){\n        e.message; //\"right error\" instead of default \"Value Is Not Validated By Specified Function\"\n    });\n```\n\nFilter does not throw by default, but if you attach a catch clause as shown above, if any `options` argument is present, it will be populated with an `error` property. [\u003c\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L529)\n\n#### Returns\n\n`Thenable`\n\n### *thenable.toBool(function[, args[, options]])* [\\\u003cprt.Thenable.prototype.toBool\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L474-L500)\n\u003chr\u003e\n\nExecutes the passed function with the arguments given, if any and `this` pointing out to the current thenable (the thenable that `toBool` is called from). You can return another `thenable` instance, use the observer pattern, or use any other mixed variable (refer to Usage section):\n\n```\nrafx.async(5)\n    .then(function(v){\n        return v + 1; //v === 6\n    })\n    .toBool(function(v){ //v === true\n        return v \u0026\u0026 \"whatever\";\n    }) \n    ..\n```\n\nIf `toBool` is not passed a function, then identity function is assumed.\n\nSimilar to `filter`, `force` or other clauses, it can receive an options object with a `throw` property pointing to a custom `Error` to be thrown\n\n\n#### Returns\n\n`Thenable`\n\n### *thenable.ifTruthy(function[, args[, options]])* [\\\u003cprt.Thenable.prototype.ifTruthy\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L536-L545)\n### *thenable.ifFalsey(function[, args[, options]])* [\\\u003cprt.Thenable.prototype.ifFalsey\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L546-L555)\n\u003chr\u003e\n\nSimilar to `filter`. Recevies the same arguments.\n\n`ifFalsey`:\n\n```\n//falsey\nrafx\n    .async(0)\n    .then(function(v){ return v;})\n    .ifFalsey(function(v, rest){\n        //v === 0\n        return \"whatever\";\n    }, \"rest\")\n    .then(function(v){ \n        //v === \"whatever\"\n    });\n```\n\n`ifFalsey`:\n\n```\nrafx\n    .async(\"payload\")\n    .then(function(v){ return v;})\n    .ifTruthy(function(v, rest){\n       //v === \"payload\"\n       return \"whatever\";\n    }, \"rest\")\n    .then(function(v){\n        //v === \"whatever\"\n    });\n```\n\nYou can control what to throw and the timing of the clause as in `filter`. These clauses do not throw by default, if you want to catch it, attach a `catch` handler:\n\n```\nrafx\n    .async(0) //not truthy\n    .ifTruthy(function(v, rest){\n       return \"whatever\";\n    }, \"rest\")\n    .then(function(v){\n        //not executed\n    })\n    .catch(function(e){\n        console.log(e.message); //Value Cannot Be Converted To Truthy\n    });\n```\n\n#### Returns\n\n`Thenable`\n\n### *thenable.recurse(function[, args])* \n### *thenable.loop(function[, args])* \n### *thenable.do(function[, args])* \n### [\\\u003cprt.Thenable.prototype.recurse\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L598-L603)\n\u003chr\u003e\n\nExecutues the following function and the arguments if any, with `this` pointing out to the current thenable (the thenable that `recurse` is called from)\n\nThe function is executed until the `until` block returns true, or the `while` block return false. The thenable following the until clause will receive the latest return value from the recurse loop:\n\n```\nrafx\n    .async(2)\n    .recurse((v,o) =\u003e {o.i += v; return o.i;}, {i:0}) //v === 2\n    .until((r,o) =\u003e r \u003e 10)\n    .then(function(r){\n        //r === 12\n    });\n```\nYou can also use `while` instead of `until`\n\n```\nrafx\n    .async(2)\n    .recurse((v,o) =\u003e {o.i += v; return o.i;}, {i:0}) //v === 2\n    .while((r,o) =\u003e r \u003c 10)\n    .then(function(r){\n        //r === 10\n    });\n```\n\nDo not use `recurse` with animations, because `recurse` is aware of what is returned inside the function, meaning if it is a `thenable` or series of nested thenables, `recurse` will wait for them to complete. Use `animate` instead\n\n#### Returns\n\n`Untillable`\n\n### *thenable.animate(function[, args])* \n### *thenable.recurseShallow(function[, args])*  \n### [\\\u003cprt.Thenable.prototype.animate\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L644-L649)\n\u003chr\u003e\n\nExecutues the following function and the arguments if any, with `this` pointing out to the current thenable (the thenable that `animate` is called from)\n\nThe function is executed until the `until` block returns true, or the `while` block return false. The thenable following the until clause will receive the latest return value from the recurse loop:\n\n```\nconst o = {i:0};\nlet j = 0;\nrafx\n    .async(2)\n    .animate(function(v, rest){\n        ++rest.i;\n        j++;\n        return v;\n    }, o)\n    .until(function(v, rest){\n        return rest.i + v === 12;\n    })\n    .then(function(v){\n        //v === 2\n        //o.i === 10\n        //j === 10\n    });\n```\n\nDo not return a `thenable` inside an `animate` clause, only use ordinary objects or variables because `animate` will not wait for the thenable's completion. Use `recurse` instead.\n\n#### Returns\n\n`Untillable`\n\n### *rafx.repeat(function[, args[, options]])* [\\\u003cprt.repeat\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L706-L748)\n\u003chr\u003e\n\nCreates a repeating function that can be controlled via a `controller`. The options argument can contain 3 fields, `throw`, `handler` and `thisArg`. All are optional.\n\n\n```\nrafx\n    .repeat(\n        function(arg, ctrl){\n            // 'this' refers to \"whatever\"\n            arg.c++;\n            if(arg.c \u003e 20){\n                // your options below\n                throw new Error(\"wrong error message\"); // option 1\n                ctrl.kill //option 2\n                ctrl.resume //option 3\n                ctrl.pause // option 4\n            }\n        },\n        {\n            c:0\n        },\n        {\n            /*if you throw, e will be the error, if handler is specified and ctrl.kill is invoked, e will be null*/\n\n            handler:function(e,arg){ \n                /*\n                    e is either null or error object\n                    arg is '{c: 0}'\n                */\n            },\n\n            //you can specify what to throw\n            throw: new Error(\"right error message\"), \n\n            //optional this argument\n            thisArg: \"whatever\"\n        }\n    );\n```\n\n`rafx.repeat` returns an id string. This id internally stored inside rafx._processes:\n\n```\ndelete rafx._processes[id];\n```\n\nAbove has the same effect as calling `ctrl.kill`, if no handler is specified, the repeat will cease, otherwise the handler will be called.\n\n#### Returns\n\nAn id `string`\n\n### *rafx.throttle(function[, args[, numberFrames]])* [\\\u003cprt.throttle\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L814-L824)\n\u003chr\u003e\n\nCreates a throttled function that fires maximum once every `numberFrames`:\n\n```\nconst f = rafx.throttle(function(a, b, c){\n    console.log(a, b, c);\n}, 2, 5);\n\nf(1, 10); //1, 2, Arguments[1, 10, callee: f, ..]\n```\n\nAbove function can fire at most once every 5 frames, which is about 83ms.\n\n#### Returns\n\n`function`\n\n### *rafx.isInView(node[, numberFrames])* [\\\u003cprt.isInView\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L799-L813)\n\u003chr\u003e\n\nReturns whether a node with `nodeType` === 1 (HTMLElement) is visible once every `numberFrames`:\n\n```\nrafx.isInView(node, 5)\n```\n\nAbove will return `boolean` at most once every 5 frames, which is about 83ms.\n\n#### Returns\n\n`boolean`\n\n### *rafx.ifInView(node[, numberFrames])* [\\\u003cprt.ifInView\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L650-L652)\n\u003chr\u003e\n\nBuilt on top of `isInView`, returns a `thenable` that will execute based on whether a node with `nodeType` === 1 (HTMLElement) is visible. The result will be refreshed after `numberFrames`:\n\n```\nrafx.ifInView(div,20)\n    .then(function(){\n        /*\n            do something if the element is in view,\n            otherwise silently fail,\n            if you attach a catch clause, you will receive 'Value Cannot Be Converted To Truthy' Error\n        */\n    }\n```\n\nAbove `thenable` will execute if the element is in view. Calling `rafx.ifInView(div,20)` again will return a new `thenable`, but whether the element is out of view or not will be refreshed after 20 frames (~0.33 secs)\n\n#### Returns\n\n`Thenable`\n\n### *rafx.ifNotInView(node[, numberFrames])* [\\\u003cprt.ifNotInView\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L653-L655)\n\u003chr\u003e\n\nBuilt on top of `isInView`, returns a `thenable` that will execute based on whether a node with `nodeType` === 1 (HTMLElement) is NOT visible. The result will be refreshed after `numberFrames`:\n\n```\nrafx.ifNotInView(div,20)\n    .then(function(){\n        /*\n            do something if the element is NOT in view,\n            otherwise silently fail,\n            if you attach a catch clause, you will receive 'Value Cannot Be Converted To Falsey' Error\n        */\n    }\n```\n\nAbove `thenable` will execute if the element is NOT in view. Calling `rafx.ifNotInView(div,20)` again will return a new `thenable`, but whether the element is out of view or not will be refreshed after 20 frames (~0.33 secs)\n\n#### Returns\n\n`Thenable`\n\n### *thenable.break()* [\\\u003cprt.Thenable.prototype.break\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L427-L430)\n\u003chr\u003e\n\nBreaks the  current thenable and all upstream/parent thenables. Use this if you want to cancel execution.\n\nBreaking behavior in RafX is aggressive, nested thenables will inherit the same `breaker` from parent thenables, if you do not want the parent `thenable` to be affected, use `setTimeout`:\n\n```\nconst outer = rafx\n    .skipFrames(600, \"payload\") //wait 10 seconds and pass \"payload\"\n    .then(function(payload){\n        setTimeut(function(){\n            rafx.async()\n\n            //breaking below won't terminate outer\n\n            .then(function(){this.break();}) \n            .then(..); //not executed due to break\n        }, 0);\n    })\n    .then(function(){\n        //do something\n    });\n```\n\n#### Returns\n\n`Thenable`\n\n### *thenable.catch(function)* [\\\u003cprt.Thenable.prototype.catch\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L656-L661)\n\u003chr\u003e\n\nMany clauses in RafX do not throw by default and silently fail when their conditions are not met.\n\nSimilarly, errors might be thrown within ordinary thenables. For all these cases you can attach a `catch` to the thenable. It does not matter where you attach the `catch`, the last one overwrites the previous:\n\n```\nrafx.async()\n    .then(function(){\n        this._identifier = \"thenable 1\";\n        var err = new Error(\"Custom Error\");\n        err._this = this;\n        throw err;\n    })\n    .catch(function(e){\n        console.log(\"catch-1\", e._this._identifier);\n    })\n    .then(function(){\n        this._identifier = \"thenable 2\";\n        var err = new Error(\"Custom Error\");\n        err._this = this;\n        throw err;\n    })\n    .catch(function(e){\n        console.log(\"catch-2\", e._this._identifier);\n    })\n    .then(function(){\n        this._identifier = \"thenable 3\";\n        var err = new Error(\"Custom Error\");\n        err._this = this;\n        throw err;\n    });\n\n/*\n    OUTPUT\n    catch-2 thenable 1\n*/\n```\n\n### *rafx.duration(string)* [\\\u003cDuration\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L125-L133)\n\u003chr\u003e\n\nRafX by default operates on frames, if you want to work with seconds or milliseconds, you can use this constructor:\n\n```\n    let dur = rafx.duration();\n    let dur = rafx.duration(\"4 mins\");\n    let dur = rafx.duration(\"5 seconds\");\n```\n\nThe input string, if any is matched against [\\\u003cDuration.prototype.rgx\\\u003e](https://github.com/IbrahimTanyalcin/RafX/blob/master/dist/rafx.v0.0.20.dev.js#L255-L272)\n\nThis returns a duration object where you can set the value and the unit. Values are integers, units can be \"minutes\", \"seconds\" etc. To set unit, you can use `u`, `unit` or `setUnit` methods, whereas for value you can choose from `v`, `value`, `setVal` or `val`:\n\n```\n    dur\n    .set\n    .unit(\"f\")\n    .u(\"frames\")\n    .setUnit(\"frame\")\n    .unit(\"ms\")\n    .u(\"milliseconds\")\n    .setUnit(\"millisecond\")\n    .u(\"s\")\n    .setUnit(\"second\")\n    .unit(\"seconds\")\n    .u(\"min\")\n    .setUnit(\"mins\")\n    .unit(\"minutes\")\n    .u(\"minute\")\n    .v(2)\n    .value(2)\n    .setVal(2)\n    .val(2);\n\n```\n\nSetting the unit will automatically convert the value:\n\n```\n    dur.set.unit(\"min\").val(1);\n    dur.set.u(\"f\");\n    +dur; //3600\n```\n\nOnce you set value and unit, you can provide it to `skipFrames`:\n\n```\n    rafx.skipFrames(dur).then(..)\n    rafx.skipFrames(rafx.duration(\"4 mins\")).then(..)\n```\n\n#### Returns\n\n`Duration`\n\n## Performance\n\nRafX has comparable performance to D3 v5, for more details you can inspect the screen shots and the html files in the `perf` folder under `src`.\n\n## Publishing\n\n- leave a single file inside the untracked `./dev` folder, matching the pattern below:\n\n```\n/^rafx\\.v(?:[0-9]+\\.){3}dev\\.js/i`\n```\n- run: \n\n```\nnpm run publishPatch\n```\n- After running the command:\n    - The older `dev/min` builds will be copied to `./olderVersions` (not tracked)\n    - The file inside `./dev` will be copied to `./dist`, renamed and updated within the file to match the npm version\n    - The above file will be minified and placed similarly inside `./dist` with `.min.js` extension\n    - Readme source code line pointers will be updated\n    - For the remaining tasks performed check `package.json`'s `publishPatch` script.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibrahimtanyalcin%2Frafx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fibrahimtanyalcin%2Frafx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibrahimtanyalcin%2Frafx/lists"}