前言

前几天,我和一位知乎网友讨论这个问题的时候,觉得这非常有意思,所以写了这篇文章作为记录
本文的思路和项目代码来源于知友@simon3000,我加以修饰以更符合理解的需求。
 
本文所用代码已经得到当事人授权,请看:
非常感谢他的理解和鼓励
 

作者初始代码地址

(进入项目页面,里面的original-version目录下就是作者的最初的代码)

通过JS文件和路径创建webworker带来的问题

Webworker,我其实一直觉得用法比较生硬,因为似乎需要创建额外的JS文件才能运行,就像下面这样
var worker =new Worker('work.js’)
 
这意味着,你需要额外创建一个js文件。这种方式让我觉得有些“古板”。因为JS操纵文件的能力很差,如果想要创建文件,当然方法也有,参考:https://github.com/eligrey/FileSaver.js/
 
但是问题在于,如果想要创建文件,JS的文件创建往往离不开下载!我原本只是想“悄无声息”地创建一个文件,但结果JS在创建的时候突然弹出一个下载框,这可让人受不了。啊,难受。(此处应有[我太难了]表情包)。
 
也就是,这时候的webWorker是“静态”的,是需要额外JS文件的,是受约束的。
 

四次转换,将一个普通函数强行变成WebWorker

但是 @simon3000 的建议让我眼前一亮!他告诉我,根据他使用webworker-loader(webpack技术栈)的经验,有一种连续转换的方式可以直接将一个普通函数变成WebWorker

 
这真是一个令人兴奋的信息。
 
试看看他的操作:
// 文件名为main.js
function work () {
onmessage = ({data: {message}}) => {
console.log ('i am worker, receive:' + message);
postMessage ({result: 'message from worker'});
};
} const runWorker = f => {
const worker = new Worker (
URL.createObjectURL (new Blob ([`(${f.toString ()})()`]))
); worker.onmessage = ({data: {result}}) => {
console.log ('i am main thread, receive:' + result);
}; worker.postMessage ({message: 'message from main thread'});
}; const testWorker = runWorker (work);
这段代码是我在他的代码基础上简化的
 
输出结果:
 

用Promise和闭包的方式去改造

我们再让它更通用一些,用Promise和闭包的方式去改造它,把runworker函数改造成一个makeworker函数
// 文件名为index.js
function work () {
onmessage = ({data: {jobId, message}}) => {
console.log ('i am worker, receive:-----' + message);
postMessage ({jobId, result: 'message from worker'});
};
} const makeWorker = f => {
let pendingJobs = {}; const worker = new Worker (
URL.createObjectURL (new Blob ([`(${f.toString ()})()`]))
); worker.onmessage = ({data: {result, jobId}}) => {
// 调用resolve,改变Promise状态
pendingJobs[jobId] (result);
// 删掉,防止key冲突
delete pendingJobs[jobId];
}; return (...message) =>
new Promise (resolve => {
const jobId = String (Math.random ());
pendingJobs[jobId] = resolve;
worker.postMessage ({jobId, message});
});
}; const testWorker = makeWorker (work); testWorker ('message from main thread').then (message => {
console.log ('i am main thread, i receive:-----' + message);
});
输出结果
 

总结

这次探讨告诉我们什么道理呢?
  • 第一,function.toString得到的并不是一个没有意义的字符串,它是完全可以被用来运行的
  • 第二,通过这种方式,webworker不需要借助额外的JS文件了,webworker完全动态化和自由化,你可以在主线程中创建任意个webworker!
  • 第三,我通过这次的交谈了解到一个道理,编程除了考量逻辑思维,信息差也是考量的一大因素。我之前也想过用webworker做这些事情,可是我不知道能用这样的四重转换呀!我也不知道function.toString得到的字符串居然是有作用的。信息差,也是会造成差距的。所以工程上也经验和前瞻也同样重要。

其他参考资料

前端黑魔法:webworker动态化,无需JS文件创建worker的更多相关文章

  1. 前端开发面试题收集 JS

    前端开发面试题收集-JS篇 收集经典的前端开发面试题 setTimeout的时间定义为0有什么用? javascript引擎是单线程处理任务的,它把任务放在队列中,不会同步执行,必须在完成一个任务后才 ...

  2. 前端迷思与React.js

    前端迷思与React.js 前端技术这几年蓬勃发展, 这是当时某几个项目需要做前端技术选型时, 相关资料整理, 部分评论引用自社区. 开始吧: 目前, Web 开发技术框架选型为两种的占 80% .这 ...

  3. 【前端芝士树】Vue.js面试题整理 / 知识点梳理

    [前端芝士树] Vue.js 面试题整理 MVVM是什么? MVVM 是 Model-View-ViewModel 的缩写. Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑. ...

  4. 前端开发之走进Vue.js

    Vue.js作为目前最热门最具前景的前端框架之一,其提供了一种帮助我们快速构建并开发前端项目的新的思维模式.本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程,并进一步理解如何通过Vue.j ...

  5. 前端开发必须知道的JS(二) 闭包及应用

    http://www.cnblogs.com/ljchow/archive/2010/07/06/1768749.html 在前端开发必须知道的JS(一) 原型和继承一文中说过下面写篇闭包,加之最近越 ...

  6. css-dialog样式实现弹框蒙层全屏无需JS计算高度兼容IE7

    <!DOCTYPE html><html><head>  <meta charset="UTF-8">  <title> ...

  7. 前端开发必须知道的JS之闭包及应用

    本文讲的是函数闭包,不涉及对象闭包(如用with实现).如果你觉得我说的有偏差,欢迎拍砖,欢迎指教. 在前端开发必须知道的JS之原型和继承一文中说过下面写篇闭包,加之最近越来越发现需要加强我的闭包应用 ...

  8. 为什么43%前端开发者想学Vue.js

    根据JavaScript 2017前端库状况调查 Vue.js是开发者最想学的前端库.我在这里说明一下我为什么认为这也是和你一起通过使用Vue构建一个简单的App应用程序的原因. 我最近曾与Evan ...

  9. 从cocos2d-html5中提取出来的,用做前端开发的框架——cc.js

    从cocos2d-html5中提取出来的,用做前端开发的框架——cc.js /************************************************************* ...

随机推荐

  1. 100天搞定机器学习|Day19-20 加州理工学院公开课:机器学习与数据挖掘

    前情回顾 机器学习100天|Day1数据预处理 100天搞定机器学习|Day2简单线性回归分析 100天搞定机器学习|Day3多元线性回归 100天搞定机器学习|Day4-6 逻辑回归 100天搞定机 ...

  2. windbg 使用与技巧

    基本知识和常用命令 (1)       Windbg下载地址http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx 安装完后执行w ...

  3. spring cloud 断路器 Hystrix

    一.微服务架构中使用断路器的原因 二.代码实现 1.在Ribbon中使用短路器 1.1.引入依赖 <dependency> <groupId>org.springframewo ...

  4. HBase的高可用(HA)

    在公司写文档时候查到的一些资料,感觉对自己很有帮助,现在整理如下: 介绍 HBase是一个高可靠性.高性能.列存储.可伸缩.实时读写的分布式数据库系统,基于列的存储模式适合于存储非结构化数据. 适用场 ...

  5. python接口测试入门1-什么是接口测试

    为什么要做接口测试 在日常开发过程中,有人做前端开发,有人负责后端开发.接口就是连接前后台,由于前端开发和后端开发的速度可能不一样,例如后端开发好了,但是前端没有开发.那么我们是不是就不需要测试呢?一 ...

  6. 查看centos中的用户和用户组和修改密码

    查看centos中的用户和用户组 1.用户列表文件: vim /etc/passwd/ 2.用户组列表文件: vim /etc/group 3.查看系统中有哪些用户: cut -d : -f /etc ...

  7. 【原创】关于DNS不得不说的一些事

    引言 今天我们来聊聊DNS. 所谓域名系统(Domain Name System缩写DNS,Domain Name被译为域名)是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据 ...

  8. 《Java 8 in Action》Chapter 2:通过行为参数化传递代码

    你将了解行为参数化,这是Java 8非常依赖的一种软件开发模式,也是引入 Lambda表达式的主要原因.行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式.一言以蔽之,它意味 着拿出一个代码 ...

  9. 枚举类&&注解&&反射

    什么是枚举类? 枚举类是优化定义固定对象的一种特殊的类. 换句话说,在需要类的实例为一个或者多个并且相对固定的时候,使用枚举类.(枚举类可扩展) 类的实例相对来说固定的有日期,客观不变的一些数字等等. ...

  10. Google Protocol Buffer Basics: C++

    proto文件简介 每个元素上的"= 1","= 2"标记标识该字段在二进制编码中使用的唯一"标记" 每个字段有三个可选修饰符 requir ...