node js 多线程

一、前提

我以前只认为node js 只能单线程,我自己用了一段时间electron 桌面开发,如果遇到CPU密集型业务怎么做呢?我不可能只靠一个CPU来搞业务啊,这个限制不是太大了?

二、解决方法

1:多进程

child_process

等模块创建多进程

这种打补丁方法不是很好,涉及进程通信,写代码效率不高,很容易出现bug。开发者很可能出现变量无法访问的问题,因为多个进程,变量没有共享。不过业务写很分开,也问题不大,多进程资源比较大。

2:多线程

worker_threads

真正用的是多线程,我自己写代码测试,不停创建worker_threads..

测试代码

const { Worker, isMainThread, parentPort } = require('worker_threads');
console.log("hello world:" + isMainThread)

/*if (isMainThread) {
  // This code is executed in the main thread and not in the worker.
  
  // Create the worker.
  const worker = new Worker(__filename);
  // Listen for messages from the worker and print them.
  worker.on('message', (msg) => { 
      console.log(msg); 
    });
} else {
  // This code is executed in the worker and not in the main thread.
  
  // Send a message to the main thread.
  parentPort.postMessage('Hello world!');
}*/

function test(){
    if(isMainThread){
      console.log("自动线程哦");
      const worker = new Worker("./work.js");
    }
   
}

setInterval(() => {
  test();
}, 1000);

通过定时器不停创建工程线程。

work.js

const { isMainThread, parentPort,Worker, threadId } = require('worker_threads');



const min = 2
const max = 1e7

function generatePrimes(start, range) {
    let primes = []
    let isPrime = true
    let end = start + range
    for (let i = start; i < end; i++) {
      for (let j = min; j < Math.sqrt(end); j++) {
        if (i !== j && i%j === 0) {
          isPrime = false
          break
        }
      }
      if (isPrime) {
        primes.push(i)
      }
      isPrime = true
    }
    return primes
 }


console.log("线程id:" + threadId)
generatePrimes(1, 10000000)
console.log("线程id:" + threadId + " 完成")

可以通过资源管理器查看线程【默认不显示,自己设置一下】,线程数不停增加

可以不停增加,因为我这个写法,会很快把cpu吃死。。。。如果像以前nodejs 普通写法,最多只能吃一个CPU..


注意在线程里面不要直接访问对象,毕竟node js 模式就是异步+主线程,引入多线程导致更多问题,多线程仅仅执行,然后丢回主线程即可。

electron 拦截 window.open

一、背景

我之前写一个工具用来客户端加载网页,同时可以注入js,增加功能,类似chrome 浏览器扩展逻辑,但由于网页总是新建一个窗口,我虽然用JS 注入,修改了所有 a 标签的 。但对于动态的无能为力,除非定时器不停遍历,但性能不好,于是就想从electron入手。

二、过程

自己网络查找一些有关的信息,找到一个new-window 事件,这个事件可以捕获新建窗口逻辑。

one_plugin_ui.webContents.on('new-window',(event, url, frameName, disposition, options, additionalFeatures)=&gt;{
      log.debug("new")
      one_plugin_ui.loadURL(url) //在当前窗口打开,如果不想打开,完全想拦截,可以通过url 判断,然后不跳转URL
      event.preventDefault()      
    })

node request 设置代理

一、背景

自己用node request 请求 http 发现请求无法正确应答,我用fidder抓包没有抓对应数据包,因为默认node 不会走 windows 默认代理。

二、解决过程

在request 构建增加参数 proxy: 'http://127.0.0.1:8888'

这个设置代理到fidder里面去,如果非HTTPS 可以直接用wireshark来抓包。

三、补充

如果是第三方程序,如果不会默认走代理,可以用proxifier, 这个软件出来很多年,自己可以百度下载,官方可以试用30天。

proxifier过滤指定进程名字,然后转发443 80 端口数据包到fiddler上面,这样子就可以抓任何程序的包,无论他支不支持代理。

java 压缩的二进制数据传递给node js处理问题

一, 背景

自己压缩android 截图数据压缩然后网络传递给我node程序,然后发现node 无法解压。

二,排错过程

打印java 压缩的二进制数据数组,打印node收到 buffer,发送java数组函数负数,而node 得到没有负数

三,思考

看到这个2边数据不一样,我就想起来是什么导致。java byte 是 -128~127,node byte是 0~255. 这样子导致数据对不上,我要说一点二进制数据是一样的。这个只是node 读同样的二进制,解析数据0~255范围[byte],java虚拟机解析~128-127。这个就跟我们传送数据,会出现大端和小端问题一样,必须保证2边一致。。。。

四,解决

我直接在NODE 处理每个字节 var c = buffer[i] & 0xff 即可

node js 后台解析HTML(获取微博热门搜搜)

一,背景

最近自己准备写一个热门排行榜的功能,自己百度一下Node js 能够解析html的库,自己找到cheerio,这个库发现非常适合自己,因为他的用法跟jquery 类似。于是我拿微博热门搜索来练手,熟悉cheerio库,顺便用一个node js 网络库got

二,逻辑

通过网页源代码,可以分析每个tr下面td class=td-02 下面a标签就是我们要找的元素,那么通过jquery 语法写法 $("tbody>tr>td.td-02>a"),逻辑就这么简单。

三,代码

const html_parse = require("cheerio")
const got = require("got")

async function getWeibo(){
    var all_data = []
    var respond = await got("https://s.weibo.com/top/summary?cate=realtimehot", {headers:{
        "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78"
    }})

    if(respond.body){
        let $ = html_parse.load(respond.body)
        let items = $("tbody>tr>td.td-02>a")

        for(let i = 1; i < 10 && i < items.length; i++){
            let item = "https://s.weibo.com";
            let href = $(items[i]).attr("href")
            let text = $(items[i]).text()
            all_data.push({
                href: item + href,
                text: text
            })
        }
    }
    return all_data
}


async function test(){
    let r = await getWeibo()
    console.log(r)
}

test()

代码是不是非常简单,await 只是异步语法糖,自从我用c# 就喜欢用这个语法,避免死亡回调,网络库用got ,我请求替换user-agent,貌似微博也没有做限制,你不设置照样也能获取数据,但我还是加了,以免带来不必要的麻烦,这里面let i = 1 从开始循环,因为它有一个置顶元素,设置1直接过滤掉,这里10 只是我自己主要10条,你可以通过参数传递获取条数。

四:效果图

五,补充

我以前解析html,我都是当成字符串切割,然后再自己解析,虽然这种比较快,但写代码每次都要计算切割,不够通用,如果直接用Html 解析库,就很容易获取了,特别这种类似jquery的查找方法的。


自己最近写前端比较多,经常看到说jquery 落寞之类,我自己反复思考这个问题,我觉得这个无稽之谈。jquery 只是封装操作dom的类而已,vue 或者 react 他们另外数据库绑定而已,他们只是隐藏了dom操作而已,但他们底层也必须实现dom操作元素。对于新手来说用vue 或者react 等等非常舒服,但毕竟不是根本。html + javascript + css 这个永远不会变,那么dom操作永远都需要。这个就好像windows开发程序员,你用了mfc封装 window 操作类,你就觉得windows api 是垃圾可笑。

我觉得开发不能完全只管业务,不去了解任何有关底层知识,这种就是舍本逐源的做法。

electron 拦截下载,启动浏览器下载

一,说明

electron 不像浏览器会带下载管理,electron 页面调用下载的话,无法感知下载进度,我这里偷懒,直接丢给默认浏览器下载。

二,代码

    one_plugin_ui.webContents.session.on("will-download", (event, item, webContents)=>{
      let url = item.getURL()
      item.cancel()
      shell.openExternal(url);
      webContents.loadFile("download.html")
    })
  • one_plugin:electron的 windows
  • win-download:触发下载事件
  • item.cancel():取消electron默认下载逻辑
  • shell.openExternal:调用默认程序(浏览器)打开url
  • webContents.loadFile:加载自己定义下载界面【因为点击文件下载,会弹出新的窗口,默认是空白的,为了体验好一点,我增加一个提示下载的页面】
  • item: 对应的electron的对象 downloaditem

三,文档

downloaditem的介绍

nodejs console 日志统一增加时间戳

一,背景

node js 一般打印日志使用console.log ,如果现有项目希望增加打印日志,那么我们可以重载打印日志函数,我们直接用现有的功能模块

log-timestamp

二,使用

require('log-timestamp');

导入即可,默认时间戳是用的国际时间,你可以传入你要写的时间戳。

const log_time = require('log-timestamp');   //增加日志时间戳
log_time(function(){
    return "[" + new Date().toLocaleString() + "]"
})

三,原理

重载函数

类似console.log = function(...){ console.old_log(...)}

fishtools 插件工具1.0.0.2

背景

这个工具我很早之前就想开发了,陆陆续续开发一段事件时间,基本功能开发完全了

目的

软件快速通过关键词或者关键词的缩写打开对应的网址,因为自己常常会开一些web,进行访问。 这个软件有点借鉴utools,这个工具可以对接任何web网页,加入js注入。
本软件只是练手electron 技术而已,后续慢慢补充各种插件和web,实现自己软件自给自足。提高自己快速编码能力和产品的驾驭能力。

用途

  • 快速访问网址,不用自己记录各种网址
  • 可以常驻后台,避免浏览器关闭,导致网页关闭
  • 自带js注入框架,方便自己扩展各种网页功能,满足更多功能【具有无限可能】
  • 后续可能的功能是窗口大小记忆

使用教程

添加自己的网址,这里主要设置关键词,这里设置js,那么当自己ctrl + alt + k 调出输入框 ,然后输入js,就会列出访问的网址。

下载云端js 插件,你也可以右键自己添加js插件,这样子就可以控制任何网页界面代码。

这里我设置正则,匹配语雀文档时候,弹出密码验证框,这样子相当于给自己的网页语雀增加了密码验证。这里密码我写死为helloworld123

下载

链接:https://pan.baidu.com/s/172DBUEKF_Y911hNik7Gtsw
提取码:1234
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V5的分享

代码

因为electron练手项目,所以暂时不开源,但electron asar只要解压就可以看到代码,所以你也可以获取到代码

TODO

  • 增加窗口大小记录
  • 增加导航栏,方便使用

electron 加载第三方页面,无法jquery问题

如题,这个官方问题里面已经写了解决方案,我只是记录一下方便整理

我在 Electron 中无法使用 jQuery、RequireJS、Meteor、AngularJS。

因为 Electron 在运行环境中引入了 Node.js,所以在 DOM 中有一些额外的变量,比如 moduleexports 和 require。 这导致 了许多库不能正常运行,因为它们也需要将同名的变量加入运行环境中。

我们可以通过禁用 Node.js 来解决这个问题,在Electron里用如下的方式:

// 在主进程中.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow(format@@
  webPreferences: {
    nodeIntegration: false
  }
})
win.show()

假如你依然需要使用 Node.js 和 Electron 提供的 API,你需要在引入那些库之前将这些变量重命名,比如:

<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js"></script>
</head>

electron 打包 与 inno setup使用

背景

自己之前用electron-builder 在windows打包,默认安装到user local 目录,自己也对elecron-builder不熟悉,对inno setup打包比较熟悉,同时inno setup 可以任意目录,各种高级功能

过程

  • electron-builer 在windows打包
  • 找到生成目录里面的win-unpacked文件夹
  • inno setup 直接打包即可(直接可视化操作,你也可以修改脚本)

总结

这里用electron-builder 主要打包成asar而已,其实也可以完全用asar打包成asar。再用inno 打包即可