# run-time-opti **Repository Path**: foxjc/run-time-opti ## Basic Information - **Project Name**: run-time-opti - **Description**: for web. 基于异步promise的 js运行时优化方案 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-12-06 - **Last Updated**: 2024-12-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一个基于异步的 优化js运行时解决方案 # 核心思路:
基于[rail](https://web.dev/rail/)标准,通过webworker并行,长任务拆分&分帧执行,让出主线程,利用浏览器空闲执行等方式
避免js线程长期执行,阻塞UI渲染。以达到性能优化的目的。 截屏2024-03-03 下午5 29 57 ![new-thread](https://github.com/wuyunqiang/dynamic-tasks/assets/13480948/aad5de7f-6919-401f-b165-cf36f0e46638) ## normal https://github.com/wuyunqiang/dynamic-tasks/assets/13480948/e3dd2bdc-ba3a-469d-b8eb-7fa2a68819d2 normal ## frame https://github.com/wuyunqiang/dynamic-tasks/assets/13480948/d2d89081-5d89-4df9-8c3a-c22b7ca36956 frame ``` npm install run-time-opti || yarn add run-time-opti ``` 默认ES6语法 使用方自行转译和polyfill ```javascript const p1 = (res) => { return 1111; }; const p2 = (res) => { return 2222; }; const p3 = (res) => new Promise((resolve) => { setTimeout(() => { resolve(33333); }, 2000); }); const p4 = (res) => new Promise((resolve, reject) => { setTimeout(() => { reject(4444); }, 6000); }); const p5 = (res) => new Promise((resolve) => { setTimeout(() => { resolve(5555); }, 1000); }); ``` # 功能:
## yieldToMain 让出主线程 避免长任务阻塞UI 造成页面卡顿
此方法后面的任务将在下一帧继续执行。
优先使用MessageChannel宏任务&无延迟 使用setTimeOut兼容处理 ```javascript import {yieldToMain} from "run-time-opti"; p1() await yieldToMain(); // 中断当前帧 让出给main thread 下一帧继续执行 p2(); ``` ## sleep ```javascript import { sleep } from "run-time-opti"; console.log('111111') await sleep(2000) // 两秒后继续执行 console.log('222222') ``` ## nextFrameExecute 下一帧执行某个任务
实现优先级:
1:使用MessageChannel宏任务方式
2:使用requestAnimationFrame
3:使用setTimeout做兼容。
```javascript import { nextFrameExecute } from "run-time-opti"; p1() nextFrameExecute(p2) // 将在下一帧执行这个任务 p3() ``` ## DynamicTasks 有UI操作并且优先级较高 建议使用DynamicTasks的方式 避免卡顿使用frame参数分帧运行
* 支持动态添加 * 支持并行&串行 * 支持同步&异步 * 支持时间切片 ```javascript import {DynamicTasks} from "run-time-opti"; const task = new DynamicTasks({ parallelMax: 3, frame: true }); task.start([ { key: "p1", task: p1, parallel: true, }, { key: "p2", task: p2, parallel: true, }, ]); task.start([ { key: "p3", task: p3, parallel: true, }, { key: "p4", task: p4, parallel: true, }, { key: "p5", task: p5, // 默认的串行的 会等待前面的全部执行完成 并且可以获取前面的结果 }, { key: "p6", task: (allResult)=>{ console.log('test allResult', allResult) }, }, ]); ``` ## pool 支持web worker线程池
无UI操作 大量运算 建议使用pool的线程池方式运行。
run in web worker thread pool。
独立main thread上下文 使用new Function转换运行,因此不能访问外部变量。
可以通过串行的方式(默认就是串行),获取到上一个task的结果。
可以通过网络获取数据运算。
```javascript import { pool } from "run-time-opti" const p1 = (res) => { console.log("test p1 res", res, 1111); return 1111; }; const p2 = (res) => { console.log("test p2 res", 22222); }; const p3 = (res) => new Promise((resolve) => { const test = () => { let count = 0; for (let i = 0; i < 1000000000; i++) { count = count + i; } }; test(); setTimeout(() => { resolve(33333); }, 5000); console.log("test p3 res", res, 3333333); }); pool([ { key: "p1", task: p1, }, { key: "p2", task: p2, }, { key: "p3", task: p3, }, ], 2).then((res) =>{ console.log("test pool:", res); { p1: { data: 1111, key: "p1", status: "succ", }, p2: { data: undefined, key: "p2", status: "succ", }, p3: { data: 33333, key: "p3", status: "succ", } } }); ``` ## clearPool ```javascript import { clearPool } from "run-time-opti" clearPool() ``` ## idleCallback 浏览器空闲执行 不紧急的任务建议使用这个api
不建议UI操作:
原因1:此时已经渲染完成,UI变更会导致页面重绘应尽量避免
原因2:因为调用时机不确定 dom操作会导致页面视觉变动难以预测
参考react fiber思路通过raf+messagechannel 对不支持requestidlecallback的浏览器做了polyfill。 ```javascript import { idleCallback } from "run-time-opti" idleCallback((params)=>{ console.log('test idleCallback params', params) }, { timeout: 100}) ``` ## idle 浏览器空闲执行 不紧急的任务建议使用这个api
不建议UI操作:
原因1:此时已经渲染完成,UI变更会导致页面重绘应尽量避免
原因2:因为调用时机不确定 dom操作会导致页面视觉变动难以预测
内部使用idleCallback方法。 ```javascript import { idle } from "run-time-opti" idle([{key: 'p1',task: p1}],100).then(res => { console.log('test idle:', res) }) ``` ## serialTask 顺序执行一系列任务 并返回结果 ```javascript import {serialTask} from "run-time-opti"; serialTask([p1,p2,p3]).then(res=>{ console.log("test res", res) }) res: [ { status: 'succ', data: 1111 }, { status: 'succ', data: 2222 }, { status: 'succ', data: 33333 } ] ``` ## parallelMaxTask 并发执行一系列任务并返回结果 ```javascript import {parallelMaxTask} from "run-time-opti"; parallelMaxTask([p1,p2, p3], 2).then((res)=>{ console.log('test parallelMaxTask: ', res) }) res: [ { status: 'succ', data: 1111 }, { status: 'succ', data: 2222 }, { status: 'succ', data: 33333 } ] ``` ## TaskCancelable 封装的一个可以取消的promise任务 ```javascript import {TaskCancelable} from "run-time-opti" const p3 = () => new Promise((resolve) => { setTimeout(() => { resolve(33333); }, 2000); }); const cancelP = TaskCancelable(p3()); cancelP .then((res) => { console.log("test res", res); }) .catch(() => { if (cancelP.isCancel()) { // true console.log("test cancel"); } }) .finally(() => { console.log("test finally isCancel:", cancelP.isCancel()); // true }); cancelP.cancel(); ``` ## [KillAwait](https://github.com/wuyunqiang/blog/issues/23) Promise的同步调用 消除异步的传染性 ```javascript import { KillAwait } from "run-time-opti" const test3 = () => { const res = KillAwait.promise((resolve) => { setTimeout(() => { resolve(3); }, 2000); }); console.log("test 3 res", res); return res; }; const test2 = () => { const res = KillAwait.promise((resolve) => { setTimeout(() => { resolve(2); }, 2000); }); console.log("test 2 res", res); return test3(); }; const test1 = () => { const res1 = KillAwait.promise((resolve) => { setTimeout(() => { resolve(1); }, 2000); }); console.log("test 1 res1", res1); const res2 = KillAwait.promise((resolve) => { setTimeout(() => { resolve(1.2); }, 2000); }); console.log("test 1 res2", res2); return test2(); }; const main2 = () => { const res = test1(); console.log("test 最终结果 res", res); }; KillAwait.execute(main2); // res test 1 res1 1 test 1 res1 1 test 1 res2 1.2 test 1 res1 1 test 1 res2 1.2 test 2 res 2 test 1 res1 1 test 1 res2 1.2 test 2 res 2 test 3 res 3 test 最终结果 res 3 ``` ## microTask & macroTask ```javascript import { microTask, macroTask } from "run-time-opti" microTask(()=>{ console.log('microTask') }) macroTask(()=>{ console.log('macroTask') }) ```