рдмрдВрдж рдХреЛ рддреЛрдбрд╝рдиреЗ рдФрд░ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдЗрдВрдЬреЗрдХреНрд╖рди

рдЫрд╡рд┐


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдбрд┐рдкреЗрдВрдбреЗрдВрд╕реА рдЗрдВрдЬреЗрдХреНрд╢рди рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╢реИрд▓реА рдореЗрдВ рд╕реНрд╡рдЪреНрдЫ, рдЖрд╕рд╛рдиреА рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдпреЛрдЧреНрдп рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рджреЗрдЦреЗрдВрдЧреЗред рдмреЛрдирд╕ 100% рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдХрд╡рд░реЗрдЬ рд╣реИред


рд▓реЗрдЦ рдореЗрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╢рдмреНрджрд╛рд╡рд▓реА


рд▓реЗрдЦ рдХреЗ рд▓реЗрдЦрдХ рдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╢рдмреНрджреЛрдВ рдХреА рдРрд╕реА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдирд╛ рд╣реЛрдЧрд╛, рдпрд╣ рд╕рдордЭрдирд╛ рдХрд┐ рдпрд╣ рдЕрдВрддрд┐рдо рд╕рддреНрдп рдирд╣реАрдВ рд╣реИ рдФрд░ рдЕрдиреНрдп рд╡реНрдпрд╛рдЦреНрдпрд╛рдПрдВ рд╕рдВрднрд╡ рд╣реИрдВред


  • рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди
    рдпрд╣ рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдкреИрдЯрд░реНрди рд╣реИ рдЬреЛ рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдХрд╛рд░реНрдпреЛрдВ рдФрд░ рд╡рд╕реНрддреБ рдХрд╛рд░рдЦрд╛рдиреЛрдВ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░реА рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдмрд╛рд╣рд░ рд╕реЗ рдЖрддреА рд╣реИрдВред рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдПрдХ рд╡реИрд╢реНрд╡рд┐рдХ рд╕рдВрджрд░реНрдн рд╕реЗ рдирд┐рд░реНрднрд░рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИред
  • рдиреЗрдЯ рдлрд╝рдВрдХреНрд╢рди
    рдпрд╣ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдХреЗрд╡рд▓ рдЙрд╕рдХреЗ рддрд░реНрдХреЛрдВ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред рд╕рд╛рде рд╣реА, рдлрдВрдХреНрд╢рди рдХрд╛ рд╕рд╛рдЗрдб рдЗрдлреЗрдХреНрдЯ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
    рдореИрдВ рддреБрд░рдВрдд рдПрдХ рдЖрд░рдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЬрд┐рди рдХрд╛рд░реНрдпреЛрдВ рдкрд░ рд╣рдо рд╡рд┐рдЪрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЙрдирдХреЗ рджреБрд╖реНрдкреНрд░рднрд╛рд╡ рдирд╣реАрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡реЗ рдЕрднреА рднреА рдХрд╛рд░реНрдп рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдбрд┐рдкреЗрдВрдбреЗрдВрд╕реА рдЗрдВрдЬреЗрдХреНрд╢рди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЖрдП рдереЗред рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЬреЛ рдХрд╛рд░реНрдп рд╣реИрдВ рдЙрдирдХреА рд╢реБрджреНрдзрддрд╛ рдПрдХ рдмрдбрд╝реЗ рдЖрд░рдХреНрд╖рдг рдХреЗ рд╕рд╛рде рд╣реИред
  • рдЗрдХрд╛рдИ рдкрд░реАрдХреНрд╖рдг
    рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкрд░реАрдХреНрд╖рдг рдЬреЛ рдпрд╣ рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрджрд░ рд╕рднреА рдХрд╛рдВрдЯреЗ рдареАрдХ рдЙрд╕реА рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓реЗрдЦрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдХрд┐рд╕реА рдЕрдиреНрдп рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рдореЛрдХреНрд╕ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╣рдо рдЕрднреНрдпрд╛рд╕ рдореЗрдВ рд╕рдордЭрддреЗ рд╣реИрдВ


рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рдХрд╛рдЙрдВрдЯрд░реЛрдВ рдХреА рдПрдХ рдлреИрдХреНрдЯреНрд░реА рдЬреЛ tick рдЧрд┐рдирддреА рдХрд░рддреА tick ред cancel рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рдЙрдВрдЯрд░ рдХреЛ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


 const createCounter = ({ ticks, onTick }) => { const state = { currentTick: 1, timer: null, canceled: false } const cancel = () => { if (state.canceled) { throw new Error('"Counter" already canceled') } clearInterval(state.timer) } const onInterval = () => { onTick(state.currentTick++) if (state.currentTick > ticks) { cancel() } } state.timer = setInterval(onInterval, 200) const instance = { cancel } return instance } export default createCounter 

рд╣рдо рдорд╛рдирд╡-рдкрдардиреАрдп, рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп рдХреЛрдб рджреЗрдЦрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдПрдХ рдХреИрдЪ рд╣реИ - рдЙрд╕ рдкрд░ рд╕рд╛рдорд╛рдиреНрдп рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдирд╣реАрдВ рд▓рд┐рдЦреЗ рдЬрд╛ рд╕рдХрддреЗред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рд░рд╛рд╕реНрддреЗ рдореЗрдВ рдХреНрдпрд╛ рд╣реИ?


1) рдЖрдк cancel , onInterval рдЕрдВрджрд░ рдлрдВрдХреНрд╢рдиреНрд╕ рддрдХ рдирд╣реАрдВ рдкрд╣реБрдБрдЪ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЕрд▓рдЧ рд╕реЗ рдЯреЗрд╕реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


2) onInterval рдлрд╝рдВрдХреНрд╢рди рдХреЛ cancel рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдЕрд▓рдЧ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдкрд╣рд▓реЗ рдХрд╛ рджреВрд╕рд░реЗ рд╕реЗ рд╕реАрдзрд╛ рд╕рдВрдмрдВрдз рд╣реИред


3) рдмрд╛рд╣рд░реА рдирд┐рд░реНрднрд░рддрд╛ clearInterval , clearInterval ред


4) createCounter рдлрд╝рдВрдХреНрд╢рди createCounter рдЕрдиреНрдп рд▓рд┐рдВрдХ рд╕реЗ рдЕрд▓рдЧ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдлрд┐рд░ рд╕реЗ рд╕реАрдзреЗ рд▓рд┐рдВрдХ рдХреЗ рдХрд╛рд░рдгред


рдЖрдЗрдП рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░реЗрдВ 1) 2) - рд╣рдо onInterval рд╕реЗ cancel , onInterval рдХреЛ onInterval рдФрд░ pool рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЙрдирдХреЗ рдмреАрдЪ рд╕реАрдзрд╛ рд▓рд┐рдВрдХ рддреЛрдбрд╝рддреЗ рд╣реИрдВред


 export const cancel = pool => { if (pool.state.canceled) { throw new Error('"Counter" already canceled') } clearInterval(pool.state.timer) } export const onInterval = pool => { pool.config.onTick(pool.state.currentTick++) if (pool.state.currentTick > pool.config.ticks) { pool.cancel() } } const createCounter = config => { const pool = { config, state: { currentTick: 1, timer: null, canceled: false } } pool.cancel = cancel.bind(null, pool) pool.onInterval = onInterval.bind(null, pool) pool.state.timer = setInterval(pool.onInterval, 200) const instance = { cancel: pool.cancel } return instance } export default createCounter 

рд╣рдо рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рдорд╛рдзрд╛рди 3) рдХрд░рддреЗ рд╣реИрдВред рд╣рдо setInterval , clearInterval рдкрд░ рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ pool рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рднреА рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред


 export const cancel = pool => { const { clearInterval } = pool if (pool.state.canceled) { throw new Error('"Counter" already canceled') } clearInterval(pool.state.timer) } export const onInterval = pool => { pool.config.onTick(pool.state.currentTick++) if (pool.state.currentTick > pool.config.ticks) { pool.cancel() } } const createCounter = (dependencies, config) => { const pool = { ...dependencies, config, state: { currentTick: 1, timer: null, canceled: false } } pool.cancel = cancel.bind(null, pool) pool.onInterval = onInterval.bind(null, pool) const { setInterval } = pool pool.state.timer = setInterval(pool.onInterval, 200) const instance = { cancel: pool.cancel } return instance } export default createCounter.bind(null, { setInterval, clearInterval }) 

рдЕрдм рд▓рдЧрднрдЧ рд╕рдм рдХреБрдЫ рдареАрдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрднреА рднреА рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ 4)ред рдЕрдВрддрд┐рдо рдЪрд░рдг рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ pool рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЙрдирдХреЗ рдмреАрдЪ рд╢реЗрд╖ рдХрдиреЗрдХреНрд╢рди рдХреЛ рддреЛрдбрд╝рддреЗ рд╣реИрдВред рдЙрд╕реА рд╕рдордп, рд╣рдо рдПрдХ рдмрдбрд╝реА рдлрд╛рдЗрд▓ рдХреЛ рдХрдИ рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддрд╛рдХрд┐ рдмрд╛рдж рдореЗрдВ рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рд▓рд┐рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рдПред


 // index.js import { createCounter } from './create-counter' import { cancel } from './cancel' import { onInterval } from './on-interval' export default createCounter.bind(null, { cancel, onInterval, setInterval, clearInterval }) 

 // create-counter.js export const createCounter = (dependencies, config) => { const pool = { ...dependencies, config, state: { currentTick: 1, timer: null, canceled: false } } pool.cancel = dependencies.cancel.bind(null, pool) pool.onInterval = dependencies.onInterval.bind(null, pool) const { setInterval } = pool pool.state.timer = setInterval(pool.onInterval, 200) const instance = { cancel: pool.cancel } return instance } 

 // on-interval.js export const onInterval = pool => { pool.config.onTick(pool.state.currentTick++) if (pool.state.currentTick > pool.config.ticks) { pool.cancel() } } 

 // cancel.js export const cancel = pool => { const { clearInterval } = pool if (pool.state.canceled) { throw new Error('"Counter" already canceled') } clearInterval(pool.state.timer) } 

рдирд┐рд╖реНрдХрд░реНрд╖


рдЖрдЦрд┐рд░ рдореЗрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреНрдпрд╛ рд╣реИ? рдлрд╛рдЗрд▓реЛрдВ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдВ рдПрдХ рд╕рд╛рдл рдлрд╝рдВрдХреНрд╢рди рд╣реЛрддрд╛ рд╣реИред рдХреЛрдб рдХреА рд╕рд╛рджрдЧреА рдФрд░ рд╕рдордЭрджрд╛рд░реА рдереЛрдбрд╝реА рдЦрд░рд╛рдм рд╣реЛ рдЧрдИ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ 100% рдХрд╡рд░реЗрдЬ рдХреА рддрд╕реНрд╡реАрд░ рд╕реЗ рдореБрдЖрд╡рдЬрд╛ рд╕реЗ рдЕрдзрд┐рдХ рд╣реИред


рдХрд╡рд░реЗрдЬ


рдореИрдВ рдпрд╣ рднреА рдиреЛрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ require рд╕рд╛рде рдХреЛрдИ рд╣реЗрд░рдлреЗрд░ рдХрд░рдиреЗ рдХреА require рдФрд░ рдлрд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред Node.js.


рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг
 // cancel.test.js import { cancel } from '../src/cancel' describe('method "cancel"', () => { test('should stop the counter', () => { const state = { canceled: false, timer: 42 } const clearInterval = jest.fn() const pool = { state, clearInterval } cancel(pool) expect(clearInterval).toHaveBeenCalledWith(pool.state.timer) }) test('should throw error: "Counter" already canceled', () => { const state = { canceled: true, timer: 42 } const clearInterval = jest.fn() const pool = { state, clearInterval } expect(() => cancel(pool)).toThrow('"Counter" already canceled') expect(clearInterval).not.toHaveBeenCalled() }) }) 

 // create-counter.test.js import { createCounter } from '../src/create-counter' describe('method "createCounter"', () => { test('should create a counter', () => { const boundCancel = jest.fn() const boundOnInterval = jest.fn() const timer = 42 const cancel = { bind: jest.fn().mockReturnValue(boundCancel) } const onInterval = { bind: jest.fn().mockReturnValue(boundOnInterval) } const setInterval = jest.fn().mockReturnValue(timer) const dependencies = { cancel, onInterval, setInterval } const config = { ticks: 42 } const counter = createCounter(dependencies, config) expect(cancel.bind).toHaveBeenCalled() expect(onInterval.bind).toHaveBeenCalled() expect(setInterval).toHaveBeenCalledWith(boundOnInterval, 200) expect(counter).toHaveProperty('cancel') }) }) 

 // on-interval.test.js import { onInterval } from '../src/on-interval' describe('method "onInterval"', () => { test('should call "onTick"', () => { const onTick = jest.fn() const cancel = jest.fn() const state = { currentTick: 1 } const config = { ticks: 5, onTick } const pool = { onTick, cancel, state, config } onInterval(pool) expect(onTick).toHaveBeenCalledWith(1) expect(pool.state.currentTick).toEqual(2) expect(cancel).not.toHaveBeenCalled() }) test('should call "onTick" and "cancel"', () => { const onTick = jest.fn() const cancel = jest.fn() const state = { currentTick: 5 } const config = { ticks: 5, onTick } const pool = { onTick, cancel, state, config } onInterval(pool) expect(onTick).toHaveBeenCalledWith(5) expect(pool.state.currentTick).toEqual(6) expect(cancel).toHaveBeenCalledWith() }) }) 

рдХреЗрд╡рд▓ рдЕрдВрдд рддрдХ рд╕рднреА рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЦреЛрд▓рдХрд░, рд╣рдо рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред

Source: https://habr.com/ru/post/hi440552/


All Articles