├── .gitignore ├── test ├── windowMock.js ├── timeMocks.ts └── test.spec.ts ├── src ├── index.ts └── hirestime.ts ├── .npmignore ├── .travis.yml ├── LICENSE ├── tsconfig.json ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules/ 3 | dist/ 4 | -------------------------------------------------------------------------------- /test/windowMock.js: -------------------------------------------------------------------------------- 1 | global.window = { 2 | performance: {} 3 | }; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import hirestime from './hirestime' 2 | 3 | export default hirestime -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .travis.yml 4 | tsconfig.json 5 | *.ts 6 | !*.d.ts -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10.0" 4 | - "12.0" 5 | - "14.0" 6 | script: npm test -------------------------------------------------------------------------------- /test/timeMocks.ts: -------------------------------------------------------------------------------- 1 | 2 | type HrTimeTuple = [ number, number ] 3 | 4 | export const hrtimeMock = (duration: number) => { 5 | const realHrTime = process.hrtime 6 | let first = true 7 | const hrt = (startTime: HrTimeTuple): HrTimeTuple => { 8 | if (first) { 9 | first = false; 10 | return [ 0, 0 ] 11 | } 12 | process.hrtime = realHrTime 13 | return [ Math.round(duration / 1e3), (duration % 1000) * 1e6 ] 14 | } 15 | hrt.bigint = () => BigInt(0) 16 | process.hrtime = hrt 17 | }; 18 | 19 | export const mockPerformance = (duration: number) => { 20 | let first = true; 21 | window.performance.now = () => { 22 | if (first) { 23 | first = false 24 | return 0 25 | } 26 | return duration; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Manuel Ernst 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "buildOnSave": false, 4 | "include": [ 5 | "src/**/*" 6 | ], 7 | "exclude": [ 8 | "node_modules" 9 | ], 10 | "typeAcquisition": { 11 | "enable": false 12 | }, 13 | "compilerOptions": { 14 | "baseUrl": ".", 15 | "paths": { 16 | "*": [ 17 | "src/*", 18 | "*" 19 | ] 20 | }, 21 | "outDir": "./dist/", 22 | "diagnostics": false, 23 | "sourceMap": true, 24 | "alwaysStrict": true, 25 | "moduleResolution": "node", 26 | "esModuleInterop": true, 27 | "noImplicitAny": true, 28 | "noImplicitReturns": true, 29 | "noImplicitThis": true, 30 | "noUnusedLocals": true, 31 | "pretty": true, 32 | "target": "es2018", 33 | "module": "CommonJS", 34 | "removeComments": false, 35 | "preserveConstEnums": true, 36 | "declaration": true, 37 | "experimentalDecorators": false, 38 | "emitDecoratorMetadata": false, 39 | "allowSyntheticDefaultImports": true, 40 | "traceResolution": false 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hirestime 2 | 3 | `hirestime` is a thin wrapper around the common time measuring APIs (node and the browser). 4 | Uses `process.hrtime()` on node, the [performance API](https://developer.mozilla.org/de/docs/Web/API/Performance/now) in the browser and falls back to `Date` if neither is available. 5 | 6 | ## Installation 7 | 8 | ````bash 9 | npm install hirestime 10 | ```` 11 | 12 | ## hirestime() 13 | returns a function: 14 | 15 | ### returnedFunction() 16 | Returns the elapsed time since the call of `hirestime` in milliseconds. 17 | 18 | ## Examples 19 | 20 | By default the time is measured in milliseconds: 21 | ````javascript 22 | import hirestime from 'hirestime' 23 | 24 | //startpoint of the time measurement 25 | const getElapsed = hirestime() 26 | 27 | setTimeout(_ => { 28 | //returns the elapsed milliseconds 29 | console.log(getElapsed()) 30 | }, 1000) 31 | ```` 32 | 33 | Specify the unit: 34 | ````javascript 35 | import hirestime from 'hirestime' 36 | 37 | //startpoint of the time measurement 38 | const getElapsed = hirestime() 39 | 40 | setTimeout(_ => { 41 | //returns the elapsed seconds 42 | console.log(getElapsed.s()) 43 | console.log(getElapsed.seconds()) 44 | 45 | //returns the elapsed milliseconds 46 | console.log(getElapsed.ms()) 47 | console.log(getElapsed.milliseconds()) 48 | 49 | //returns the elapsed nanoseconds 50 | console.log(getElapsed.ns()) 51 | console.log(getElapsed.nanoseconds()) 52 | }, 1000) 53 | ```` 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hirestime", 3 | "version": "7.0.4", 4 | "type": "module", 5 | "description": "thin wrapper around process.hrtime", 6 | "exports": { 7 | "require": "./dist/index.cjs", 8 | "types": "./dist/index.d.ts", 9 | "default": "./dist/index.esm.js" 10 | }, 11 | "main": "./dist/index.cjs", 12 | "module": "./dist/index.esm.js", 13 | "umd:main": "./dist/index.umd.js", 14 | "types": "./dist/index.d.ts", 15 | "scripts": { 16 | "prepublish": "npm run build", 17 | "build": "microbundle --no-sourcemap", 18 | "test": "ts-mocha --require test/windowMock.js --paths test/**/*.ts", 19 | "test:watch": "ts-mocha --require test/windowMock.js --paths test/**/*.ts -w --watch-extensions ts" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/seriousManual/hirestime.git" 24 | }, 25 | "keywords": [ 26 | "hrtime", 27 | "hirestimer", 28 | "milliseconds", 29 | "seconds", 30 | "nanoseconds", 31 | "high resolution timer", 32 | "profiling", 33 | "profiler", 34 | "timing", 35 | "measurement" 36 | ], 37 | "author": "Manuel Ernst ", 38 | "license": "MIT", 39 | "bugs": { 40 | "url": "https://github.com/seriousManual/hirestime/issues" 41 | }, 42 | "devDependencies": { 43 | "@types/chai": "^4.2.12", 44 | "@types/expect": "^24.3.0", 45 | "@types/mocha": "^9.1.1", 46 | "@types/node": "^17.0.35", 47 | "@types/sinon": "^10.0.11", 48 | "chai": "^4.2.0", 49 | "microbundle": "^0.15.1", 50 | "mocha": "^10.0.0", 51 | "sinon": "^14.0.0", 52 | "ts-mocha": "^10.0.0", 53 | "ts-node": "^10.7.0", 54 | "tsconfig-paths": "^4.0.0" 55 | }, 56 | "files": [ 57 | "dist" 58 | ], 59 | "engines": { 60 | "node": ">=6.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/hirestime.ts: -------------------------------------------------------------------------------- 1 | export interface Elapsor { 2 | startedAt: () => number; 3 | (): number 4 | seconds(): number 5 | s(): number 6 | milliseconds(): number 7 | ms(): number 8 | microseconds(): number 9 | us(): number 10 | nanoseconds(): number 11 | ns(): number 12 | } 13 | 14 | const hrTimeToMillis = (hrtime: [number, number]) => hrtime[0] * 1e3 + hrtime[1] / 1e6 15 | const round = (number: number) => Number(number.toFixed(2)) 16 | 17 | const getElapsor = (startTime: number, getTime: () => number): Elapsor => { 18 | const elapsor = () => round(getTime()) 19 | 20 | elapsor.startedAt = () => startTime 21 | elapsor.seconds = elapsor.s = () => round(getTime() / 1e3) 22 | elapsor.milliseconds = elapsor.ms = () => round(getTime()) 23 | elapsor.microseconds = elapsor.us = () => round(getTime() * 1e3) 24 | elapsor.nanoseconds = elapsor.ns = () => round(getTime() * 1e6) 25 | 26 | return elapsor; 27 | } 28 | 29 | export const hiresTimeBrowserDate = (): Elapsor => { 30 | const start = Date.now() 31 | return getElapsor(start, () => Date.now() - start) 32 | } 33 | 34 | export const hiresTimeBrowserPerformance = (): Elapsor => { 35 | const start = window.performance.now() 36 | return getElapsor(start, () => window.performance.now() - start) 37 | } 38 | 39 | export const hirestimeNode = (): Elapsor => { 40 | const start = process.hrtime() 41 | return getElapsor(hrTimeToMillis(start), () => hrTimeToMillis(process.hrtime(start))) 42 | } 43 | 44 | const isRunningInNode = () => typeof process !== "undefined" && process.hrtime 45 | const isRunningInBrowser = () => typeof window !== "undefined" && window.performance 46 | 47 | const hirestime = isRunningInNode() ? hirestimeNode : 48 | isRunningInBrowser() ? hiresTimeBrowserPerformance : 49 | hiresTimeBrowserDate 50 | 51 | export default hirestime 52 | -------------------------------------------------------------------------------- /test/test.spec.ts: -------------------------------------------------------------------------------- 1 | import { useFakeTimers } from 'sinon' 2 | import { expect } from 'chai' 3 | 4 | import { hrtimeMock, mockPerformance } from './timeMocks' 5 | 6 | import { 7 | hiresTimeBrowserDate, 8 | hiresTimeBrowserPerformance, 9 | hirestimeNode 10 | } from '../src/hirestime' 11 | 12 | describe('hirestime', () => { 13 | describe('node', () => { 14 | it('should return the timestamp when the timer was started in milliseconds', () => { 15 | const now = process.hrtime() 16 | const timer = hirestimeNode() 17 | expect(Math.round(timer.startedAt())).to.equal(Math.round(now[0] * 1e3 + now[1] / 1e6)) 18 | }) 19 | 20 | it('should return an approximate number of elapsed time in milliseconds (no unit given)', () => { 21 | hrtimeMock(1119.1111) 22 | const getElapsed = hirestimeNode() 23 | expect(getElapsed()).to.equal(1119.11) 24 | }) 25 | 26 | it('should return an approximate number of elapsed time in seconds (seconds unit)', () => { 27 | hrtimeMock(1119.1111) 28 | const getElapsed = hirestimeNode() 29 | 30 | expect(getElapsed.s()).to.equal(1.12) 31 | }) 32 | 33 | it('should return an approximate number of elapsed time in seconds (seconds unit)', () => { 34 | hrtimeMock(1119.1111) 35 | const getElapsed = hirestimeNode() 36 | 37 | expect(getElapsed.seconds()).to.equal(1.12) 38 | }) 39 | 40 | it('should return an approximate number of elapsed time in milliseconds (milliseconds unit)', () => { 41 | hrtimeMock(1119.1111) 42 | const getElapsed = hirestimeNode() 43 | 44 | expect(getElapsed.ms()).to.equal(1119.11) 45 | }) 46 | 47 | it('should return an approximate number of elapsed time in milliseconds (milliseconds unit)', () => { 48 | hrtimeMock(1119.1111) 49 | const getElapsed = hirestimeNode() 50 | 51 | expect(getElapsed.milliseconds()).to.equal(1119.11) 52 | }) 53 | 54 | it('should return an approximate number of elapsed time in microseconds (microseconds unit)', () => { 55 | hrtimeMock(1119.1111) 56 | const getElapsed = hirestimeNode() 57 | 58 | expect(getElapsed.us()).to.equal(1119111.1) 59 | }) 60 | 61 | it('should return an approximate number of elapsed time in microseconds (microseconds unit)', () => { 62 | hrtimeMock(1119.1111) 63 | const getElapsed = hirestimeNode() 64 | 65 | expect(getElapsed.microseconds()).to.equal(1119111.1) 66 | }) 67 | 68 | it('should return an approximate number of elapsed time in nanoseconds (nanoseconds unit)', () => { 69 | hrtimeMock(1119.1111) 70 | const getElapsed = hirestimeNode() 71 | 72 | expect(getElapsed.ns()).to.equal(1119111100) 73 | }) 74 | 75 | it('should return an approximate number of elapsed time in nanoseconds (nanoseconds unit)', () => { 76 | hrtimeMock(1119.1111) 77 | const getElapsed = hirestimeNode() 78 | 79 | expect(getElapsed.nanoseconds()).to.equal(1119111100) 80 | }) 81 | }) 82 | 83 | describe('browserDate', () => { 84 | it('should return the timestamp when the timer was started in milliseconds', () => { 85 | const now = Date.now() 86 | const timer = hiresTimeBrowserDate() 87 | expect(Math.round(timer.startedAt())).to.equal(now) 88 | }) 89 | 90 | it('should return an approximate number of elapsed time in milliseconds (no unit given)', () => { 91 | const clock = useFakeTimers() 92 | const getElapsed = hiresTimeBrowserDate() 93 | clock.tick(1119.1111) 94 | 95 | expect(getElapsed()).to.equal(1119) 96 | 97 | clock.restore() 98 | }) 99 | }) 100 | 101 | describe('browserPerformance', () => { 102 | it('should return the timestamp when the timer was started in milliseconds', () => { 103 | const now = mockPerformance(1119.1111) 104 | const timer = hiresTimeBrowserPerformance() 105 | expect(Math.round(timer.startedAt())).to.equal(0) 106 | }) 107 | 108 | it('should return an approximate number of elapsed time in milliseconds (no unit given)', () => { 109 | mockPerformance(1119.1111) 110 | const getElapsed = hiresTimeBrowserPerformance() 111 | expect(getElapsed()).to.equal(1119.11) 112 | }) 113 | }) 114 | }) 115 | --------------------------------------------------------------------------------