M8Test Help

高级主题

协作式取消

协程的取消是“协作式”的,这意味着协程代码需要主动检查自己是否被取消。所有本库提供的挂起函数(如 delay)都会自动进行这种检查。

控制执行线程

使用 scope.withContext 可以在不同的线程池(调度器)之间安全地切换,而无需手动管理回调。

import com.m8test.script.GlobalVariables.* _threads.getMain().setBackground(true) // 修复:newScope 块移除显式参数 it ->,直接调用 setDispatcher val scope = _coroutines.newScope { setDispatcher { dispatchers -> dispatchers.getDefault() } } // 修复:launch 块移除显式参数 scope.launch(null, null) { _console.log("当前在默认线程池上: " + Thread.currentThread().name) // 修复:withContext 的 contextBuilder 块移除显式参数 withContext({ // 在配置块中指定要切换到的调度器 setDispatcher { dispatchers -> dispatchers.getScriptMain() } }) { // 修复:block 移除显式参数 innerScope -> // 这个闭包内的代码将在脚本主线程上执行 _console.log("已切换到脚本主线程: " + Thread.currentThread().name) "脚本主线程" } // 修复:withContext 参数 withContext({ setDispatcher { dispatchers -> dispatchers.getAndroidMain() } }) { _console.log("已切换到 Android UI 线程: " + Thread.currentThread().name) "Android UI线程" } }
$threads.getMain().setBackground(true) def scope = $coroutines.newScope { it.setDispatcher { dispatchers -> dispatchers.getDefault() } } scope.launch(null, null, { coroutineScope -> $console.log("当前在默认线程池上: " + Thread.currentThread().getName()) coroutineScope.withContext({ context -> // 在配置块中指定要切换到的调度器 context.setDispatcher { dispatchers -> dispatchers.getScriptMain() } }, { innerScope -> // 这个闭包内的代码将在脚本主线程上执行 $console.log("已切换到脚本主线程: " + Thread.currentThread().getName()) "脚本主线程" }) coroutineScope.withContext({ context -> context.setDispatcher { dispatchers -> dispatchers.getAndroidMain() } }) { $console.log("已切换到 Android UI 线程: " + Thread.currentThread().getName()) "Android UI线程" } })
$threads.getMain().setBackground(true); const scope = $coroutines.newScope(it => { it.setDispatcher(dispatchers => dispatchers.getDefault()); }); scope.launch(null, null, coroutineScope => { $console.log("当前在默认线程池上: " + Packages.java.lang.Thread.currentThread().getName()); coroutineScope.withContext(context => { // 在配置块中指定要切换到的调度器 context.setDispatcher(dispatchers => dispatchers.getScriptMain()); }, innerScope => { // 这个闭包内的代码将在脚本主线程上执行 $console.log("已切换到脚本主线程: " + Packages.java.lang.Thread.currentThread().getName()); return "脚本主线程"; }); coroutineScope.withContext(context => context.setDispatcher(dispatchers => dispatchers.getAndroidMain()), innerScope => { $console.log("已切换到 Android UI 线程: " + Packages.java.lang.Thread.currentThread().getName()); return "Android UI线程"; }); });
-- 引入 java.lang.Thread 类,这是修复的关键点 local Thread = require("m8test_java.java.lang.Thread") _threads:getMain():setBackground(true) local scope = _coroutines:newScope(function(it) it:setDispatcher(function(dispatchers) return dispatchers:getDefault() end) end) scope:launch(nil, nil, function(coroutineScope) _console:log("当前在默认线程池上: " .. Thread:currentThread():getName()) coroutineScope:withContext(function(context) -- 在配置块中指定要切换到的调度器 context:setDispatcher(function(dispatchers) return dispatchers:getScriptMain() end) end, function(innerScope) -- 这个闭包内的代码将在脚本主线程上执行 _console:log("已切换到脚本主线程: " .. Thread:currentThread():getName()) return "脚本主线程" end) coroutineScope:withContext(function(context) context:setDispatcher(function(dispatchers) return dispatchers:getAndroidMain() end) end, function() _console:log("已切换到 Android UI 线程: " .. Thread:currentThread():getName()) return "Android UI线程" end) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; use m8test_java\java\lang\Thread; $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $scope->launch(null, null, function ($coroutineScope) { global $console; $console->log(javaString("当前在默认线程池上: ") . Thread::currentThread()->getName()); $coroutineScope->withContext(function ($context) { // 在配置块中指定要切换到的调度器 $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }, function ($innerScope) { global $console; // 这个闭包内的代码将在脚本主线程上执行 $console->log(javaString("已切换到脚本主线程: ") . Thread::currentThread()->getName()); return javaString("脚本主线程"); }); });
# 导入Python标准库 import threading from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda dispatchers: dispatchers.getScriptMain()) ) scope.launch(None, None, lambda coroutineScope: ( _console.log("当前在脚本主线程上: " + threading.current_thread().name), coroutineScope.withContext( lambda context: context.setDispatcher(lambda dispatchers: dispatchers.getAndroidMain()), lambda innerScope: ( _console.log("已切换到 Android UI 线程: " + threading.current_thread().name), "Android UI线程" ) ) ))
# encoding: utf-8 $threads.getMain().setBackground(true) scope = $coroutines.newScope do |it| it.setDispatcher { |dispatchers| dispatchers.getDefault() } end scope.launch(nil, nil) do |coroutineScope| $console.log("当前在默认线程池上: " + Java::JavaLang::Thread.currentThread().getName()) coroutineScope.withContext(lambda do |context| # 在配置块中指定要切换到的调度器 context.setDispatcher { |dispatchers| dispatchers.getScriptMain() } end) do |innerScope| # 这个闭包内的代码将在脚本主线程上执行 $console.log("已切换到脚本主线程: " + Java::JavaLang::Thread.currentThread().getName()) "脚本主线程" end coroutineScope.withContext(lambda { |context| context.setDispatcher { |dispatchers| dispatchers.getAndroidMain() } }) do $console.log("已切换到 Android UI 线程: " + Java::JavaLang::Thread.currentThread().getName()) "Android UI线程" end end

懒加载协程

默认情况下,launch 和 async 会立即调度协程执行。但你可以通过 start 参数将其设置为懒加载模式,这样协程只会在被需要时(例如调用 job.start())才真正开始。

import com.m8test.script.GlobalVariables.* /* * 完整示例 6.4: 使用懒加载模式 */ // --- 样板代码 --- _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) _console.log("创建一个懒加载的 Deferred...") // 使用 CoroutineStarts.getLazy() 来设置启动模式 // 注意:start 参数是 (CoroutineStarts) -> CoroutineStart,这里需要保留参数 starts -> // 修复:block 参数是 CoroutineScope.() -> T,需要移除 s -> val lazyDeferred = scope.async(null, { starts -> starts.getLazy() }) { _console.log("懒加载的协程现在才真正开始执行!") delay(1500).then { innerScope, _ -> innerScope.resolve("懒加载的结果") } } _console.log("Deferred 已创建,但内部代码尚未执行。") _console.log("任务状态: isActive=" + lazyDeferred.isActive() + ", isCompleted=" + lazyDeferred.isCompleted()) scope.delay(1000).then { s, _ -> _console.log("\n1秒后... 准备启动任务...") // 手动启动任务 lazyDeferred.start() // 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 lazyDeferred .then { innerScope, result -> result } .then { innerScope, result -> _console.log("懒加载任务完成,结果是: " + result) innerScope.resolve(null) } }
/* * 完整示例 6.4: 使用懒加载模式 */ // --- 样板代码 --- $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) $console.log("创建一个懒加载的 Deferred...") // 使用 CoroutineStarts.getLazy() 来设置启动模式 def lazyDeferred = scope.async(null, { starts -> starts.getLazy() }, { s -> $console.log("懒加载的协程现在才真正开始执行!") s.delay(1500).then({ innerScope, _ -> innerScope.resolve("懒加载的结果") }) }) $console.log("Deferred 已创建,但内部代码尚未执行。") $console.log("任务状态: isActive=" + lazyDeferred.isActive() + ", isCompleted=" + lazyDeferred.isCompleted()) scope.delay(1000).then({ s, _ -> $console.log("\n1秒后... 准备启动任务...") // 手动启动任务 lazyDeferred.start() // 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 lazyDeferred .then({ innerScope, result -> result }) .then { innerScope, result -> $console.log("懒加载任务完成,结果是: " + result) innerScope.resolve(null) } })
/* * 完整示例 6.4: 使用懒加载模式 */ // --- 样板代码 --- $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); $console.log("创建一个懒加载的 Deferred..."); // 使用 CoroutineStarts.getLazy() 来设置启动模式 const lazyDeferred = scope.async(null, starts => starts.getLazy(), s => { $console.log("懒加载的协程现在才真正开始执行!"); return s.delay(1500).then((innerScope, _) => { return innerScope.resolve("懒加载的结果") }); }); $console.log("Deferred 已创建,但内部代码尚未执行。"); $console.log("任务状态: isActive=" + lazyDeferred.isActive() + ", isCompleted=" + lazyDeferred.isCompleted()); scope.delay(1000).then((s, _) => { $console.log("\n1秒后... 准备启动任务..."); // 手动启动任务 lazyDeferred.start(); // 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 return lazyDeferred .then((innerScope, result) => { // 根据API,then的处理器需要返回一个新的Deferred,这里我们用resolve包装结果 return result; }) .then((innerScope, result) => { $console.log("懒加载任务完成,结果是: " + result); return innerScope.resolve(null); }); }).onError(error => { $console.error("懒加载任务出错: " + error); });
--[[ * 完整示例 6.4: 使用懒加载模式 ]] -- --- 样板代码 --- _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) _console:log("创建一个懒加载的 Deferred...") -- 使用 CoroutineStarts.getLazy() 来设置启动模式 local lazyDeferred = scope:async(nil, function(starts) return starts:getLazy() end, function(s) _console:log("懒加载的协程现在才真正开始执行!") return s:delay(1500):_then(function(innerScope, _) return innerScope:resolve("懒加载的结果") end) end) _console:log("Deferred 已创建,但内部代码尚未执行。") _console:log("任务状态: isActive=" .. tostring(lazyDeferred:isActive()) .. ", isCompleted=" .. tostring(lazyDeferred:isCompleted())) scope:delay(1000):_then(function(s, _) _console:log("\n1秒后... 准备启动任务...") -- 手动启动任务 lazyDeferred:start() -- 或者,如果你需要结果,可以直接调用 ._then(),它们会自动触发启动 return lazyDeferred :_then(function(innerScope, result) return result end) :_then(function(innerScope, result) _console:log("懒加载任务完成,结果是: " , result) return innerScope:resolve(nil) end) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /* * 完整示例 6.4: 使用懒加载模式 */ // --- 样板代码 --- $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $console->log(javaString("创建一个懒加载的 Deferred...")); // 使用 CoroutineStarts.getLazy() 来设置启动模式 $lazyDeferred = $scope->async(null, function ($starts) { return $starts->getLazy(); }, function ($s) { global $console; $console->log(javaString("懒加载的协程现在才真正开始执行!")); return $s->delay(1500)->then(function ($innerScope, $_) { return $innerScope->resolve(javaString("懒加载的结果")); }); }); $console->log(javaString("Deferred 已创建,但内部代码尚未执行。")); $console->log(javaString("任务状态: isActive=") . ($lazyDeferred->isActive() ? 'true' : 'false') . javaString(", isCompleted=") . ($lazyDeferred->isCompleted() ? 'true' : 'false')); $scope->delay(1000)->then(function ($s, $_) use ($lazyDeferred) { global $console; $console->log(javaString("\n1秒后... 准备启动任务...")); // 手动启动任务 $lazyDeferred->start(); // 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 $lazyDeferred ->then(function ($innerScope, $result) { return $result; }) ->then(function ($innerScope, $result) { global $console; $console->log(javaString("懒加载任务完成,结果是: ") . $result); return $innerScope->resolve(null); }); return $s->resolve(null); });
# # 完整示例 6.4: 使用懒加载模式 # from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines # --- 样板代码 --- # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) _console.log("创建一个懒加载的 Deferred...") # 使用 CoroutineStarts.getLazy() 来设置启动模式 # Remember to use _async for scope.async lazyDeferred = scope._async(None, lambda starts: starts.getLazy(), lambda s: ( _console.log("懒加载的协程现在才真正开始执行!"), s.delay(1500).then(lambda innerScope, _: innerScope.resolve("懒加载的结果")) )[-1]) _console.log("Deferred 已创建,但内部代码尚未执行。") _console.log("任务状态: isActive=" + str(lazyDeferred.isActive()) + ", isCompleted=" + str(lazyDeferred.isCompleted())) scope.delay(1000).then(lambda sc, _: ( _console.log("\n1秒后... 准备启动任务..."), # 手动启动任务 lazyDeferred.start(), # 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 lazyDeferred .then(lambda i, result: result) .then(lambda s, result: ( _console.log("懒加载任务完成,结果是: " + str(result)), s.resolve(None) )[-1]) )[-1])
# encoding: utf-8 # # 完整示例 6.4: 使用懒加载模式 # # --- 样板代码 --- $threads.getMain().setBackground(true) scope = $coroutines.newScope(nil) $console.log("创建一个懒加载的 Deferred...") # 使用 CoroutineStarts.getLazy() 来设置启动模式 lazyDeferred = scope.async(nil, lambda { |starts| starts.getLazy() }) do |s| $console.log("懒加载的协程现在才真正开始执行!") s.delay(1500).then { |innerScope, _| innerScope.resolve("懒加载的结果") } end $console.log("Deferred 已创建,但内部代码尚未执行。") $console.log("任务状态: isActive=" + lazyDeferred.isActive().to_s + ", isCompleted=" + lazyDeferred.isCompleted().to_s) scope.delay(1000).then do |s, _| $console.log("\n1秒后... 准备启动任务...") # 手动启动任务 lazyDeferred.start() # 或者,如果你需要结果,可以直接调用 .then(),它们会自动触发启动 lazyDeferred .then(lambda { |innerScope, result| result }) .then do |innerScope, result| $console.log("懒加载任务完成,结果是: " + result) innerScope.resolve(nil) end end

超时(withTimeout 与 withTimeoutOrNull)

为异步操作设置超时是一个常见的需求。本库提供了两个便利的函数来处理这种情况。

  • scope.withTimeout(millis) : 在指定时间内运行代码块。如果超时,返回的 Deferred 会因 TimeoutCancellationException 而失败。

  • scope.withTimeoutOrNull(millis) : 行为类似,但超时后返回的 Deferred 会成功完成,其结果为 null,而不是抛出异常。

import com.m8test.script.GlobalVariables.* /* * 完整示例 7.1: 演示超时处理 */ // --- 样板代码 --- _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) // 案例 1: withTimeout,将会失败 _console.log("测试 withTimeout (预期会失败)...") scope.withTimeout(500) { // 这个任务需要 1 秒,但超时只有 500 毫秒 // 注意: withTimeout 的 block 是 CoroutineScope.() -> T,所以可以直接调用 delay delay(1000).then { innerScope, _ -> innerScope.resolve("这个结果永远不会返回") } }.then { s, r -> _console.log("withTimeout(预期会失败): 这个应该不会打印", r) s.resolve(null) }.onError { error -> _console.error("withTimeout(预期失败)成功捕获到超时异常") } // 案例 2: withTimeout,将会成功 scope.delay(2000).then { s1, _ -> _console.log("测试 withTimeout (预期会成功)...") // 这里使用了外部的 scope,也可以使用 s1 scope.withTimeout(500) { // 这个任务需要 100 毫秒,超时有 500 毫秒 delay(100).then { innerScope, u -> innerScope.resolve("这个结果会返回") } } }.then { s, r -> _console.log("withTimeout(预期会成功): 这个应该会打印", r) s.resolve(null) }.onError { error -> _console.error("成功捕获到超时异常: " + error) } // 案例 3: withTimeoutOrNull,将会返回 null scope.delay(3000).then { s, _ -> _console.log("\n测试 withTimeoutOrNull (预期返回 null)...") s.withTimeoutOrNull(500) { // 这里的 this 是新的 CoroutineScope delay(1000).then { innerS, u -> innerS.resolve("这个结果也永远不会返回") } } }.then { innerS, result -> val msg = if (result == null) "null (符合预期)" else result _console.log("withTimeoutOrNull(预期失败) 的结果是: " + msg) innerS.resolve(null) } // 案例 4: withTimeoutOrNull,会返回给定的数据 scope.delay(4000).then { s, _ -> _console.log("\n测试 withTimeoutOrNull (预期返回给定的数据)...") s.withTimeoutOrNull(500) { delay(100).then { innerS, u -> innerS.resolve("这个结果会返回") } } }.then { innerS, result -> val msg = if (result == null) "null (符合预期)" else result _console.log("withTimeoutOrNull(预期成功) 的结果是: " + msg) innerS.resolve(null) }
/* * 完整示例 7.1: 演示超时处理 */ // --- 样板代码 --- $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) // 案例 1: withTimeout,将会失败 $console.log("测试 withTimeout (预期会失败)...") scope.withTimeout(500, { s -> // 这个任务需要 1 秒,但超时只有 500 毫秒 return s.delay(1000).then({ innerScope, _ -> return innerScope.resolve("这个结果永远不会返回") }) }).then { s, r -> $console.log("withTimeout(预期会失败): 这个应该不会打印", r) return s.resolve(null) }.onError({ error -> $console.error("withTimeout(预期失败)成功捕获到超时异常") }) // 案例 2: withTimeout,将会成功 scope.delay(2000).then({ s1, _ -> $console.log("测试 withTimeout (预期会成功)...") return scope.withTimeout(500, { s -> // 这个任务需要 100 毫秒,超时有 500 毫秒 return s.delay(100).then({ innerScope, u -> return innerScope.resolve("这个结果会返回") }) }) }).then { s, r -> $console.log("withTimeout(预期会成功): 这个应该会打印", r) return s.resolve(null) }.onError({ error -> $console.error("成功捕获到超时异常: " + error.stackTraceToString()) }) // 案例 3: withTimeoutOrNull,将会返回 null scope.delay(3000).then({ s, _ -> $console.log("\n测试 withTimeoutOrNull (预期返回 null)...") return s.withTimeoutOrNull(500, { innerS -> return innerS.delay(1000).then({ s1, u -> return innerS.resolve("这个结果也永远不会返回") }) }) }).then({ innerS, result -> $console.log("withTimeoutOrNull(预期失败) 的结果是: " + (result == null ? "null (符合预期)" : result)) return innerS.resolve(null) }) // 案例 4: withTimeoutOrNull,会返回给定的数据 scope.delay(4000).then({ s, _ -> $console.log("\n测试 withTimeoutOrNull (预期返回给定的数据)...") return s.withTimeoutOrNull(500, { innerS -> return innerS.delay(100).then({ s1, u -> return innerS.resolve("这个结果会返回") }) }) }).then({ innerS, result -> $console.log("withTimeoutOrNull(预期成功) 的结果是: " + (result == null ? "null (符合预期)" : result)) return innerS.resolve(null) })
/* * 完整示例 7.1: 演示超时处理 */ // --- 样板代码 --- $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); // 案例 1: withTimeout,将会失败 $console.log("测试 withTimeout (预期会失败)..."); scope.withTimeout(500, s => { // 这个任务需要 1 秒,但超时只有 500 毫秒 return s.delay(1000).then((innerScope, _) => { return innerScope.resolve("这个结果永远不会返回"); }); }).then((s, r) => { $console.log("withTimeout(预期会失败): 这个应该不会打印", r); return s.resolve(null); }).onError(error => { $console.error("withTimeout(预期失败)成功捕获到超时异常"); }); // 案例 2: withTimeout,将会成功 scope.delay(2000).then((s1, _) => { $console.log("测试 withTimeout (预期会成功)..."); return scope.withTimeout(500, s => { // 这个任务需要 100 毫秒,超时有 500 毫秒 return s.delay(100).then((innerScope, u) => { return innerScope.resolve("这个结果会返回"); }); }); }).then((s, r) => { $console.log("withTimeout(预期会成功): 这个应该会打印", r); return s.resolve(null); }).onError(error => { $console.error("成功捕获到超时异常: " + error.stackTraceToString()); }); // 案例 3: withTimeoutOrNull,将会返回 null scope.delay(3000).then((s, _) => { $console.log("\n测试 withTimeoutOrNull (预期返回 null)..."); return s.withTimeoutOrNull(500, innerS => { return innerS.delay(1000).then((s1, u) => { return innerS.resolve("这个结果也永远不会返回"); }); }); }).then((innerS, result) => { $console.log("withTimeoutOrNull(预期失败) 的结果是: " + (result == null ? "null (符合预期)" : result)); return innerS.resolve(null); }); // 案例 4: withTimeoutOrNull,会返回给定的数据 scope.delay(4000).then((s, _) => { $console.log("\n测试 withTimeoutOrNull (预期返回给定的数据)..."); return s.withTimeoutOrNull(500, innerS => { return innerS.delay(100).then((s1, u) => { return innerS.resolve("这个结果会返回"); }); }); }).then((innerS, result) => { $console.log("withTimeoutOrNull(预期成功) 的结果是: " + (result == null ? "null (符合预期)" : result)); return innerS.resolve(null); });
--[[ * 完整示例 7.1: 演示超时处理 ]] -- --- 样板代码 --- _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) -- 案例 1: withTimeout,将会失败 _console:log("测试 withTimeout (预期会失败)...") scope:withTimeout(500, function(s) -- 这个任务需要 1 秒,但超时只有 500 毫秒 return s:delay(1000):_then(function(innerScope, _) return innerScope:resolve("这个结果永远不会返回") end) end):_then(function(s, r) _console:log("withTimeout(预期会失败): 这个应该不会打印", r) return s:resolve(nil) end):onError(function(error) _console:error("withTimeout(预期失败)成功捕获到超时异常") end) -- 案例 2: withTimeout,将会成功 scope:delay(2000):_then(function(s1, _) _console:log("测试 withTimeout (预期会成功)...") return scope:withTimeout(500, function(s) -- 这个任务需要 100 毫秒,超时有 500 毫秒 return s:delay(100):_then(function(innerScope, u) return innerScope:resolve("这个结果会返回") end) end) end):_then(function(s, r) _console:log("withTimeout(预期会成功): 这个应该会打印", r) return s:resolve(nil) end):onError(function(error) _console:error("成功捕获到超时异常: " .. error:stackTraceToString()) end) -- 案例 3: withTimeoutOrNull,将会返回 null scope:delay(3000):_then(function(s, _) _console:log("\n测试 withTimeoutOrNull (预期返回 null)...") return s:withTimeoutOrNull(500, function(innerS) return innerS:delay(1000):_then(function(s1, u) return innerS:resolve("这个结果也永远不会返回") end) end) end):_then(function(innerS, result) _console:log("withTimeoutOrNull(预期失败) 的结果是: " .. (result == nil and "null (符合预期)" or result)) return innerS:resolve(nil) end) -- 案例 4: withTimeoutOrNull,会返回给定的数据 scope:delay(4000):_then(function(s, _) _console:log("\n测试 withTimeoutOrNull (预期返回给定的数据)...") return s:withTimeoutOrNull(500, function(innerS) return innerS:delay(100):_then(function(s1, u) return innerS:resolve("这个结果会返回") end) end) end):_then(function(innerS, result) _console:log("withTimeoutOrNull(预期成功) 的结果是: " .. (result == nil and "null (符合预期)" or result)) return innerS:resolve(nil) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /* * 完整示例 7.1: 演示超时处理 */ // --- 样板代码 --- $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); // 案例 1: withTimeo<?php ///** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ //global $threads; ///** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ //global $coroutines; ///** @var m8test_java\com\m8test\script\core\api\console\Console $console */ //global $console; // ///* // * 完整示例 7.1: 演示超时处理 // */ // //// --- 样板代码 --- //$threads->getMain()->setBackground(true); //$scope = $coroutines->newScope(function ($context) { // $context->setDispatcher(function ($dispatchers) { // return $dispatchers->getScriptMain(); // }); //}); // //// 案例 1: withTimeout,将会失败 //$console->log(javaString("测试 withTimeout (预期会失败)...")); //$scope->withTimeout(500, function ($s) { // // 这个任务需要 1 秒,但超时只有 500 毫秒 // return $s->delay(1000)->then(function ($innerScope, $_) { // return $innerScope->resolve(javaString("这个结果永远不会返回")); // }); //})->then(function ($s, $r) { // global $console; // $console->log(javaString("withTimeout(预期会失败): 这个应该不会打印"), $r); // return $s->resolve(null); //})->onError(function ($error) { // global $console; // $console->error(javaString("withTimeout(预期失败)成功捕获到超时异常")); //}); // //// 案例 2: withTimeout,将会成功 //$scope->delay(2000)->then(function ($s1, $_) use ($scope) { // global $console; // $console->log(javaString("测试 withTimeout (预期会成功)...")); // return $scope->withTimeout(500, function ($s) { // // 这个任务需要 100 毫秒,超时有 500 毫秒 // return $s->delay(100)->then(function ($innerScope, $u) { // return $innerScope->resolve(javaString("这个结果会返回")); // }); // }); //})->then(function ($s, $r) { // global $console; // $console->log(javaString("withTimeout(预期会成功): 这个应该会打印"), $r); // return $s->resolve(null); //})->onError(function ($error) { // global $console; // $console->error(javaString("成功捕获到超时异常: " . $error->stackTraceToString())); //}); // //// 案例 3: withTimeoutOrNull,将会返回 null //$scope->delay(3000)->then(function ($s, $_) { // global $console; // $console->log(javaString("\n测试 withTimeoutOrNull (预期返回 null)...")); // return $s->withTimeoutOrNull(500, function ($innerS) { // return $innerS->delay(1000)->then(function ($s1, $u) use ($innerS) { // return $innerS->resolve(javaString("这个结果也永远不会返回")); // }); // }); //})->then(function ($innerS, $result) { // global $console; // $console->log(javaString("withTimeoutOrNull(预期失败) 的结果是: " . ($result == null ? javaString("null (符合预期)") : $result))); // return $innerS->resolve(null); //}); // //// 案例 4: withTimeoutOrNull,会返回给定的数据 //$scope->delay(4000)->then(function ($s, $_) { // global $console; // $console->log(javaString("\n测试 withTimeoutOrNull (预期返回给定的数据)...")); // return $s->withTimeoutOrNull(500, function ($innerS) { // return $innerS->delay(100)->then(function ($s1, $u) use ($innerS) { // return $innerS->resolve(javaString("这个结果会返回")); // }); // }); //})->then(function ($innerS, $result) { // global $console; // $console->log(javaString("withTimeoutOrNull(预期成功) 的结果是: " . ($result == null ? javaString("null (符合预期)") : $result))); // return $innerS->resolve(null); //});ut,将会失败 $console->log(javaString("测试 withTimeout (预期会失败)...")); $scope->withTimeout(500, function ($s) { // 这个任务需要 1 秒,但超时只有 500 毫秒 return $s->delay(1000)->then(function ($innerScope, $_) { return $innerScope->resolve(javaString("这个结果永远不会返回")); }); }) ->then(function ($s, $r) { global $console; $console->log(javaString("这个应该不会打印")); }) ->onError(function ($error) { global $console; $console->error(javaString("成功捕获到超时异常: ") . $error->getOrigin()->getClass()->getName()); }); // 案例 2: withTimeoutOrNull,将会返回 null $scope->delay(1500)->then(function ($s, $_) { global $console; $console->log(javaString("\n测试 withTimeoutOrNull (预期返回 null)...")); return $s->withTimeoutOrNull(500, function ($innerS) { return $innerS->delay(1000)->then(function ($s1, $u) use ($innerS) { return $innerS->resolve(javaString("这个结果也永远不会返回")); }); })->then(function ($innerS, $result) { global $console; $console->log(javaString("withTimeoutOrNull 的结果是: ") . ($result == null ? javaString("null (符合预期)") : $result)); return $innerS->resolve(null); }); });
# # 完整示例 7.1: 演示超时处理 # # --- 样板代码 --- # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _console _threads.getMain().setBackground(True) # 使用您指定的 scope 创建方式 scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) # 案例 1: withTimeout,将会失败 _console.log("测试 withTimeout (预期会失败)...") scope.withTimeout(500, lambda s: # 这个任务需要 1 秒,但超时只有 500 毫秒 s.delay(1000).then(lambda innerScope, _: innerScope.resolve("这个结果永远不会返回") ) ).then(lambda s, r: ( _console.log("withTimeout(预期会失败): 这个应该不会打印", r), s.resolve(None) )[-1]).onError(lambda error: _console.error("withTimeout(预期失败)成功捕获到超时异常") ) # 案例 2: withTimeout,将会成功 scope.delay(2000).then(lambda s1, _: ( _console.log("测试 withTimeout (预期会成功)..."), # 此 lambda 只有一个返回表达式,所以直接返回 scope.withTimeout(500, lambda s: # 这个任务需要 100 毫秒,超时有 500 毫秒 s.delay(100).then(lambda innerScope, u: innerScope.resolve("这个结果会返回") ) ) )[-1]).then(lambda s, r: ( _console.log("withTimeout(预期会成功): 这个应该会打印", r), s.resolve(None) )[-1]).onError(lambda error: _console.error("成功捕获到超时异常: " + str(error.stackTraceToString())) ) # 案例 3: withTimeoutOrNull,将会返回 null scope.delay(3000).then(lambda s, _: ( _console.log("\n测试 withTimeoutOrNull (预期返回 null)..."), s.withTimeoutOrNull(500, lambda innerS: innerS.delay(1000).then(lambda s1, u: innerS.resolve("这个结果也永远不会返回") ) ) )[-1]).then(lambda innerS, result: ( # Groovy的 (result == null ? "..." : result) 转换为Python的条件表达式 _console.log("withTimeoutOrNull(预期失败) 的结果是: " + ("null (符合预期)" if result is None else str(result))), innerS.resolve(None) )[-1]) # 案例 4: withTimeoutOrNull,会返回给定的数据 scope.delay(4000).then(lambda s, _: ( _console.log("\n测试 withTimeoutOrNull (预期返回给定的数据)..."), s.withTimeoutOrNull(500, lambda innerS: innerS.delay(100).then(lambda s1, u: innerS.resolve("这个结果会返回") ) ) )[-1]).then(lambda innerS, result: ( _console.log("withTimeoutOrNull(预期成功) 的结果是: " + ("null (符合预期)" if result is None else str(result))), innerS.resolve(None) )[-1])
# encoding: utf-8 # 如果源代码中包含中文,那么就需要添加上面的编码语句 # # 完整示例 7.1: 演示超时处理 # # --- 样板代码 --- $threads.getMain().setBackground(true) scope = $coroutines.newScope(nil) # 案例 1: withTimeout,将会失败 $console.log("测试 withTimeout (预期会失败)...") scope.withTimeout(500) do |s| # 这个任务需要 1 秒,但超时只有 500 毫秒 s.delay(1000).then do |innerScope, _it| innerScope.resolve("这个结果永远不会返回") end end.then do |s, r| $console.log("withTimeout(预期会失败): 这个应该不会打印", r) s.resolve(nil) end.onError do |error| $console.error("withTimeout(预期失败)成功捕获到超时异常") end # 案例 2: withTimeout,将会成功 scope.delay(2000).then do |s1, _it| $console.log("测试 withTimeout (预期会成功)...") scope.withTimeout(500) do |s| # 这个任务需要 100 毫秒,超时有 500 毫秒 s.delay(100).then do |innerScope, u| innerScope.resolve("这个结果会返回") end end end.then do |s, r| $console.log("withTimeout(预期会成功): 这个应该会打印", r) s.resolve(nil) end.onError do |error| $console.error("成功捕获到超时异常: " + error.stackTraceToString()) end # 案例 3: withTimeoutOrNull,将会返回 null scope.delay(3000).then do |s, _it| $console.log("\n测试 withTimeoutOrNull (预期返回 null)...") s.withTimeoutOrNull(500) do |innerS| innerS.delay(1000).then do |s1, u| innerS.resolve("这个结果也永远不会返回") end end end.then do |innerS, result| $console.log("withTimeoutOrNull(预期失败) 的结果是: " + (result.nil? ? "null (符合预期)" : result.to_s)) innerS.resolve(nil) end # 案例 4: withTimeoutOrNull,会返回给定的数据 scope.delay(4000).then do |s, _it| $console.log("\n测试 withTimeoutOrNull (预期返回给定的数据)...") s.withTimeoutOrNull(500) do |innerS| innerS.delay(100).then do |s1, u| innerS.resolve("这个结果会返回") end end end.then do |innerS, result| $console.log("withTimeoutOrNull(预期成功) 的结果是: " + (result.nil? ? "null (符合预期)" : result.to_s)) innerS.resolve(nil) end

异常处理

  • deferred.onError(...): 异步错误处理。它是 Deferred 链的一部分,用于捕获异步流程中发生的任何异常(包括上游 Deferred 的失败)。这是处理异步错误的首选方式。

  • $exceptions.tryCatch : 同步错误处理。它用于 launch 或 async 代码块内部,捕获那些在协程调度和执行的同步部分可能抛出的异常。例如,解析 JSON、访问一个可能为 null 的属性等。

对于 launch 启动的、未被 try-catch 包围的协程,如果发生异常,异常会向上“冒泡”。你可以通过在创建 CoroutineScope 时提供一个 exceptionHandler 来捕获这些“未被捕获”的异常。

import com.m8test.script.GlobalVariables.* /* * 完整示例 7.3: 使用作用域级别的异常处理器 */ // --- 样板代码 --- _threads.getMain().setBackground(true) // 创建一个带有自定义异常处理器的作用域 val scopeWithHandler = _coroutines.newScope { setExceptionHandler { ctx, error -> _console.error("[作用域异常捕获器]: 在协程 '${ctx.getName()}' 中捕获到未处理的异常 -> " + error.getMessage()) } // 设置 SupervisorJob 这样子 job 失败不会取消其他子 job setJob(newSupervisorJob(null)) } // 案例 1: launch 中的异常会被捕获 // 修正:移除了 lambda 参数,直接使用 receiver (this) 调用 setName 和 delay scopeWithHandler.launch({ setName("会失败的Launch任务") }, null) { delay(200).then<Unit> { innerScope, _ -> throw RuntimeException("来自 launch 的错误") } } // 案例 2: async 中的异常不会被捕获,而是由 onError 处理 // 修正:移除了 lambda 参数,直接使用 receiver (this) 调用 setName 和 delay val failedAsync = scopeWithHandler.async({ setName("会失败的Async任务") }, null) { delay(400).then<Unit> { innerScope, _ -> throw RuntimeException("来自 async 的错误") } } failedAsync.onError { error -> _console.log("[onError]: 成功捕获到 async 的错误 -> " + error.getMessage()) }
/* * 完整示例 7.3: 使用作用域级别的异常处理器 */ // --- 样板代码 --- $threads.getMain().setBackground(true) // 创建一个带有自定义异常处理器的作用域 def scopeWithHandler = $coroutines.newScope({ context -> context.setExceptionHandler({ ctx, error -> $console.error("[作用域异常捕获器]: 在协程 '${ctx.getName()}' 中捕获到未处理的异常 -> " + error.getMessage()) }) // 设置 SupervisorJob 这样子 job 失败不会取消其他子 job context.setJob(context.newSupervisorJob(null)) }) // 案例 1: launch 中的异常会被捕获 scopeWithHandler.launch({ ctx -> ctx.setName("会失败的Launch任务") }, null, { s -> s.delay(200).then({ innerScope, _ -> throw new RuntimeException("来自 launch 的错误") }) }) // 案例 2: async 中的异常不会被捕获,而是由 onError 处理 def failedAsync = scopeWithHandler.async({ ctx -> ctx.setName("会失败的Async任务") }, null, { s -> s.delay(400).then({ innerScope, _ -> throw new RuntimeException("来自 async 的错误") }) }) failedAsync.onError({ error -> $console.log("[onError]: 成功捕获到 async 的错误 -> " + error.getMessage()) })
/* * 完整示例 7.3: 使用作用域级别的异常处理器 */ // --- 样板代码 --- $threads.getMain().setBackground(true); // 创建一个带有自定义异常处理器的作用域 const scopeWithHandler = $coroutines.newScope(context => { context.setExceptionHandler((ctx, error) => { $console.error(`[作用域异常捕获器]: 在协程 '${ctx.getName()}' 中捕获到未处理的异常 -> ${error.getMessage()}`); }); // 设置 SupervisorJob 这样子 job 失败不会取消其他子 job context.setJob(context.newSupervisorJob(null)); }); // 案例 1: launch 中的异常会被捕获 scopeWithHandler.launch(ctx => ctx.setName("会失败的Launch任务"), null, s => { s.delay(200).then((innerScope, _) => { throw new Error("来自 launch 的错误"); }); }); // 案例 2: async 中的异常不会被捕获,而是由 onError 处理 const failedAsync = scopeWithHandler.async(ctx => ctx.setName("会失败的Async任务"), null, s => { return s.delay(400).then((innerScope, _) => { throw new Error("来自 async 的错误"); }); }); failedAsync.onError(error => { $console.log("[onError]: 成功捕获到 async 的错误 -> " + error.getMessage()); });
--[[ * 完整示例 7.3: 使用作用域级别的异常处理器 ]] -- --- 样板代码 --- _threads:getMain():setBackground(true) -- 创建一个带有自定义异常处理器的作用域 local scopeWithHandler = _coroutines:newScope(function(context) context:setExceptionHandler(function(ctx, error) _console:error("[作用域异常捕获器]: 在协程 '" .. ctx:getName() .. "' 中捕获到未处理的异常 -> " .. error:getMessage()) end) -- 设置 SupervisorJob 这样子 job 失败不会取消其他子 job context:setJob(context:newSupervisorJob(nil)) end) -- 案例 1: launch 中的异常会被捕获 scopeWithHandler:launch(function(ctx) ctx:setName("会失败的Launch任务") end, nil, function(s) s:delay(200):_then(function(innerScope, _) error("来自 launch 的错误") end) end) -- 案例 2: async 中的异常不会被捕获,而是由 onError 处理 local failedAsync = scopeWithHandler:async(function(ctx) ctx:setName("会失败的Async任务") end, nil, function(s) return s:delay(400):_then(function(innerScope, _) error("来自 async 的错误") end) end) failedAsync:onError(function(error) _console:log("[onError]: 成功捕获到 async 的错误 -> " .. error:getMessage()) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /* * 完整示例 7.3: 使用作用域级别的异常处理器 */ // --- 样板代码 --- $threads->getMain()->setBackground(true); // 创建一个带有自定义异常处理器的作用域 $scopeWithHandler = $coroutines->newScope(function ($context) { global $console; $context->setExceptionHandler(function ($ctx, $error) use ($console) { $console->error(javaString("[作用域异常捕获器]: 在协程 '") . $ctx->getName() . javaString("' 中捕获到未处理的异常 -> ") . $error->getMessage()); }); // 设置 SupervisorJob 这样子 job 失败不会取消其他子 job $context->setJob($context->newSupervisorJob(null)); $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); // 案例 1: launch 中的异常会被捕获 $scopeWithHandler->launch(function ($ctx) { $ctx->setName(javaString("会失败的Launch任务")); }, null, function ($s) { $s->delay(200)->then(function ($innerScope, $_) { global $exceptions; return $innerScope->reject($exceptions->newThrowable(function ($eb) { $eb->setMessageAndClassName(javaString("来自 launch 的错误"), null); })); }); }); // 案例 2: async 中的异常不会被捕获,而是由 onError 处理 $failedAsync = $scopeWithHandler->async(function ($ctx) { $ctx->setName(javaString("会失败的Async任务")); }, null, function ($s) { return $s->delay(400)->then(function ($innerScope, $_) { global $exceptions; return $innerScope->reject($exceptions->newThrowable(function ($eb) { $eb->setMessageAndClassName(javaString("来自 async 的错误"), null); })); }); }); $failedAsync->onError(function ($error) { global $console; $console->log(javaString("[onError]: 成功捕获到 async 的错误 -> ") . $error->getMessage()); });
# # 完整示例 7.3: 使用作用域级别的异常处理器 # from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _exceptions # --- 样板代码 --- # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads _threads.getMain().setBackground(True) # 创建一个带有自定义异常处理器的作用域 scopeWithHandler = _coroutines.newScope(lambda context: ( context.setExceptionHandler(lambda ctx, error: _console.error( "[作用域异常捕获器]: 在协程 '{}' 中捕获到未处理的异常 -> {}".format(ctx.getName(), error.getMessage())) ), # 设置 SupervisorJob 这样子 job 失败不会取消其他子 job context.setJob(context.newSupervisorJob(None)), context.setDispatcher(lambda dispatchers: dispatchers.getScriptMain()) )) # 案例 1: launch 中的异常会被捕获 scopeWithHandler.launch(lambda ctx: ctx.setName("会失败的Launch任务"), None, lambda s: ( s.delay(200).then(lambda innerScope, _: innerScope.reject(_exceptions.newThrowable(lambda builder: builder.setMessageAndClassName("来自 launch 的错误", "java.lang.RuntimeException") ) )) )) # 案例 2: async 中的异常不会被捕获,而是由 onError 处理 failedAsync = scopeWithHandler._async(lambda ctx: ctx.setName("会失败的Async任务"), None, lambda s: s.delay(400).then(lambda innerScope, _: innerScope.reject(_exceptions.newThrowable(lambda builder: builder.setMessageAndClassName("来自 async 的错误", "java.lang.RuntimeException") )) ) ) failedAsync.onError(lambda error: ( _console.log("[onError]: 成功捕获到 async 的错误 -> " + str(error.getMessage())) ))
# encoding: utf-8 # # 完整示例 7.3: 使用作用域级别的异常处理器 # # --- 样板代码 --- $threads.getMain().setBackground(true) # 创建一个带有自定义异常处理器的作用域 scopeWithHandler = $coroutines.newScope do |context| context.setExceptionHandler do |ctx, error| $console.error("[作用域异常捕获器]: 在协程 '#{ctx.getName()}' 中捕获到未处理的异常 -> " + error.getMessage()) end # 设置 SupervisorJob 这样子 job 失败不会取消其他子 job context.setJob(context.newSupervisorJob(nil)) end # 案例 1: launch 中的异常会被捕获 scopeWithHandler.launch(lambda { |ctx| ctx.setName("会失败的Launch任务") }, nil) do |s| s.delay(200).then do |innerScope, _| raise RuntimeException.new("来自 launch 的错误") end end # 案例 2: async 中的异常不会被捕获,而是由 onError 处理 failedAsync = scopeWithHandler.async(lambda { |ctx| ctx.setName("会失败的Async任务") }, nil) do |s| s.delay(400).then do |innerScope, _| raise RuntimeException.new("来自 async 的错误") end end failedAsync.onError do |error| $console.log("[onError]: 成功捕获到 async 的错误 -> " + error.getMessage()) end

适配回调式 api

许多库(特别是旧的 Java 库)都使用回调风格的异步 API。scope.cancellableDeferred 是一个强大的桥梁,可以将这些回调无缝转换为现代的 Deferred 对象。

import com.m8test.script.GlobalVariables.* /* * 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred */ // --- 样板代码 --- _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) // 使用 cancellableDeferred 进行包装 val modernDeferred = scope.cancellableDeferred { continuation -> _console.log("正在通过 cancellableDeferred 调用旧的回调式 API...") _threads.getMain().getTimer().setTimeout({ continuation.resume("M8Test", null) }, 5000) } // 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred.then { s, data -> _console.log("成功将回调转换为 Deferred!结果: " + data) s.resolve(null) }.onError { error -> _console.error("从回调转换的 Deferred 失败了: " + error.getMessage()) }
/* * 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred */ // --- 样板代码 --- $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) // 使用 cancellableDeferred 进行包装 def modernDeferred = scope.cancellableDeferred({ continuation -> $console.log("正在通过 cancellableDeferred 调用旧的回调式 API...") $threads.getMain().getTimer().setTimeout({ continuation.resume("M8Test", null) }, 5000) }) // 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred.then({ s, data -> $console.log("成功将回调转换为 Deferred!结果: " + data) s.resolve(null) }).onError({ error -> $console.error("从回调转换的 Deferred 失败了: " + error.getMessage()) })
/* * 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred */ // --- 样板代码 --- $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); // 使用 cancellableDeferred 进行包装 const modernDeferred = scope.cancellableDeferred(continuation => { $console.log("正在通过 cancellableDeferred 调用旧的回调式 API..."); $threads.getMain().getTimer().setTimeout(() => { continuation.resume("M8Test", null); }, 5000); }); // 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred.then((s, data) => { $console.log("成功将回调转换为 Deferred!结果: " + data); return s.resolve(null); }).onError(error => { $console.error("从回调转换的 Deferred 失败了: " + error.getMessage()); });
--[[ * 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred ]] -- --- 样板代码 --- _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) -- 使用 cancellableDeferred 进行包装 local modernDeferred = scope:cancellableDeferred(function(continuation) _console:log("正在通过 cancellableDeferred 调用旧的回调式 API...") _threads:getMain():getTimer():setTimeout(function() continuation:resume("M8Test", nil) end, 5000) end) -- 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred:_then(function(s, data) _console:log("成功将回调转换为 Deferred!结果: " .. data) return s:resolve(nil) end):onError(function(error) _console:error("从回调转换的 Deferred 失败了: " .. error:getMessage()) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /* * 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred */ // --- 样板代码 --- $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); // 使用 cancellableDeferred 进行包装 $modernDeferred = $scope->cancellableDeferred(function ($continuation) { global $console, $threads; $console->log(javaString("正在通过 cancellableDeferred 调用旧的回调式 API...")); $threads->getMain()->getTimer()->setTimeout(function() use ($continuation) { $continuation->resume(javaString("M8Test"), null); }, 5000); }); // 现在你可以像使用任何其他 Deferred 一样使用它了! $modernDeferred->then(function ($s, $data) { global $console; $console->log(javaString("成功将回调转换为 Deferred!结果: ") . $data); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("从回调转换的 Deferred 失败了: ") . $error->getMessage()); });
# # 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred # # --- 样板代码 --- # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _console _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) # 使用 cancellableDeferred 进行包装 modernDeferred = scope.cancellableDeferred(lambda continuation: ( _console.log("正在通过 cancellableDeferred 调用旧的回调式 API..."), _threads.getMain().getTimer().setTimeout(lambda _: ( continuation.resume("M8Test", None) ), 5000) )) # 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred.then(lambda s, data: ( _console.log("成功将回调转换为 Deferred!结果: " + str(data)), s.resolve(None) )[-1]).onError(lambda error: ( _console.error("从回调转换的 Deferred 失败了: " + str(error.getMessage())) ))
# encoding: utf-8 # # 完整示例 8.1: 将一个虚构的回调函数转换为 Deferred # # --- 样板代码 --- $threads.getMain().setBackground(true) scope = $coroutines.newScope(nil) # 使用 cancellableDeferred 进行包装 modernDeferred = scope.cancellableDeferred do |continuation| $console.log("正在通过 cancellableDeferred 调用旧的回调式 API...") $threads.getMain().getTimer().setTimeout(lambda { |p| continuation.resume("M8Test", nil) }, 5000) end # 现在你可以像使用任何其他 Deferred 一样使用它了! modernDeferred.then do |s, data| $console.log("成功将回调转换为 Deferred!结果: " + data) s.resolve(nil) end.onError do |error| $console.error("从回调转换的 Deferred 失败了: " + error.getMessage()) end
09 December 2025