哔哩哔哩:https://www.bilibili.com/video/BV1KyfhYnEHC/
– 多线程 –
1、什么是多线程
threads模块提供了多线程支持,可以启动新线程来运行脚本。
脚本主线程会等待所有子线程执行完成后才停止执行,因此如果子线程中有死循环,请在必要的时候调用exit()
来直接停止脚本或threads.shutDownAll()
来停止所有子线程。
通过threads.start()
启动的所有线程会在脚本被强制停止时自动停止。
由于JavaScript自身没有多线程的支持,因此您可能会遇到意料之外的问题。
2、启动多线程
threads.start(action)
action
{Function} 要在新线程执行的函数- 返回 Thread
启动一个新线程并执行action。
例如:
threads.start(function(){
//在新线程执行的代码
while(true){
log("子线程");
}
});
while(true){
log("脚本主线程");
}
通过该函数返回的Thread对象可以获取该线程的状态,控制该线程的运行中。例如:
var thread = threads.start(function(){
while(true){
log("子线程");
}
});
//停止线程执行
thread.interrupt();
3、在UI中使用多线程
"ui";
ui.layout(
<vertical>
<button id="start" text="开始运行"/>
<button text="第二个按钮"/>
</vertical>
);
ui.start.click(function(){
home();
sleep(1000);
})
4、获取线程对象Thread
线程对象,threads.start()
返回的对象,用于获取和控制线程的状态,与其他线程交互等。
Thread对象提供了和timers模块一样的API,例如setTimeout()
, setInterval()
等,用于在该线程执行相应的定时回调,从而使线程之间可以直接交互。例如:
var thread = threads.start(function(){
//在子线程执行的定时器
setInterval(function(){
log("子线程:" + threads.currentThread());
}, 1000);
});
log("当前线程为主线程:" + threads.currentThread());
//等待子线程启动
thread.waitFor();
//在子线程执行的定时器
thread.setTimeout(function(){
//这段代码会在子线程执行
log("当前线程为子线程:" + threads.currentThread());
}, 2000);
sleep(30 * 1000);
thread.interrupt();
threads.currentThread()
返回当前线程。
5、线程控制
threads.shutDownAll()
停止所有通过threads.start()
启动的子线程。
Thread.interrupt()
中断线程运行。
Thread.join([timeout])
timeout
{number} 等待时间,单位毫秒
等待线程执行完成。如果timeout为0,则会一直等待直至该线程执行完成;否则最多等待timeout毫秒的时间。
例如:
var sum = 0;
//启动子线程计算1加到10000
var thread = threads.start(function(){
for(var i = 0; i < 10000; i++){
sum += i;
}
});
//等待该线程完成
thread.join();
toast("sum = " + sum);
isAlive()
- 返回 {boolean}
返回线程是否存活。如果线程仍未开始或已经结束,返回false
; 如果线程已经开始或者正在运行中,返回true
。
waitFor()
等待线程开始执行。调用threads.start()
以后线程仍然需要一定时间才能开始执行,因此调用此函数会等待线程开始执行;如果线程已经处于执行状态则立即返回。
var thread = threads.start(function(){
//do something
});
thread.waitFor();
thread.setTimeout(function(){
//do something
}, 1000);
– 示例代码 –
1、多线程:变量可见性实验
var running = true;
threads.start(function(){
while(running){
log("running = true");
}
});
sleep(2000);
running = false;
console.info("running = false");
2、多线程:多线程按键监听
auto();
threads.start(function(){
//在子线程中调用observeKey()从而使按键事件处理在子线程执行
events.observeKey();
events.on("key_down", function(keyCode, events){
//音量键关闭脚本
if(keyCode == keys.volume_up){
exit();
}
});
});
toast("音量上键关闭脚本");
events.on("exit", function(){
toast("脚本已结束");
});
while(true){
log("脚本运行中...");
sleep(2000);
}
3、多线程:启动与关闭
//启动一个无限循环的线程
var thread = threads.start(function(){
while(true){
log("子线程运行中...");
sleep(1000);
}
});
//5秒后关闭线程
sleep(5000);
thread.interrupt();
4、多线程:简单示例
//启动一个线程
threads.start(function(){
//在线程中每隔1秒打印"线程1"
while(true){
log("线程1");
sleep(1000);
}
});
//启动另一个线程
threads.start(function(){
//在线程中每隔2秒打印"线程1"
while(true){
log("线程2");
sleep(2000);
}
});
//在主线程中每隔3秒打印"主线程"
for(var i = 0; i < 10; i++){
log("主线程");
sleep(3000);
}
//打印10次后退出所有线程
threads.shutDownAll();
5、协程:协程HelloWorld
"useFeatures": ["continuation"]
// 注意,要使用协程这个特性,必须使用项目功能,并且在project.json配置好features属性
// delay不同于sleep,不会阻塞当前线程
function delay(millis) {
var cont = continuation.create();
setTimeout(()=>{
cont.resume();
}, millis);
cont.await();
}
// 异步IO例子,在另一个线程读取文件,读取完成后返回当前线程继续执行
function read(path) {
var cont = continuation.create();
threads.start(function(){
try {
cont.resume(files.read(path));
}catch(err){
cont.resumeError(err);
}
});
return cont.await();
}
// 使用Promise和协程的例子
function add(a, b) {
return new Promise(function(resolve, reject) {
var sum = a + b;
resolve(sum);
});
}
toastLog("Hello, Continuation!");
//3秒后发出提示
setTimeout(()=>{
toastLog("3秒后....");
}, 3000);
// 你可以尝试把delay更换成sleep,看会发生什么!
delay(6000);
toastLog("6秒后...");
try {
toastLog("读取文件hello.txt: " + read("./hello.txt"));
}catch(err){
console.error(err);
}
var sum = add(1, 2).await();
toastLog("1 + 2 = " + sum);
6、协程:ui中使用协程
"ui";
ui.layout(
<frame bg="#4fc3f7">
<text textColor="white" textSize="18sp" layout_gravity="center">
UI中使用协程
</text>
</frame>
);
continuation.delay(5000);
if (!requestScreenCapture()) {
dialogs.alert("请授予软件截图权限").await();
}
// 退出应用对话框
ui.emitter.on("back_pressed", function (e) {
e.consumed = true;
let exit = dialogs.confirm("确定要退出程序").await();
if (exit) {
ui.finish();
}
});