node读取大文件
js
import * as fs from 'fs';
import * as os from 'os';
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';
// 配置常量
const FILE_DELIMITER = 'YOUR_FILE_DELIMITER';
const EOL = os.EOL;
const EOL_BUFFER = Buffer.from(EOL);
const DELIMITER_LINE = Buffer.from(FILE_DELIMITER + EOL);
const WORKER_COUNT = os.cpus().length;
// 主线程预处理函数
async function findDelimiterPositions(filePath: string) {
const fileSize = (await fs.promises.stat(filePath)).size;
const chunkSize = 1024 * 1024;
const positions: number[] = [];
let previousRemaining = Buffer.alloc(0);
const fd = await fs.promises.open(filePath, 'r');
try {
for (let offset = 0; offset < fileSize;) {
const buffer = Buffer.alloc(chunkSize + DELIMITER_LINE.length);
const { bytesRead } = await fd.read(buffer, 0, chunkSize, offset);
if (!bytesRead) break;
const combined = Buffer.concat([previousRemaining, buffer.subarray(0, bytesRead)]);
let pos = 0;
while (pos < combined.length) {
const idx = combined.indexOf(DELIMITER_LINE, pos);
if (idx === -1) {
previousRemaining = combined.subarray(pos);
break;
}
positions.push(offset - previousRemaining.length + idx);
pos = idx + DELIMITER_LINE.length;
}
offset += bytesRead;
}
} finally {
await fd.close();
}
return positions;
}
// 工作线程处理逻辑
function workerProcess() {
const { filePath, start, end, filePo } = workerData;
const stream = fs.createReadStream(filePath, { start, end });
const result: Buffer[] = [];
let stationBuffer = Buffer.alloc(100);
let tempBuffer = Buffer.alloc(5);
let linePo = 0;
// 字节处理状态机
let state = 0; // 0: 正常行处理,1: 分隔符处理
let buffer = Buffer.alloc(0);
return new Promise<void>((resolve) => {
stream.on('data', (chunk: Buffer) => {
buffer = Buffer.concat([buffer, chunk]);
while (true) {
olIndex = buffer.indexOf(EOL_BUFFER);
if (eolIndex === -1) break;
const line = buffer.subarray(0, eolIndex);
buffer = buffer.subarray(eolIndex + EOL_BUFFER.length);
if (line.equals(DELIMITER_LINE.subarray(0, line.length))) {
// 分隔符行直接跳过
continue;
}
// 字节到字符串转换优化
const transformed = processLine(line, linePo, filePo);
result.push(Buffer.from(transformed + EOL));
linePo++;
}
});
stream.on('end', () => {
parentPort.postMessage({
filePo,
data: Buffer.concat(result)
});
resolve();
});
});
}
// 优化的行处理函数
function processLine(lineBuffer: Buffer, linePo: number, filePo: number) {
// 实现你的自定义转换逻辑
return lineBuffer.toString() + `_processed_${filePo}_${linePo}`;
}
// 主线程逻辑
async function main() {
const filePath = process.argv[2];
const outputPath = process.argv[3];
const delimiterPositions = await findDelimiterPositions(filePath);
const fileSize = (await fs.promises.stat(filePath)).size;
const parts = [];
let prevPos = 0;
// 生成处理区间
for (const pos of delimiterPositions) {
parts.push({ start: prevPos, end: pos, filePo: parts.length });
prevPos = pos + DELIMITER_LINE.length;
}
parts.push({ start: prevPos, end: fileSize, filePo: parts.length });
// 创建工作线程
const workers = new Map();
const results = new Map();
parts.forEach((part, idx) => {
const worker = new Worker(__filename, {
workerData: { ...part, filePath }
});
worker.on('message', (msg) => {
results.set(msg.filePo, msg.data);
if (results.size === parts.length) {
// 按顺序写入结果
const sorted = Array.from(results.keys()).sort((a, b) => a - b);
const ws = fs.createWriteStream(outputPath);
sorted.forEach(po => ws.write(results.get(po)));
ws.end();
}
});
workers.set(idx, worker);
});
}
// 启动入口
if (isMainThread) {
main();
} else {
workerProcess();
}js判断当前环境是否是微信小程序环境
js
window.navigator.userAgent.toLowerCase().includes('miniprogram/wx') || window.__wxjs_environment === 'miniprogram'类中方法的this指向
js
class Person{
constructor(name,age){
this.name=name
this.age=age
}
study(){
console.log(this)
}
}
const p = new Person('tom',18)
p.study()
const x = p.study
X() //属于函数的直接调用,输出this是 undefined类中所定义的方法,局部都开启了严格模式,跟babel无关
fetch()添加超时功能
js
function createFetchWithTimeout(timeout = 1000){
return (url,options)=>{
return new Promise((resolve,reject) => {
const signalController = new AbortController()//创建一个信号控制器 用来终端请求的
fetch(url,{
...options,
signal:signalController.signal
}).then(resolve,reject)
setTimeout(()=>{
reject(new Error('fetch timeout'))
//取消请求
signalController.abort()
},timeout)
})
}
}网页文件下载(a标签)
html
<!-- 添加download属性 -->
<a :href="item.filePath" download>下载</a>这种方式在ios会预览文件,而不是下载
js
/**
* @decription 下载兼容ios
* @param {object} value
* @param {object} value.filePath -文件地址
* @param {object} value.fileName - 文件名
*/
function download(value) {
let link = document.createElement('a');
link.href = value.filePath;
link.download = value.fileName;
// 在IOS上模拟点击链接
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
var event = document.createEvent('MouseEvents');
event.initMouseEvent(
'click',
true,
true,
window,
1,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
link.dispatchEvent(event);
} else {
// 在其他设备上直接下载文件
link.click();
}
}静态资源统一导出
js
export { default as lishui } from './lishui.json';
export { default as lishuipng } from './lishui.png';fetch获取json文件,拿到数据
js
let data = await fetch(lishui).then((response) => response.json());去除对象结构中不想要的字段
js
// 原始对象 item
const item = {
assets_id: 123,
name: 'Example',
description: 'This is an example description',
price: 100
};
// 从 item 中去除 name 字段
const { name, ...newItem } = item;
console.log(newItem);观察者IntersectionObserver
使用IntersectionObserver实现懒加载
js
//创建观察者
const ob = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
ob.unobserve(img); //取消对这个img观察
}
}
},
{
root: null, //观察元素跟谁的交叉,null表示视口 默认是null
rootMargin: '0px', //对视口进行扩张大于0向外扩张,默认是0
threshold: 0, //交叉多少才触发0~1
}
);
const imges = document.querySelectorAll('img[data-src]')
imgs.forEach((img) => {
ob.observe(img)
})判断当前环境是否是微信小程序
js
window.navigator.userAgent.toLowerCase().includes('miniprogram/wx');
window.__wxjs_environment === 'miniprogram'