| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import { handleError, ErrorTypes } from './errorHandling'
- const queue: Function[] = []
- const postFlushCbs: Function[] = []
- const p = Promise.resolve()
- let isFlushing = false
- export function nextTick(fn?: () => void): Promise<void> {
- return fn ? p.then(fn) : p
- }
- export function queueJob(job: () => void) {
- if (queue.indexOf(job) === -1) {
- queue.push(job)
- if (!isFlushing) {
- nextTick(flushJobs)
- }
- }
- }
- export function queuePostFlushCb(cb: Function | Function[]) {
- if (Array.isArray(cb)) {
- postFlushCbs.push.apply(postFlushCbs, cb)
- } else {
- postFlushCbs.push(cb)
- }
- if (!isFlushing) {
- nextTick(flushJobs)
- }
- }
- const dedupe = (cbs: Function[]): Function[] => Array.from(new Set(cbs))
- export function flushPostFlushCbs() {
- if (postFlushCbs.length) {
- const cbs = dedupe(postFlushCbs)
- postFlushCbs.length = 0
- for (let i = 0; i < cbs.length; i++) {
- cbs[i]()
- }
- }
- }
- const RECURSION_LIMIT = 100
- type JobCountMap = Map<Function, number>
- function flushJobs(seenJobs?: JobCountMap) {
- isFlushing = true
- let job
- if (__DEV__) {
- seenJobs = seenJobs || new Map()
- }
- while ((job = queue.shift())) {
- if (__DEV__) {
- const seen = seenJobs as JobCountMap
- if (!seen.has(job)) {
- seen.set(job, 1)
- } else {
- const count = seen.get(job) as number
- if (count > RECURSION_LIMIT) {
- throw new Error(
- 'Maximum recursive updates exceeded. ' +
- "You may have code that is mutating state in your component's " +
- 'render function or updated hook.'
- )
- } else {
- seen.set(job, count + 1)
- }
- }
- }
- try {
- job()
- } catch (err) {
- handleError(err, null, ErrorTypes.SCHEDULER)
- }
- }
- flushPostFlushCbs()
- isFlushing = false
- // some postFlushCb queued jobs!
- // keep flushing until it drains.
- if (queue.length) {
- flushJobs(seenJobs)
- }
- }
|