UNPKG

@tencentcloud/call-uikit-vue

Version:

An Open-source Voice & Video Calling UI Component Based on Tencent Cloud Service.

163 lines (157 loc) 5.44 kB
/* eslint-disable */ import { isPlainObject, performanceNow, isFunction } from './common-utils'; import { NAME } from '../const/index'; /** * 定时器,功能: * 1. 支持定时执行回调 [1,n] 次,用于常规延迟、定时操作 * @example * // 默认嵌套执行,count=0 无限次 * timer.run(callback, {delay: 2000}); * // count=1 等同于 原始setTimeout * timer.run(callback, {delay: 2000, count:0}); * 2. 支持 RAF 执行回调,用于小流渲染,audio音量获取等任务,需要渲染频率稳定,支持页面退后台后,用 setTimeout 接管,最短 1s 执行一次 * @example * // 默认60fps,可以根据单位时长换算,默认开启后台执行 * timer.run('raf', callback, {fps: 60}); * // 设置执行次数 * timer.run('raf', callback, {fps: 60, count: 300, backgroundTask: false}); * 3. 支持空闲任务执行回调, requestIdleCallback 在帧渲染的空闲时间执行任务,可以用于 storage 写入等低优先级的任务 * @example * // 支持原生setInterval 但不推荐使用,定时任务推荐用 timeout * timer.run('interval', callback, {delay:2000, count:10}) */ class Timer { static taskMap = new Map(); static currentTaskID = 1; static generateTaskID() { return this.currentTaskID++; } /** * * @param {string} taskName 'interval' 'timeout' * @param {function} callback * @param {object} options include: * @param {number} options.delay millisecond * @param {number} options.count 定时器回调执行次数,0 无限次 or n次 * @param {boolean} options.backgroundTask 在页面静默后是否继续执行定时器 */ static run(taskName = NAME.TIMEOUT, callback: any, options: any) { // default options if (taskName === NAME.INTERVAL) { options = { ...{ delay: 2000, count: 0, backgroundTask: true }, ...options }; } else { options = { ...{ delay: 2000, count: 0, backgroundTask: true }, ...options }; } // call run(function, {...}) if (isPlainObject(callback)) { options = { ...options, ...callback }; } if (isFunction(taskName)) { callback = taskName; taskName = NAME.TIMEOUT; } // 1. 创建 taskID,作为 timer task 的唯一标识,在本函数执行完后返回,用于在调用的地方实现互斥逻辑 // 2. 根据 taskName 执行相应的函数 const taskItem = { taskID: this.generateTaskID(), loopCount: 0, intervalID: null, timeoutID: null, taskName, callback, ...options }; this.taskMap.set(taskItem.taskID, taskItem); // console.log(`timer run task:${taskItem.taskName}, task queue size: ${this.taskMap.size}`); if (taskName === NAME.INTERNAL) { this.interval(taskItem); } else { this.timeout(taskItem); } return taskItem.taskID; } /** * 定时循环执行回调函数 * 可以指定循环的时间间隔 * 可以指定循环次数 * @param {object} taskItem * @param {function} callback * @param {*} delay * @param {*} count * @returns ID */ static interval(taskItem: any) { // setInterval 缺点,浏览器退后台会降频,循环执行间隔时间不可靠 // 创建进入定时器循环的任务函数,函数内:1. 判断是否满足执行条件,2.执行 callback // 通过 setInterval 执行任务函数 // 将 intervalID 记录到 taskMap 对应的 item const task = () => { taskItem.callback(); taskItem.loopCount += 1; if (this.isBreakLoop(taskItem)) { return; } }; return taskItem.intervalID = setInterval(task, taskItem.delay); } /** * 延迟执行回调 * count = 0,循环 * count = n, 执行n次 * @param {object} taskItem * */ static timeout(taskItem: any) { // setTimeout 浏览器退后台,延迟变为至少1s const task: any = () => { // 执行回调 taskItem.callback(); taskItem.loopCount += 1; if (this.isBreakLoop(taskItem)) { return; } // 不修正延迟,每次callback间隔平均 return taskItem.timeoutID = setTimeout(task, taskItem.delay); }; return taskItem.timeoutID = setTimeout(task, taskItem.delay); } static hasTask(taskID: any) { return this.taskMap.has(taskID); } static clearTask(taskID: any) { // console.log('timer clearTask start', `| taskID:${taskID} | size:${this.taskMap.size}`); if (!this.taskMap.has(taskID)) { return true; } const { intervalID, timeoutID, onVisibilitychange } = this.taskMap.get(taskID); if (intervalID) { clearInterval(intervalID); } if (timeoutID) { clearTimeout(timeoutID); } if (onVisibilitychange) { document.removeEventListener('visibilitychange', onVisibilitychange); } this.taskMap.delete(taskID); // console.log('timer clearTask end ', `| size:${this.taskMap.size}`); return true; } /** * 1. 如果已移除出定时队列,退出当前任务 * 2. 如果当前任务已满足次数限制,则退出当前任务 * @param {object} taskItem * @returns */ static isBreakLoop(taskItem: any) { if (!this.taskMap.has(taskItem.taskID)) { return true; } if (taskItem.count !== 0 && taskItem.loopCount >= taskItem.count) { this.clearTask(taskItem.taskID); return true; } return false; } } export default Timer;