diff --git a/src/components/bisector/api.ts b/src/components/bisector/api.ts index d7f91f322..6e650fcf4 100644 --- a/src/components/bisector/api.ts +++ b/src/components/bisector/api.ts @@ -1,10 +1,10 @@ import { DialogInstance, showDialog } from '@/core/dialog' import type { Settings } from '@/core/settings/types' import { Toast } from '@/core/toast' -import { mountVueComponent } from '@/core/utils' +import { getRandomId, mountVueComponent, sleep } from '@/core/utils' import { useScopedConsole } from '@/core/utils/log' import type { RecordValue } from '../types' -import type { BisectNext } from './bisect' +import type { BisectNext, BisectReturn } from './bisect' import { bisect } from './bisect' import { BisectorOptions } from './options' import ResultToastContent from './ResultToastContent.vue' @@ -13,7 +13,7 @@ type UserComponent = RecordValue let bisectorOptions: BisectorOptions let scopedConsole: ReturnType -let bisectorGenerator: ReturnType +let bisectorGenerator: Generator, BisectReturn> let groupedComponents: Awaited> let dialog: DialogInstance @@ -80,23 +80,25 @@ export const stop = async () => { scopedConsole?.log('stop - 准备停止组件二等分') dialog?.close() const { configurableUserComponents } = await classifyComponents() - const unmatchedComponentNames = [] + const unmatchedComponents: UserComponent[] = [] for (const [componentName, componentSettings] of Object.entries(configurableUserComponents)) { const originalStatus = bisectorOptions.originalComponentEnableState?.[componentName] if (originalStatus == null) { - unmatchedComponentNames.push(componentName) + unmatchedComponents.push(componentSettings) continue } componentSettings.settings.enabled = originalStatus } - if (unmatchedComponentNames.length) { - scopedConsole?.warn( - `stop - 部分组件未能还原状态:${getComponentNames(unmatchedComponentNames)}`, - ) + if (unmatchedComponents.length) { + const msg = `部分组件未能还原状态:${getComponentNames(unmatchedComponents)}` + scopedConsole?.warn(`stop - ${msg}`) + Toast.error(msg, '组件二等分') + await sleep(3e3) } scopedConsole?.log('stop - 清理状态') bisectorGenerator = null bisectorOptions.bisectInitialState = {} + bisectorOptions.originalComponentEnableState = {} scopedConsole?.log('stop - 重载页面') location.reload() } @@ -109,24 +111,20 @@ export const next = async (seeingBad?: boolean, autoReload?: boolean) => { seeingBad == null ? '未知' : seeingBad ? '异常' : '正常' }`, ) - const { done, value } = bisectorGenerator.next(seeingBad) as unknown as { - done: boolean - value: BisectNext | UserComponent - } + const { done, value } = bisectorGenerator.next(seeingBad) if (done) { - const elementId = `bisector-result-toast-content-${Math.floor( - Math.random() * (Number.MAX_SAFE_INTEGER + 1), - )}` - Toast.info(/* html */ `
`, '二等分结果') - setTimeout(() => { - const vm = mountVueComponent<{ userComponent: UserComponent }>( - ResultToastContent, - `#${elementId}`, - ) - vm.userComponent = value as UserComponent - vm.$on('restore', () => { - stop() - }) + const { low, high } = value + bisectorOptions.bisectInitialState = { low, high } + const elementId = `bisector-result-toast-content-${getRandomId()}` + Toast.info(/* html */ `
`, '组件二等分结果') + await sleep() + const vm = mountVueComponent<{ userComponent: UserComponent }>( + ResultToastContent, + `#${elementId}`, + ) + vm.userComponent = value.target + vm.$on('restore', () => { + stop() }) } else { const { slice, low, high } = value as BisectNext diff --git a/src/components/bisector/bisect.ts b/src/components/bisector/bisect.ts index e7d8e1284..017bf8455 100644 --- a/src/components/bisector/bisect.ts +++ b/src/components/bisector/bisect.ts @@ -8,62 +8,84 @@ export interface BisectNext { rouge: number } +export interface BisectReturn extends BisectNext { + target: O +} + export interface InitialState { low?: number high?: number } -export function* bisectLeft(data: readonly O[], initialState?: InitialState) { +export function* bisectLeft( + data: readonly O[], + initialState?: InitialState, +): Generator, BisectReturn> { let low = initialState?.low ?? 0 let high = initialState?.high ?? data.length - let mid = (low + high) >>> 1 + let mid: number - while (true) { - const seeingBad = yield ({ + while (low + 1 < high) { + mid = (low + high) >>> 1 + + const seeingBad = yield { low, high, mid, slice: data.slice(low, mid), rouge: ~~Math.log2(high - low), - } as BisectNext) || false + } if (seeingBad) { high = mid } else { low = mid } - if (low + 1 < high) { - mid = (low + high) >>> 1 - } else { - return data[low] - } + } + + return { + low, + high, + mid, + slice: data.slice(low, mid), + rouge: ~~Math.log2(high - low), + target: data[low], } } -export function* bisectRight(data: readonly O[], initialState?: InitialState) { +export function* bisectRight( + data: readonly O[], + initialState?: InitialState, +): Generator, BisectReturn> { let low = initialState?.low ?? 0 let high = initialState?.high ?? data.length let mid = (low + high) >>> 1 - while (true) { - const seeingBad = yield ({ + while (low + 1 < high) { + mid = (low + high) >>> 1 + + const seeingBad = yield { low, high, mid, slice: data.slice(mid, high), rouge: ~~Math.log2(high - low), - } as BisectNext) || false + } if (seeingBad) { low = mid } else { high = mid } - if (low + 1 < high) { - mid = (low + high) >>> 1 - } else { - return data[low] - } + } + + return { + low, + high, + mid, + slice: data.slice(low, mid), + rouge: ~~Math.log2(high - low), + target: data[low], } } diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts index 270e5e04d..797f88631 100644 --- a/src/core/utils/index.ts +++ b/src/core/utils/index.ts @@ -634,3 +634,11 @@ export const getRandomId = (length = 8) => { .join('') .substring(0, length) } + +/** + * 异步延时指定毫秒数 + * + * @param ms 传递给 setTimeout 的第二个参数,表示延时时间 + * @returns + */ +export const sleep = (ms?: number) => new Promise(resolve => setTimeout(resolve, ms))