前言

  众所周知,js是单线程的,从上往下,从左往右依次执行,当我们有耗时的任务需要处理时,便会阻塞线程造成页面卡顿等问题。web worker的目的,就是为JavaScript创造多线程环境,允许主线程将一些任务分配给子线程。在主线程运行的同时,子线程在后台运行,两者互不干扰。等到子线程完成计算任务,再把结果返回给主线程。因此,每一个子线程就好像一个“工人”(worker),默默地完成自己的工作。更多worker的介绍请戳:JavaScript标准参考教程

  本文通过web worker 统计博客园总阅读量,来学习一下worker的使用,前段时间想看一下自己的博客有多少的阅读量,发现博客园好像没有提供这个统计功能,刚好之前有了解到worker,js的多线程,刚好适用于去统计总阅读量,又不影响我页面的渲染,主线程渲染页面,子线程负责循环请求博客园随笔列表进行统计,统计好了再将数据发送到主线程。详细思路如下:

  主线程

  1、先追加一个带id=‘statistical’的span标签,并显示“统计中...”

  2、开启worker子线程开始统计,并且开始监听onmessage事件等待子线程返回数据

  3、onmessage收到子线程返回的数据,更新id=‘statistical’的span标签的text值

  子线程

  1、循环使用XMLHttpRequest对象请求博客园随笔列表,直到最后一页(直到返回的页面没有文章数据)

  2、使用正则处理、匹配数据(每篇文章的阅读量)存入全局变量中,并且判断是否最后一页,以便跳出循环

  3、将收集到的数据进行数据清洗、相加得到总阅读量

  4、将总阅读量推送给主线程,并结束子线程

  代码编写

  在开始写主线程之前,我们先实现子线程的任务

  子线程

  根据博客园目前的链接规则,访问个人博客主页的地址如下:http://www.cnblogs.com/huanzi-qch/,分页查看随笔列表的地址如下:https://www.cnblogs.com/huanzi-qch/default.html?page=1,并根据响应回来的页面内容格式用正则 /huanzi-qch\s+阅读[(]+[1-9]\d+[)]/g 去匹配,当然也可以用 /阅读[(]+[1-9]\d+[)]/g

  我们对子线程进行如下封装,name值在主线程new Worker的时候构造:

    console.log("我是worker 任务线程 负责统计总阅读量..");//我的博客园地址名称var myCnblogsName = this.name;//监听主线程发送过来的数据//this.addEventListener('message', function (e) {//  this.postMessage('主线程发送过来的数据: ' + e.data);//}, false);//监听发送报错//this.addEventListener('messageerror ', function (e) {//  this.postMessage('发送数据到主线程报错: ' + e.data);//}, false);//加载其他 JS 脚本。//this.importScripts("")://任务线程内部的全局变量数组,用于保存数据var statisticsArray = [];//发送ajax请求博客园function getReadData(page){//是否还要继续var flag = false;//使用XMLHttpRequest对象请求博客园 var xhr = new XMLHttpRequest();            xhr.open('GET', "https://www.cnblogs.com/"+myCnblogsName+"/default.html?page=" + page, false);//同步xhr.setRequestHeader("Content-Type", "text/html; charset=utf-8"); //设置响应格式xhr.onreadystatechange = function() {// readyState == 4说明请求已完成if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { //使用正则处理HTML字符串,需要设置全局标识//var myRe = /huanzi-qch\s+阅读[(]+[1-9]\d+[)]/g;var myRe = /阅读[(]+[1-9]\d+[)]/g;var resultArray = xhr.responseText.match(myRe);//合并到全局变量数组中statisticsArray = statisticsArray.concat(resultArray);//判断这个即可:resultArray.length > 0     如果还有文章集合,则返回trueif(resultArray && resultArray.length > 0){flag = true;}}};xhr.send();return flag;}//循环调用getReadData,默认最大页数 100 (100页,每页10条记录,相对于1000篇博客,已经够多了吧?)for(var i = 1;i < 100;i++){//如果返回false则立即跳出循环if(!getReadData(i)){ break;}}//处理全局数组for(var i = 0;i < statisticsArray.length;i++){if(statisticsArray[i]){//只保留数字部分statisticsArray[i] = statisticsArray[i].match(/[1-9]\d+/)[0];}else{statisticsArray.splice(i, 1);}}
//数组求和,需要返回主线程的最终值//向产生这个 Worker 线程发送消息。var count = eval(statisticsArray.join("+"));this.postMessage(count);console.log("统计结束,总阅读量为:"+count);//关闭 Worker 线程this.close();

  主线程

  刚开始我是想将子线程单独放在一个js文件里,上传到博客园后台管理的文件里,然后引入创建worker对象,不成想博客园门户地址跟保存用户上传文件的地址不同源,而worker受同源限制,导致无法创建对象

  只能将子线程的代码放在同一个页面了,通过<script id="worker" type="app/worker"></script>包起来,通过读取这个script的内容成Blob二进制对象,然后二进制对象转为URL,再通过这个URL创建worker。

  最后代码如下:

        // 先追加一个显示标签$("#profile_block").append("总阅读量:<span id='statistical' style='color: #464646;'>统计中...</span><br/>");//创建一个Blob,读取同个页面中的script标签var blob = new Blob([document.querySelector('#worker').textContent]);//这里需要把代码当作二进制对象读取,所以使用Blob接口。然后,这个二进制对象转为URL,再通过这个URL创建worker。var url = window.URL.createObjectURL(blob);//创建worker对象var worker = new Worker(url ,{ name : 'huanzi-qch'});//监听任务线程返回的数据worker.onmessage = function (event) {//设置总阅读量$("#statistical").text(event.data);}//error 事件的监听函数。worker.onerror = function (event) {console.log('error:' + event);}//messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。worker.onmessageerror = function (event) {console.log('messageerror:' + event);}//发送数据到任务线程//worker.postMessage('Hello World');

  效果演示

  将所有代码都添加到 博客侧边栏公告 并保存

  小扩展:既然添加了总阅读量,不如把积分、排名也放一起显示吧!

  先前往 博客设置 --> 选项 勾选上“积分与排名”,然后加入以下js代码

        //隐藏博客园提供的积分与排名标签,并将内容迁移到指定位置$("#sidebar_scorerank").hide();$("#profile_block").append("积分:<span style='color: #464646;'>"+$("#sidebar_scorerank").find(".liScore").text().match(/[1-9]\d+/)[0]+"</span><br/>");$("#profile_block").append("排名:<span style='color: #464646;'>"+$("#sidebar_scorerank").find(".liRank").text().match(/[1-9]\d+/)[0]+"</span><br/>");

        

  总结

  通过这个小例子,我们以后看自己的博客情况也更加方便了,访问有侧边公告栏的页面都会统计总阅读量(不过这样会无形增加博客园服务器的压力 <手动羞涩脸>),并且也充分的感受到了worker的威力,之前js受限于单线程模型,无法充分发挥js的潜力,现在有了worker多线程,我们可以解锁更多姿势了!

  更多对worker的介绍请戳:JavaScript标准参考教程。

  统计任意博客总阅读量

  我们直接用子线程的代码去统计别人的博客的总阅读量,不需要大幅度改动,直接将myCnblogsName的值改成对应的博客地址名称,我们进行简单封装成一个function,然后跑去博客主页打开F12在控制台运行代码然后调用function即可,简单方便,即开即用

/**输入别人的博客园地址名称
*/
function statistical(myCnblogsName){console.log("我是worker 任务线程 正在统计 "+myCnblogsName+" 的博客的总阅读量..");//任务线程内部的全局变量数组,用于保存数据var statisticsArray = [];//发送ajax请求博客园function getReadData(page){//是否还要继续var flag = false;//使用XMLHttpRequest对象请求博客园var xhr = new XMLHttpRequest();            xhr.open('GET', "https://www.cnblogs.com/"+myCnblogsName+"/default.html?page=" + page, false);//同步xhr.setRequestHeader("Content-Type", "text/html; charset=utf-8"); //设置响应格式xhr.onreadystatechange = function() {// readyState == 4说明请求已完成if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { //使用正则处理HTML字符串,需要设置全局标识//var myRe = /huanzi-qch\s+阅读[(]+[1-9]\d+[)]/g;var myRe = /阅读[(]+[1-9]\d+[)]/g;var resultArray = xhr.responseText.match(myRe);//合并到全局变量数组中statisticsArray = statisticsArray.concat(resultArray);//判断这个即可:resultArray.length > 0     如果还有文章集合,则返回trueif(resultArray && resultArray.length > 0){flag = true;}}};xhr.send();return flag;}//循环调用getReadData,默认最大页数 100 (100页,每页10条记录,相对于1000篇博客,已经够多了吧?)for(var i = 1;i < 100;i++){//如果返回false则立即跳出循环if(!getReadData(i)){ break;}}//处理全局数组for(var i = 0;i < statisticsArray.length;i++){if(statisticsArray[i]){//只保留数字部分statisticsArray[i] = statisticsArray[i].match(/[1-9]\d+/)[0];}else{statisticsArray.splice(i, 1);}}//数组求和,需要返回主线程的最终值var count = eval(statisticsArray.join("+"));console.log("统计结束,总阅读量为:"+count);
}

  我们去统计一下推荐博客排行榜中的部分大佬看一看他们的总阅读量是多少

  看了一下他们的随笔数量,一个是六百多,一个是一百多,我们定义的循环次数100是够用的,其实改成for(;;)也没有问题,因为我们已经设置了break的条件

    

  然后去他们的博客主页打开控制台,运行代码,然后调用statistical方法

    

  不愧是大佬啊,总阅读量一个是七百万,一个是三百万

  

转载于:https://www.cnblogs.com/huanzi-qch/p/10523912.html

Web Worker——js的多线程,实现统计博客园总阅读量相关推荐

  1. java实现阅读量统计_博客中的阅读量是如何设计的?

    在博客园中,一篇博客的底部,通常有该篇博客的阅读量的统计.当浏览器端没发起一个请求的时候,它通过相应的逻辑判断,如果符合要求,则给阅读量加一.所以,有了如下代码: package test; impo ...

  2. 如何统计博客园的个人博客访问量

    使用过新浪博客的人都知道,新浪博客的首页有访问量统计功能,迁移到博客园之后发现博客园却没有这项功能,所幸博客园在后台管理的设置选项中有一个公告栏和设置页首页脚代码功能,使用起来非常灵活和方便.借此我们 ...

  3. 10000个怎么用js写 创建li_给博客园加一个会动的小人-spig.js

    给博客园加一个会动的小人-spig.js 效果大概是这样,感觉十分可爱qvq 那么怎么添加呢? 首先需要开通js/html权限. 然后在页脚html代码中加入以下代码 -- var isindex=t ...

  4. java如何统计文章阅读量_博客中的阅读量是如何设计的?

    在博客园中,一篇博客的底部,通常有该篇博客的阅读量的统计.当浏览器端没发起一个请求的时候,它通过相应的逻辑判断,如果符合要求,则给阅读量加一.所以,有了如下代码: package test; impo ...

  5. 真正阅读量php,科学网—博客70万阅读量与研究网8万点击量感言 - 陈安的博文

    ??前天,我的题为"崇尚智慧和人生改变的人请来这里"天涯博客(http://change1970.tianyablog.com)超过了70万的阅读量,这个博客现在有点沦为科学网博客 ...

  6. C++统计博客园写过的代码行数

    一.获得数据 1.备份到XML 2.改为txt 2.进行统计 #include<iostream> #include<string> using namespace std; ...

  7. JS事件大全 - semye-静心 - 博客园

    本文转自 http://www.cnblogs.com/semye/archive/2007/04/16/706957.html  js事件列表 一般事件 事件 浏览器支持 描述 onClick IE ...

  8. 博客园HTML源码运行特制js(原创自Zjmainstay)

    canrun 测试运行HTML <html> <head><title>测试博客园HTML源码运行程序</title><meta http-equ ...

  9. 【开源】博客园文章编辑器4.0版发布

    源起 最近个人时间多起来了: 于是打算持续写一点东西: 前面写了两篇关于riot.js的东西: 被博客园的领导移出首页了: 原因之一是排版不整齐: 确实是不整齐,这我认, 然而,我自己可是博客园文章编 ...

  10. java代码画樱花飘落_一行代码引入博客园樱花飘落特效

    前言 博客园作为面向大众的博客, 个性新颖可以博得一赞, 简约美观也不失阅读体验, 本文对樱花特效js进行了解读, 发现作者的设计确实秒不可言, 即使没有注释, 思路展示的也很清晰. 那就废话不多说, ...

最新文章

  1. C++11 unordered_map详细介绍
  2. 秉承着一位代码艺术家的分享精神
  3. Docker Review - docker 容器 常用命令
  4. TFS 2008 中文版下载及安装完整图解
  5. php’s fopen() 函数
  6. Python基础(三)文件操作和处理json
  7. 高可用—Keepalived安装部署使用详解
  8. HttpClient官方sample代码的深入分析(连接池)
  9. 任务型对话(一)—— NLU/SLU(意识识别和槽值填充)
  10. eureka动态扩容_SpringCloud- 第二篇 Eureka快速上手
  11. Ubuntu18系统安装使用Nginx
  12. JavaScript的注意事项
  13. shiro权限控制登陆成功页面跳转问题
  14. java 余弦定理_Java根据余弦定理计算文本相似度
  15. Microsoft Visual Studio 注册码
  16. 错误解决:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255]
  17. C++のeasyx3:函数clearcliprgn、cleardevice、closegraph、getaspectratio、graphdefaults的运用
  18. codeforces1166E. The LCMs Must be Large
  19. 孙溟㠭篆刻艺术——《真金》
  20. elasticsearch做如何进行日志采集

热门文章

  1. 1.2执行更高级的线程任务(Performing More Advanced Thread Tasks)
  2. 电子相册系统(一)Dao的组件设计
  3. 【渝粤教育】国家开放大学2018年春季 0043-21T计算机文化 参考试题
  4. 【ICLR 2018】模型集成的TRPO算法【附代码】
  5. /etc/resolv.conf
  6. Mavan学习之pom聚合
  7. FHQ Treap摘要
  8. 使用charles抓取https的方法
  9. 查看svn的版本(转载)
  10. 大学四年计算机也许应该这样学。。。