├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | tmp/ 4 | npm-debug.log* 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "0.12" 3 | - "4" 4 | sudo: false 5 | language: node_js 6 | script: "npm run test:cov" 7 | after_script: "npm i -g codecov.io && cat ./coverage/lcov.info | codecov" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yoshua Wuyts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nanotick [![stability][0]][1] 2 | [![npm version][2]][3] [![build status][4]][5] [![test coverage][6]][7] 3 | [![downloads][8]][9] [![js-standard-style][10]][11] 4 | 5 | Process.nextTick() batching utility. 6 | 7 | ## Usage 8 | ```js 9 | var nanotick = require('nanotick') 10 | 11 | var tick = nanotick() 12 | 13 | var myFunc = tick(function () { 14 | // do sync thing 15 | }) 16 | 17 | // now resolves async 18 | myFunc() 19 | ``` 20 | 21 | ## API 22 | ### tick = nanotick 23 | Create a new nanotick instance 24 | 25 | ### tick(cb) 26 | Always resolve a function asynchronously. Uses batching under the hood to 27 | optimize performance 28 | 29 | ## Installation 30 | ```sh 31 | $ npm install nanotick 32 | ``` 33 | 34 | ## See Also 35 | - [yoshuawuyts/nanoraf](https://github.com/yoshuawuyts/nanoraf) 36 | - [yoshuawuyts/nanomorph](https://github.com/yoshuawuyts/nanomorph) 37 | 38 | ## License 39 | [MIT](https://tldrlegal.com/license/mit-license) 40 | 41 | [0]: https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square 42 | [1]: https://nodejs.org/api/documentation.html#documentation_stability_index 43 | [2]: https://img.shields.io/npm/v/nanotick.svg?style=flat-square 44 | [3]: https://npmjs.org/package/nanotick 45 | [4]: https://img.shields.io/travis/yoshuawuyts/nanotick/master.svg?style=flat-square 46 | [5]: https://travis-ci.org/yoshuawuyts/nanotick 47 | [6]: https://img.shields.io/codecov/c/github/yoshuawuyts/nanotick/master.svg?style=flat-square 48 | [7]: https://codecov.io/github/yoshuawuyts/nanotick 49 | [8]: http://img.shields.io/npm/dm/nanotick.svg?style=flat-square 50 | [9]: https://npmjs.org/package/nanotick 51 | [10]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 52 | [11]: https://github.com/feross/standard 53 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-eval */ 2 | var assert = require('assert') 3 | 4 | module.exports = nanotick 5 | var delay = (typeof window !== 'undefined' && window.document) 6 | ? (typeof setImmediate !== 'undefined') 7 | ? setImmediate 8 | : setTimeout 9 | : eval('process.nextTick') 10 | 11 | // Process.nextTick() batching ulity 12 | // null -> fn(any) -> fn(any) 13 | function nanotick () { 14 | var callbacks = [] 15 | var interval = false 16 | 17 | return function tick (cb) { 18 | assert.equal(typeof cb, 'function', 'nanotick.tick: cb should be a function') 19 | 20 | var isAsync = false 21 | 22 | executeAsync(function () { 23 | isAsync = true 24 | }) 25 | 26 | return function wrappedTick () { 27 | var length = arguments.length 28 | var args = new Array(length) 29 | for (var i = 0; i < length; i++) args[i] = arguments[i] 30 | 31 | if (isAsync) { 32 | cb.apply(cb, args) 33 | } else { 34 | executeAsync(function () { 35 | cb.apply(cb, args) 36 | }) 37 | } 38 | } 39 | } 40 | 41 | function executeAsync (cb) { 42 | callbacks.push(cb) 43 | 44 | if (!interval) { 45 | interval = true 46 | delay(function () { 47 | while (callbacks.length > 0) { 48 | callbacks.shift()() 49 | } 50 | interval = false 51 | }) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nanotick", 3 | "version": "1.1.6", 4 | "description": "Process.nextTick() batching utility", 5 | "main": "index.js", 6 | "scripts": { 7 | "deps": "dependency-check . && dependency-check . --extra --no-dev", 8 | "test": "standard && npm run deps && NODE_ENV=test node test", 9 | "test:cov": "standard && npm run deps && NODE_ENV=test istanbul cover test.js" 10 | }, 11 | "repository": "yoshuawuyts/nanotick", 12 | "keywords": [ 13 | "batch", 14 | "process", 15 | "next-tick", 16 | "settimeout", 17 | "timer" 18 | ], 19 | "license": "MIT", 20 | "dependencies": {}, 21 | "devDependencies": { 22 | "dependency-check": "^2.6.0", 23 | "istanbul": "^0.4.5", 24 | "standard": "^8.6.0", 25 | "tape": "^4.6.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var nanotick = require('./') 3 | 4 | test('nanotick', function (t) { 5 | t.test('should assert input types', function (t) { 6 | t.plan(1) 7 | var tick = nanotick() 8 | t.throws(tick.bind(null), /function/) 9 | }) 10 | 11 | t.test('async functions should resolve in the same tick', function (t) { 12 | t.plan(1) 13 | 14 | var oops = false 15 | process.nextTick(function () { 16 | process.nextTick(function () { 17 | oops = true 18 | }) 19 | }) 20 | 21 | var tick = nanotick() 22 | var fn = tick(function () { 23 | t.equal(oops, false) 24 | }) 25 | 26 | process.nextTick(fn) 27 | }) 28 | 29 | t.test('sync function should resolve in the next tick', function (t) { 30 | t.plan(1) 31 | 32 | var oops = false 33 | process.nextTick(function () { 34 | process.nextTick(function () { 35 | oops = true 36 | }) 37 | }) 38 | 39 | var tick = nanotick() 40 | var fn = tick(function () { 41 | t.equal(oops, false) 42 | }) 43 | 44 | fn() 45 | }) 46 | 47 | t.test('is able to push more values onto the same tick from within a tick', function (t) { 48 | t.plan(2) 49 | 50 | var changed = false 51 | process.nextTick(function () { 52 | process.nextTick(function () { 53 | changed = true 54 | }) 55 | }) 56 | 57 | var tick = nanotick() 58 | ;(tick(function () { 59 | t.equal(changed, false) 60 | 61 | ;(tick(function () { 62 | t.equal(changed, false) 63 | }))() 64 | }))() 65 | }) 66 | 67 | t.test('scheduled functions should be cleared after their execution', function (t) { 68 | t.plan(1) 69 | 70 | var numCalls = 0 71 | var tick = nanotick() 72 | 73 | // Arrange for a function to be called on the first tick 74 | tick(function () { 75 | ++numCalls 76 | })() 77 | 78 | process.nextTick(function () { 79 | // Arrange for another function to be called on the second tick 80 | tick(function () { 81 | })() 82 | process.nextTick(function () { 83 | t.equal(numCalls, 1, 'There should only be one call to a scheduled function') 84 | }) 85 | }) 86 | }) 87 | }) 88 | --------------------------------------------------------------------------------