沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 必看导言

    • 就业的核心问题

      • 课件
    • 表现力的训练

      • 课件
  • 简历制作

    • 课件
    • 简历准备课堂笔记
    • 个人信息课堂笔记
    • 求职意向课堂笔记
    • 技术栈课堂笔记
    • 教育经历课堂笔记
    • 个人优势与评价课堂笔记
    • 工作经历课堂笔记
    • 项目
    • 项目亮难点问题

    • 项目经历

  • 项目准备

    • 课件
    • 课件
  • 技术重点

    • 划重点

    • 非技术环节
  • 简历投递和面试准备

    • 简历投递
    • 面试准备
  • 笔面试环节知识讲解
  • 项目准备
  • 难点攻关
  • 计时器节流问题
luzhichang
2024-09-18
目录

14-技术讲解

# 计时器节流问题

# 技术讲解

# 什么问题

有时候会有这样的需求,比如,在一些有编辑需求的应用中,如果长时间不对页面进行编辑,就自动帮你退出编辑状态。

咋一看感觉挺简单,用setinterval不就行了?但是还有要求是,必须保证在当前页面失活的时候,定时器是正常的。

这样的需求有什么问题?

# 解决思路

首先要知道,直接使用计时器会有什么问题?这是因为浏览器认为setTimeout() / setInterval()如果当前页面失活了,继续按照之前的方案去执行,可能会消耗大量资源。在后台选项卡中以极短间隔运行回调的应用程序可能会消耗大量内存,以至于当前活动选项卡的运行可能会受到影响。在最坏的情况下,浏览器可能会崩溃,或者设备的电池会迅速耗尽。

在这种情况下,对后台选项卡中运行的计时器施加一些限制是有意义的。

所以,对于有些浏览器来说,比如Chrome (opens new window),对于非活动选项卡,它们会自动限制计时器每 1 秒运行一次,而不管代码中指定的原始延迟是多少。例如,如果代码最初使用setInterval()每 50 毫秒运行一次某些代码,一旦应用程序移至后台选项卡,间隔就会自动变为 1000 毫秒(1 秒),随着时间的推移,时间差距也会慢慢拉大。 然而,一旦重新激活选项卡,原始间隔或延迟就会返回到原始值。

下面是一个简单的setInterval计时,一秒打印一次,切换页签一段时间之后,可以很明显的看出时间间隔甚至出现了一分钟一次

let sum = 0;
setInterval(() => {
  sum += 1;
  console.log("--->" + new Date() + sum);
}, 1000);

image-20240629222110027

如果我们只是想在页面失活的时候暂停计时器,那比较简单,我们可以使用 Page Visibility API 来查找用户是否离开了标签页,或者是否再次返回了标签页

document.addEventListener('visibilitychange', function() {
    if(document.hidden) { // 或者document.visibilityState === 'hidden'
        // 当前标签页失活了
    }
    else { // 或者document.visibilityState === 'visible'
        // 当前标签页激活了
    }
});

但是,我们的要求是,如果当前页签失活了,还是希望失活的页面继续精确的计时,而不是简单的暂停了事。

思考了一下觉得可以在切换页面的时候新建一个线程来准确的计时。

要在页面使用线程,那就只有用 web worker 了,用它单纯来进行计时,不用管其他逻辑,切换页面也不会有误差或者终止。

# 解决细节

1、 Web Worker (opens new window)

Web Worker 是 HTML5 标准的一部分,这一规范定义了一套 API,允许我们在 js 主线程之外开辟新的 Worker 线程,并将一段 js 脚本运行其中,它赋予了开发者利用 js 操作多线程的能力。

因为是独立的线程,Worker 线程与 js 主线程能够同时运行,互不阻塞。所以,在我们有大量运算任务时,可以把运算任务交给 Worker 线程去处理,当 Worker 线程计算完成,再把结果返回给 js 主线程。这样,js 主线程只用专注处理业务逻辑,不用耗费过多时间去处理大量复杂计算,从而减少了阻塞时间,也提高了运行效率,页面流畅度和用户体验自然而然也提高了。

虽然 Worker 线程是在浏览器环境中被唤起,但是它与当前页面窗口运行在不同的全局上下文中,我们常用的顶层对象 window,以及 parent 对象在 Worker 线程上下文中是不可用的。另外,在 Worker 线程上下文中,操作 DOM 的行为也是不可行的,document对象也不存在。但是,location和navigator对象可以以可读方式访问

基本使用:

main.js(主线程)

const myWorker = new Worker('/worker.js'); // 创建worker

myWorker.addEventListener('message', e => { // 接收消息
    console.log(e.data); // Hello from Worker.js,worker线程发送的消息
});

// 这种写法也可以
// myWorker.onmessage = e => { // 接收消息
//    console.log(e.data);
// };

myWorker.postMessage('Hello from Main.js'); // 向 worker 线程发送消息,对应 worker 线程中的 e.data

worker.js(worker线程)

self.addEventListener('message', e => { // 接收到消息
    console.log(e.data); // Hello from Main.js,接收主线程发送的消息
    self.postMessage('Hello from Worker.js'); // 向主线程发送消息
});

WebWork子线程处理计时器

App.vue(主线程)

<template>
  <div id="app">
    <h1>这是编辑页面</h1>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      sum: 0
    };
  },
  mounted() {
    this.myWorker = new Worker("/worker.js");
    this.myWorker.postMessage("start");
    this.myWorker.addEventListener("message", (e) => {
      console.log(e.data);
      this.sum = e.data.sum;
      if (this.sum >= 10) { // 10秒后失效
        console.log("页面失效");
        this.myWorker.postMessage("end");
      }
    });
  },
};
</script>

WebWork(子线程)

let timer;
self.addEventListener("message", (e) => {
  // 接收到消息
  console.log(e.data); // 主线程发送的消息
  let sum = 0;
  let msg;

  if (e.data === "start") {
    console.log("--->重新开始计时");
    timer = setInterval(() => { // WebWork子线程计时
      sum += 1;
      msg = {
        text: "编辑中",
        sum,
      };
      self.postMessage(msg); // 向主线程发送消息 msg 对象
    }, 1000);
  } else {
    console.log("===>关闭计时");
    clearInterval(timer);
  }
});

image-20240701115632830

2、心跳检测

在编辑页面,为了保证不出现多人同时编辑的状态,同一时间只能有一个人编辑,和后端配合,每分钟向后端发送简单的通讯包(当然由谁主动发送都可以,可以是客户端,也可以是服务器端,客户端主动发送稍微简单一些),后端就会帮你保持正在编辑的状态,这种对时间精准性要求不是那么严格,收到一个心跳后,可以简单设置连接标志,比如{edit:true},如果别人想要编辑,就会拒绝别人的编辑。如果你一分钟后没发送这个心态检测,后端会把 true 改成 false,这时别人想要编辑,后端就会接受别人的编辑了

3、切换标签页

document.addEventListener("visibilitychange", function () {
  if (document.visibilityState == "visible") {
    console.log("visible")
  } else if  (document.visibilityState == "hidden") {
    console.log("hidden")
  }
});

4、避免浏览器节流的通用处理

其实我们的最终目的是希望浏览器在当前页签失活的时候,不要做节流处理,但是如果有多个页面都要处理这种情况,极大的增加了心智负担。无非我们就是希望WebWorker线程单独来处理setInterval/setTimeout计时器,如果我们能单独抽离出来,那在代码中就和原来使用setInterval/setTimeout是一个道理了。

5、window.URL.createObjectURL(blob) (opens new window)

通过window.URL.createObjectURL(blob)动态生成WebWorker的脚本

if (!/MSIE 10/i.test(navigator.userAgent)) {
    try {
      var blob = new Blob([
        "\
var fakeIdToId = {};\
onmessage = function (event) {\
	var data = event.data,\
		name = data.name,\
		fakeId = data.fakeId,\
		time;\
	if(data.hasOwnProperty('time')) {\
		time = data.time;\
	}\
	switch (name) {\
		case 'setInterval':\
			fakeIdToId[fakeId] = setInterval(function () {\
				postMessage({fakeId: fakeId});\
			}, time);\
			break;\
		case 'clearInterval':\
			if (fakeIdToId.hasOwnProperty (fakeId)) {\
				clearInterval(fakeIdToId[fakeId]);\
				delete fakeIdToId[fakeId];\
			}\
			break;\
		case 'setTimeout':\
			fakeIdToId[fakeId] = setTimeout(function () {\
				postMessage({fakeId: fakeId});\
				if (fakeIdToId.hasOwnProperty (fakeId)) {\
					delete fakeIdToId[fakeId];\
				}\
			}, time);\
			break;\
		case 'clearTimeout':\
			if (fakeIdToId.hasOwnProperty (fakeId)) {\
				clearTimeout(fakeIdToId[fakeId]);\
				delete fakeIdToId[fakeId];\
			}\
			break;\
	}\
}\
",
      ]);
      workerScript = window.URL.createObjectURL(blob);
    } catch (error) {
    }
  }

6、拦截(模拟)settimeout、setInterval

在主线程模拟setTimeout与setInterval,其实就是覆盖原有的相关方法,改成worker.postMessage

伪代码:

var worker,
  fakeIdToCallback = {}, // 用于记录setInterval回调函数的对象
  lastFakeId = 0,
  maxFakeId = 0x7FFFFFFF // // 是一个十六进制值,转换为十进制时是 2147483647。这个值是 32 位有符号整数的最大值,这个值可以表示为 2^31-1

function getFakeId() {
  // 确保生成的fakeid 在 fakeIdToCallback 中是唯一的
  do {
    if (lastFakeId == maxFakeId) { // 如果已经是最大值,设置为0
      lastFakeId = 0;
    } else {
      lastFakeId++;
    }
  } while (fakeIdToCallback.hasOwnProperty(lastFakeId));
  return lastFakeId;
}

worker = new Worker (workerScript);
// 模拟setInterval
window.setInterval = function (callback, time /* , parameters */) {
  var fakeId = getFakeId(); // 生成随机id,并且确保不和fakeIdToCallback已存在的id属性冲突
  fakeIdToCallback[fakeId] = {
    callback: callback,
    parameters: Array.prototype.slice.call(arguments, 2),
  };
  worker.postMessage({
    name: "setInterval",
    fakeId: fakeId,
    time: time,
  });
  return fakeId;
};

// 模拟clearInterval
window.clearInterval = function (fakeId) {
  if (fakeIdToCallback.hasOwnProperty(fakeId)) {
    delete fakeIdToCallback[fakeId];
    worker.postMessage({
      name: "clearInterval",
      fakeId: fakeId,
    });
  }
};

7、在WebWorker线程中监听主线程发送的信息,并执行对应的计时器

var fakeIdToId = {};
onmessage = function (event) {
  var data = event.data,
    name = data.name,
    fakeId = data.fakeId,
    time;
  if (data.hasOwnProperty("time")) {
    time = data.time;
  }
  switch (name) {
    case "setInterval":
      fakeIdToId[fakeId] = setInterval(function () {
        postMessage({ fakeId: fakeId });
      }, time);
      break;
    case "clearInterval":
      if (fakeIdToId.hasOwnProperty(fakeId)) {
        clearInterval(fakeIdToId[fakeId]);
        delete fakeIdToId[fakeId];
      }
      break;
  }
};

8、主线程监听消息,并做出对应处理

worker.onmessage = function (event) {
  var data = event.data,
    fakeId = data.fakeId,
    request,
    parameters,
    callback;
  if (fakeIdToCallback.hasOwnProperty(fakeId)) {
    request = fakeIdToCallback[fakeId];
    callback = request.callback;
    parameters = request.parameters;
    if (request.hasOwnProperty('isTimeout') && request.isTimeout) {
      delete fakeIdToCallback[fakeId];
    }
  }
}

执行流程

image-20240701133603099

# 浏览器节流的通用处理全代码:

HackTimer.js

(function (workerScript) {
	if (!/MSIE 10/i.test (navigator.userAgent)) {
		try {
			var blob = new Blob (["\
var fakeIdToId = {};\
onmessage = function (event) {\
	var data = event.data,\
		name = data.name,\
		fakeId = data.fakeId,\
		time;\
	if(data.hasOwnProperty('time')) {\
		time = data.time;\
	}\
	switch (name) {\
		case 'setInterval':\
			fakeIdToId[fakeId] = setInterval(function () {\
				postMessage({fakeId: fakeId});\
			}, time);\
			break;\
		case 'clearInterval':\
			if (fakeIdToId.hasOwnProperty (fakeId)) {\
				clearInterval(fakeIdToId[fakeId]);\
				delete fakeIdToId[fakeId];\
			}\
			break;\
		case 'setTimeout':\
			fakeIdToId[fakeId] = setTimeout(function () {\
				postMessage({fakeId: fakeId});\
				if (fakeIdToId.hasOwnProperty (fakeId)) {\
					delete fakeIdToId[fakeId];\
				}\
			}, time);\
			break;\
		case 'clearTimeout':\
			if (fakeIdToId.hasOwnProperty (fakeId)) {\
				clearTimeout(fakeIdToId[fakeId]);\
				delete fakeIdToId[fakeId];\
			}\
			break;\
	}\
}\
"]);
			// Obtain a blob URL reference to our worker 'file'.
			workerScript = window.URL.createObjectURL(blob);
		} catch (error) {
			/* Blob is not supported, use external script instead */
		}
	}
	var worker,
		fakeIdToCallback = {},
		lastFakeId = 0,
		maxFakeId = 0x7FFFFFFF, // 2 ^ 31 - 1, 31 bit, positive values of signed 32 bit integer
		logPrefix = 'HackTimer.js by turuslan: ';
	if (typeof (Worker) !== 'undefined') {
		function getFakeId () {
			do {
				if (lastFakeId == maxFakeId) {
					lastFakeId = 0;
				} else {
					lastFakeId ++;
				}
			} while (fakeIdToCallback.hasOwnProperty (lastFakeId));
			return lastFakeId;
		}
		try {
			worker = new Worker (workerScript);
			window.setInterval = function (callback, time /* , parameters */) {
				var fakeId = getFakeId ();
				fakeIdToCallback[fakeId] = {
					callback: callback,
					parameters: Array.prototype.slice.call(arguments, 2)
				};
				worker.postMessage ({
					name: 'setInterval',
					fakeId: fakeId,
					time: time
				});
				return fakeId;
			};
			window.clearInterval = function (fakeId) {
				if (fakeIdToCallback.hasOwnProperty(fakeId)) {
					delete fakeIdToCallback[fakeId];
					worker.postMessage ({
						name: 'clearInterval',
						fakeId: fakeId
					});
				}
			};
			window.setTimeout = function (callback, time /* , parameters */) {
				var fakeId = getFakeId ();
				fakeIdToCallback[fakeId] = {
					callback: callback,
					parameters: Array.prototype.slice.call(arguments, 2),
					isTimeout: true
				};
				worker.postMessage ({
					name: 'setTimeout',
					fakeId: fakeId,
					time: time
				});
				return fakeId;
			};
			window.clearTimeout = function (fakeId) {
				if (fakeIdToCallback.hasOwnProperty(fakeId)) {
					delete fakeIdToCallback[fakeId];
					worker.postMessage ({
						name: 'clearTimeout',
						fakeId: fakeId
					});
				}
			};
			worker.onmessage = function (event) {
				var data = event.data,
					fakeId = data.fakeId,
					request,
					parameters,
					callback;
				if (fakeIdToCallback.hasOwnProperty(fakeId)) {
					request = fakeIdToCallback[fakeId];
					callback = request.callback;
					parameters = request.parameters;
					if (request.hasOwnProperty ('isTimeout') && request.isTimeout) {
						delete fakeIdToCallback[fakeId];
					}
				}
				if (typeof (callback) === 'string') {
					try {
						callback = new Function (callback);
					} catch (error) {
						console.log (logPrefix + 'Error parsing callback code string: ', error);
					}
				}
				if (typeof (callback) === 'function') {
					callback.apply (window, parameters);
				}
			};
			worker.onerror = function (event) {
				console.log (event);
			};
		} catch (error) {
			console.log (logPrefix + 'Initialisation failed');
			console.error (error);
		}
	} else {
		console.log (logPrefix + 'Initialisation failed - HTML5 Web Worker is not supported');
	}
}) ('HackTimerWorker.js');

HackTimerWorker.js

var fakeIdToId = {};
onmessage = function (event) {
	var data = event.data,
		name = data.name,
		fakeId = data.fakeId,
		time;
	if(data.hasOwnProperty('time')) {
		time = data.time;
	}
	switch (name) {
		case 'setInterval':
			fakeIdToId[fakeId] = setInterval(function () {
				postMessage({fakeId: fakeId});
			}, time);
			break;
		case 'clearInterval':
			if (fakeIdToId.hasOwnProperty (fakeId)) {
				clearInterval(fakeIdToId[fakeId]);
				delete fakeIdToId[fakeId];
			}
			break;
		case 'setTimeout':
			fakeIdToId[fakeId] = setTimeout(function () {
				postMessage({fakeId: fakeId});
				if (fakeIdToId.hasOwnProperty (fakeId)) {
					delete fakeIdToId[fakeId];
				}
			}, time);
			break;
		case 'clearTimeout':
			if (fakeIdToId.hasOwnProperty (fakeId)) {
				clearTimeout(fakeIdToId[fakeId]);
				delete fakeIdToId[fakeId];
			}
			break;
	}
}
Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式