前言
大家好,我是鲫小鱼。是一名不写前端代码
的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!
第六章:多线程与异步操作
一、理论讲解:为什么要用多线程与异步?
在自动化脚本开发中,常常需要同时处理多个任务,比如:
- 主流程自动化操作的同时,后台监控弹窗、广告、异常
- 定时任务与实时响应用户操作
- 网络请求、数据存储等耗时操作不阻塞主线程
Auto.js 提供了 threads、timers、events、异步回调等多种并发与异步机制,帮助我们实现高效、流畅的自动化体验。
1.1 多线程与异步的区别
- 多线程:多个线程并发执行,互不阻塞,适合后台监控、定时任务、并发操作
- 异步:通过回调、Promise、定时器等机制,实现任务非阻塞,适合网络请求、UI响应等
1.2 常见应用场景
- 后台弹窗/广告/异常监控与自动处理
- 定时任务与周期性操作
- 网络请求、文件读写、数据同步
- 多账号/多任务并发执行
- UI界面与主逻辑分离,提升响应速度
二、基础用法与代码示例
2.1 启动新线程
javascript
// 启动一个新线程执行任务
threads.start(function(){
while(true){
toast("子线程运行中");
sleep(5000);
}
});
2.2 线程间通信
javascript
// 主线程与子线程通过 events 模块通信
var th = threads.start(function(){
events.on("custom_event", function(msg){
toast("收到主线程消息:" + msg);
});
});
events.broadcast.emit("custom_event", "你好,子线程!");
2.3 线程安全与资源释放
javascript
// 线程退出与资源释放
var th = threads.start(function(){
while(true){
if (files.exists("/sdcard/stop.flag")) break;
sleep(1000);
}
toast("子线程已退出");
});
// 主线程可通过 th.interrupt() 强制终止
// th.interrupt();
2.4 定时任务与异步操作
javascript
// 定时执行任务
timers.setInterval(function(){
toast("定时任务执行中");
}, 10000);
// 延时执行
timers.setTimeout(function(){
toast("延时3秒执行");
}, 3000);
2.5 异步网络请求
javascript
// 异步请求数据并回调处理
http.get("https://api.github.com", {}, function(res, err){
if(err){
toast("请求失败");
return;
}
toast("状态码:" + res.statusCode);
});
2.6 Promise 用法
javascript
// 使用 Promise 封装异步操作
function asyncTask(){
return new Promise((resolve, reject) => {
setTimeout(() => resolve("任务完成"), 2000);
});
}
asyncTask().then(msg => toast(msg));
2.7 多线程与 UI 交互
javascript
// 子线程不能直接操作 UI,需通过 runOnUiThread
threads.start(function(){
ui.run(() => {
toast("在UI线程弹窗");
});
});
三、实战项目:后台弹窗监控与自动处理
3.1 需求分析
- 主线程执行主流程(如自动签到、自动点击)
- 子线程实时监控弹窗、广告、异常提示,并自动关闭
- 支持多种弹窗文本、控件类型的适配
- 日志记录弹窗处理历史
3.2 项目结构
plaintext
autojs-multithread/
├── main.js
├── modules/
│ ├── popup_watcher.js
│ └── logger.js
├── logs/
│ └── popup.log
└── README.md
3.3 popup_watcher.js 代码
javascript
// modules/popup_watcher.js
const logger = require("./logger.js");
const popupTexts = ["关闭", "取消", "我知道了", "以后再说", "忽略", "不再提示"];
function startWatcher(){
threads.start(function(){
while(true){
popupTexts.forEach(txt => {
let btn = text(txt).findOne(500);
if(btn){
btn.click();
logger.log("自动关闭弹窗:" + txt);
}
});
sleep(1000);
}
});
}
module.exports = { startWatcher };
3.4 logger.js 代码
javascript
// modules/logger.js
function log(msg) {
let line = `[${new Date().toLocaleTimeString()}] ${msg}`;
files.append("../logs/popup.log", line + "\n");
toast(msg);
}
module.exports = { log };
3.5 main.js 代码
javascript
// main.js
const watcher = require("./modules/popup_watcher.js");
const logger = require("./modules/logger.js");
// 启动弹窗监控线程
watcher.startWatcher();
// 主流程示例
for(let i=0;i<10;i++){
logger.log("主流程第" + (i+1) + "步");
sleep(2000);
}
logger.log("主流程结束");
四、分步详解与进阶技巧
4.1 多线程监控多类弹窗
- 支持自定义弹窗文本、控件类型、正则匹配
- 支持多线程并发监控不同App、不同页面
4.2 线程池与线程管理
- 使用 threads.start 多线程并发,注意线程数量控制
- 线程池模式可避免线程泄漏、资源浪费
- 线程退出与回收,防止僵尸线程
4.3 线程间通信与数据共享
- events 模块实现线程间消息传递
- 全局变量、文件、数据库实现数据共享
- 注意线程安全与同步
4.4 异步队列与任务调度
- 使用队列管理异步任务,避免并发冲突
- 任务优先级、超时、重试机制
4.5 UI与多线程协作
- 子线程不能直接操作UI,需通过 ui.run/runOnUiThread
- UI事件与主逻辑分离,提升响应速度
4.6 线程异常与容错
- try-catch 捕获线程异常,日志记录
- 线程崩溃自动重启、报警
4.7 定时任务与周期性操作
- timers.setInterval/setTimeout 实现定时、延时
- 支持多定时器、动态调整周期
4.8 多账号/多任务并发
- 多线程并发处理多个账号、多个App
- 线程池+任务队列实现高效批量操作
五、常见问题与解决方案
问题 | 解决方案 |
---|---|
子线程无法操作UI | 用 ui.run() 或 events 传递到主线程 |
线程无法退出/僵尸线程 | 合理使用 interrupt、条件变量、资源释放 |
线程间数据不同步 | 用 events、全局变量、文件等同步 |
异步回调未执行/丢失 | 检查回调函数、网络状态、异常捕获 |
定时任务不准/丢失 | 检查 timers、线程、App 后台限制 |
线程数过多导致卡顿 | 控制线程数量、使用线程池、优化任务粒度 |
线程崩溃/异常未捕获 | try-catch 捕获异常,日志记录,自动重启 |
多线程操作同一资源冲突 | 加锁、队列、分片处理,避免并发写入 |
六、性能优化建议
- 控制线程数量,避免资源耗尽
- 合理拆分主线程与子线程,主线程只做调度
- 异步处理耗时操作,提升主流程响应
- 定时任务加超时与重试,防止卡死
- 线程退出及时释放资源,避免内存泄漏
- 日志分级输出,开发阶段多输出,正式运行时降级
- 线程池+任务队列提升并发效率
- 线程异常自动重启,提升健壮性
- 合理 sleep,避免无效等待
- 线程间通信用 events,避免全局变量冲突
最后感谢阅读!欢迎关注我,微信公众号:
《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!!