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

  前言

  众所周知,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     如果还有文章集合,则返回true
                if(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标准参考教程

原文地址:https://www.cnblogs.com/huanzi-qch/p/10523912.html

时间: 2024-10-08 17:43:38

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

如何正确设置统计博客园的个人博客访问量(图文详解)

第一步: http://www.flagcounter.com/ 选择自己喜欢的显示风格后,点击"get your flag counter"按钮 第二步: 我这里,为了保持,我博客园所接收消息,也是采用本人的Q,一致.  当然,你也可以直接选择skip跳过 然后,会生成两组代码: 第三步: 这里我选择html格式的代码,复制后粘贴到博客园后台管理的公告栏即可: Code for websites (HTML): (推荐用这种) <a href="https://inf

博客园美化阅读模式

为了自己能更加好的查看自己的总结以及让关注我的小可爱们能更加好的学习我弄了阅读模式 一.直接上代码 放在页脚即可 <style> .read_book { background: url(https://images.cnblogs.com/cnblogs_com/pythonywy/1516412/o_greedread.png) } .not_read_book { background: url(https://images.cnblogs.com/cnblogs_com/pythony

history.js使用方法(来自博客园)

Ajax保留浏览器历史的解决方案 <ul class="menu"><li><a href="/home/index#page=1">page1</a></li><li><a href="/home/index#page=2">page2</a></li><li><a href="/home/index#page

【如何设置博客园好看的标题样式】

1.向博客园申请js权限 我们需要进入博客园自定义博客模板的页面,向博客园管理团队申请页面运行js的权限.[博客园]->[设置]->[博客设置],点击页面上的js权限申请,然后填写申请的理由,耐心等几分钟,再刷新一下,页面就会显示支持js代码 ,博客园也会在用户邮箱给你发送是否开通js权限的邮件. 2.添加css样式 我们在[管理]-->[设置]-->[博客设置]-->[页面定制CSS代码]中粘贴如下面的代码 #cnblogs_post_body { color: black

为你的博客园添加平滑移动到页面顶端的锚点和tag云

首先我的目录是在marvin的基础上二次开发的.然后我发现锚点图和目录都在同一个图上面,所以就一起用了. 返回顶部锚点: 我用以前旧版bilibili的那个函数.可以做到平滑滚动到页面,并且在触顶前不能向下滚屏.具体的看我参考链接.当然因为涉及到js要申请权限,简单的话a标签href用#top当然可以,体验有点差罢了. 然后因为我懒,锚点的出现条件直接和目录的出现条件弄在一起.也就是匹配元素相对滚动条顶部的偏移超过200时显示. tag云: 我用Google随便找的.用的矢量绘图. 但是这玩意有

Typora + Open Live Writer 管理博客园

Typora(markdown编辑+latex数学公式实时显现) OLW(文章离线管理编辑+标签合理分类+代码高亮) 详细操作如下 打包下载 链接:https://pan.baidu.com/s/1ZtzZxNxd5dcim_jNxv3bRA 密码:9nhb 代码高亮方面:(把css,js文件上传到博客园,在页首代码加几句话就OK) 网上教程都有,这里就说一点,OLW很多人的代码插件都加载不了的原因: 这样子 在这里加代码后,就自动代码高亮了 Typora生成.md文件自动上传图片方法: htt

如何设置博客园好看的标题样式

1.向博客园申请js权限 我们需要进入博客园自定义博客模板的页面,向博客园管理团队申请页面运行js的权限.[博客园]->[设置]->[博客设置],点击页面上的js权限申请,然后填写申请的理由,耐心等几分钟,再刷新一下,页面就会显示支持js代码 ,博客园也会在用户邮箱给你发送是否开通js权限的邮件. 2.添加css样式 我们在[管理]-->[设置]-->[博客设置]-->[页面定制CSS代码]中粘贴如下面的代码 #cnblogs_post_body { color: black

制作博客园目录导航

在博客园文章的上方制作一个导航窗口,方便浏览文章内容.点击按钮可以跳转到指定标题,还具备返回顶部功能. 1.向博客园申请JS权限 我们需要进入博客园自定义博客模板的页面,向博客园管理团队申请页面运行js的权限.[博客园]->[设置]->[博客设置],点击页面上的js权限申请,然后填写申请的理由,耐心等几分钟,再刷新一下,页面就会显示支持js代码 ,博客园也会在用户邮箱给你发送是否开通js权限的邮件. 2.添加JS脚本 复制粘贴下面代码到申请的JS权限区域: <script languag

你博客园文章中的图片可以放大吗?反正我的是可以放大了!

序 看看项目经理是如何实现的? 插件选择 试了几个插件,感觉还是 lightbox 插件好用,链接:https://github.com/lokesh/lightbox2,该插件具备如下几个特点: 点击图片后根据图片实际尺寸自动显示 图片有加载动画特效,有前.后.关闭按钮 想看详细介绍,可以查看:https://www.lokeshdhakar.com/projects/lightbox2/ 具体实现 通过上面的链接下载好后需要如下几个文件:lightbox.css.lightbox-plus-