入门
异步编程模式
这是本库最最重要的概念。所有异步操作(如 delay, async)都会立即返回一个 Deferred 对象,而不会暂停代码执行。任何需要在该异步操作完成后执行的逻辑,都必须通过 .then() 方法链接到 Deferred 对象上。
import com.m8test.script.GlobalVariables.*
_threads.getMain().setBackground(true)
val scope = _coroutines.newScope(null)
// ----------------- ❌ 错误示范:同步思维 -----------------
// 这种写法是无效的,因为 delay 不会阻塞代码
// 修复:移除 lambda 参数 aScope,直接使用 implicit this 调用 delay
scope.launch(null, null) {
delay(1000)
_console.log("这行日志会立刻打印,而不是在1秒后!")
}
// ----------------- ✅ 正确示范:异步链式思维 -----------------
// 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
// .then 的回调是 (CoroutineScope, T) -> Deferred<R>,需要参数,所以这里是对的
scope.delay(1000).then { aScope, result ->
_console.log("这行日志会在1秒后正确打印。")
// then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
aScope.resolve(null)
}
$threads.getMain().setBackground(true)
def scope = $coroutines.newScope(null)
// ----------------- ❌ 错误示范:同步思维 -----------------
// 这种写法是无效的,因为 delay 不会阻塞代码
scope.launch(null, null, { aScope ->
aScope.delay(1000)
$console.log("这行日志会立刻打印,而不是在1秒后!")
})
// ----------------- ✅ 正确示范:异步链式思维 -----------------
// 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
scope.delay(1000).then({ aScope, result ->
$console.log("这行日志会在1秒后正确打印。")
// then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
aScope.resolve(null)
})
$threads.getMain().setBackground(true);
const scope = $coroutines.newScope(null);
// ----------------- ❌ 错误示范:同步思维 -----------------
// 这种写法是无效的,因为 delay 不会阻塞代码
scope.launch(null, null, aScope => {
aScope.delay(1000);
$console.log("这行日志会立刻打印,而不是在1秒后!");
});
// ----------------- ✅ 正确示范:异步链式思维 -----------------
// 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
scope.delay(1000).then((aScope, result) => {
$console.log("这行日志会在1秒后正确打印。");
// then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
return aScope.resolve(null);
});
_threads:getMain():setBackground(true)
local scope = _coroutines:newScope(nil)
-- ----------------- ❌ 错误示范:同步思维 -----------------
-- 这种写法是无效的,因为 delay 不会阻塞代码
scope:launch(nil, nil, function(aScope)
aScope:delay(1000)
_console:log("这行日志会立刻打印,而不是在1秒后!")
end)
-- ----------------- ✅ 正确示范:异步链式思维 -----------------
-- 所有依赖于前一个异步操作结果的代码,都必须放入 ._then() 闭包中
scope:delay(1000):_then(function(aScope, result)
_console:log("这行日志会在1秒后正确打印。")
-- _then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
return aScope: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;
$threads->getMain()->setBackground(true);
$scope = $coroutines->newScope(function ($context) {
$context->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
// ----------------- ❌ 错误示范:同步思维 -----------------
// 这种写法是无效的,因为 delay 不会阻塞代码
$scope->launch(null, null, function ($aScope) {
global $console;
$aScope->delay(1000);
$console->log(javaString("这行日志会立刻打印,而不是在1秒后!"));
});
// ----------------- ✅ 正确示范:异步链式思维 -----------------
// 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
$scope->delay(1000)->then(function ($aScope, $result) {
global $console;
$console->log(javaString("这行日志会在1秒后正确打印。"));
// then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
return $aScope->resolve(null);
});
# 导入所需的全局变量
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)
# 被转换为 Python 的嵌套 lambda 表达式
scope = _coroutines.newScope(lambda it:
it.setDispatcher(lambda dispatchers: dispatchers.getScriptMain())
)
# ----------------- ❌ 错误示范:同步思维 -----------------
# 这种写法是无效的,因为 delay 不会阻塞代码
scope.launch(None, None, lambda aScope: (
aScope.delay(1000),
_console.log("这行日志会立刻打印,而不是在1秒后!")
))
# ----------------- ✅ 正确示范:异步链式思维 -----------------
# 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
scope.delay(1000).then(lambda aScope, result: (
_console.log("这行日志会在1秒后正确打印。"),
# then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
aScope.resolve(None)
)[-1])
# encoding: utf-8
$threads.getMain().setBackground(true)
scope = $coroutines.newScope(nil)
# ----------------- ❌ 错误示范:同步思维 -----------------
# 这种写法是无效的,因为 delay 不会阻塞代码
scope.launch(nil, nil) do |aScope|
aScope.delay(1000)
$console.log("这行日志会立刻打印,而不是在1秒后!")
end
# ----------------- ✅ 正确示范:异步链式思维 -----------------
# 所有依赖于前一个异步操作结果的代码,都必须放入 .then() 闭包中
scope.delay(1000).then do |aScope, result|
$console.log("这行日志会在1秒后正确打印。")
# then 闭包必须返回一个新的 Deferred,即使没有有意义的结果
aScope.resolve(nil)
end
“即发即忘”的异步任务
当你需要执行一个后台任务,但又不关心它的返回值时(例如,发送一条日志、更新一个文件),scope.launch() 是最佳选择。
import com.m8test.script.GlobalVariables.*
/*
* 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
*/
// --- 样板代码 ---
_threads.getMain().setBackground(true)
val scope = _coroutines.newScope(null)
_console.log("在 launch 调用之前。")
// 使用 scope.launch() 启动一个“即发即忘”的协程
// 修复:移除 lambda 参数,直接调用 delay
scope.launch(null, null) {
_console.log("协程已经开始执行...")
// 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
delay(1500).then { innerScope, _ ->
// 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
_console.log("延时结束,协程任务完成!")
// 最佳实践:then 闭包必须返回一个 Deferred。
// 对于没有实际返回值的操作,使用 innerScope.resolve(null) 来创建一个已完成的 Deferred。
innerScope.resolve(null)
}
}
_console.log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。")
/*
* 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true)
def scope = $coroutines.newScope(null)
$console.log("在 launch 调用之前。")
// 使用 scope.launch() 启动一个“即发即忘”的协程
scope.launch(null, null, { coroutineScope ->
$console.log("协程已经开始执行...")
// 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
coroutineScope.delay(1500).then({ innerScope, _ ->
// 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
$console.log("延时结束,协程任务完成!")
// 最佳实践:then 闭包必须返回一个 Deferred。
// 对于没有实际返回值的操作,使用 innerScope.resolve(null) 来创建一个已完成的 Deferred。
innerScope.resolve(null)
})
})
$console.log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。")
/*
* 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true);
const scope = $coroutines.newScope(null);
$console.log("在 launch 调用之前。");
// 使用 scope.launch() 启动一个“即发即忘”的协程
scope.launch(null, null, coroutineScope => {
$console.log("协程已经开始执行...");
// 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
coroutineScope.delay(1500).then((innerScope, _) => {
// 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
$console.log("延时结束,协程任务完成!");
// 最佳实践:then 闭包必须返回一个 Deferred。
// 对于没有实际返回值的操作,使用 innerScope.resolve(null) 来创建一个已完成的 Deferred。
return innerScope.resolve(null);
});
});
$console.log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。");
--[[
* 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
]]
-- --- 样板代码 ---
_threads:getMain():setBackground(true)
local scope = _coroutines:newScope(nil)
_console:log("在 launch 调用之前。")
-- 使用 scope:launch() 启动一个“即发即忘”的协程
scope:launch(nil, nil, function(coroutineScope)
_console:log("协程已经开始执行...")
-- 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
coroutineScope:delay(1500):_then(function(innerScope, _)
-- 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
_console:log("延时结束,协程任务完成!")
-- 最佳实践:_then 闭包必须返回一个 Deferred。
-- 对于没有实际返回值的操作,使用 innerScope:resolve(nil) 来创建一个已完成的 Deferred。
return innerScope:resolve(nil)
end)
end)
_console:log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。")
<?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;
/*
* 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
*/
// --- 样板代码 ---
$threads->getMain()->setBackground(true);
$scope = $coroutines->newScope(function ($context) {
$context->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
$console->log(javaString("在 launch 调用之前。"));
// 使用 scope.launch() 启动一个“即发即忘”的协程
$scope->launch(null, null, function ($coroutineScope) {
global $console;
$console->log(javaString("协程已经开始执行..."));
// 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
$coroutineScope->delay(1500)->then(function ($innerScope, $_) {
global $console;
// 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
$console->log(javaString("延时结束,协程任务完成!"));
// 最佳实践:then 闭包必须返回一个 Deferred。
// 对于没有实际返回值的操作,使用 innerScope.resolve(null) 来创建一个已完成的 Deferred。
return $innerScope->resolve(null);
});
});
$console->log(javaString("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。"));
#
# 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
#
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 创建方式
scope = _coroutines.newScope(lambda it:
it.setDispatcher(lambda dispatchers: dispatchers.getScriptMain())
)
_console.log("在 launch 调用之前。")
# 使用 scope.launch() 启动一个“即发即忘”的协程
scope.launch(None, None, lambda coroutineScope: (
_console.log("协程已经开始执行..."),
# 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
coroutineScope.delay(1500).then(lambda innerScope, _: (
# 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
_console.log("延时结束,协程任务完成!"),
# 最佳实践:then 闭包必须返回一个 Deferred。
# 对于没有实际返回值的操作,使用 innerScope.resolve(null) 来创建一个已完成的 Deferred。
innerScope.resolve(None)
)[-1])
))
_console.log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。")
# encoding: utf-8
#
# 完整示例 2.1: 使用 launch 执行一个简单的后台延时任务
#
# --- 样板代码 ---
$threads.getMain().setBackground(true)
scope = $coroutines.newScope(nil)
$console.log("在 launch 调用之前。")
# 使用 scope.launch() 启动一个“即发即忘”的协程
scope.launch(nil, nil) do |coroutineScope|
$console.log("协程已经开始执行...")
# 调用作用域提供的非阻塞 delay 函数,它会立即返回一个 Deferred<Unit>
# Ruby 中 _ 也是有效的参数名,表示不关心该参数
coroutineScope.delay(1500).then do |innerScope, _|
# 这个闭包内的代码,将在1.5秒延迟结束后被调度执行
$console.log("延时结束,协程任务完成!")
# 最佳实践:then 闭包必须返回一个 Deferred。
# 对于没有实际返回值的操作,使用 innerScope.resolve(nil) 来创建一个已完成的 Deferred。
innerScope.resolve(nil)
end
end
$console.log("在 launch 调用之后。注意这行日志会立刻打印,脚本不会在此处等待。")
获取结果:async 与 Deferred
当你的异步任务需要计算并返回一个结果时,使用 scope.async()。它会返回一个 Deferred 对象,T 是你期望的结果类型。Deferred 是一个对未来结果的承诺。
Deferred 的核心 API
.then({ scope, result -> ... }): 当 Deferred 成功完成时调用。result 是上一个异步任务的返回值。此闭包必须返回一个新的 Deferred 对象。
.onError({ error -> ... }): 当 Deferred 失败时调用。error 是导致失败的异常对象。
.onComplete(): 无论成功还是失败,在 Deferred 完成时总会调用。常用于资源清理。
获取简单的异步结果
import com.m8test.script.GlobalVariables.*
/*
* 完整示例 3.2: 使用 async 获取一个模拟的用户数据
*/
// --- 样板代码 ---
_threads.getMain().setBackground(true)
val scope = _coroutines.newScope(null)
_console.log("准备开始异步获取用户数据...")
// scope.async 启动一个会返回结果的协程
// 修复:移除 lambda 参数
val userDeferred = scope.async(null, null) {
// async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
// 这个 Map 将成为 userDeferred 的未来结果
mapOf("id" to "user-001", "name" to "张三")
}
// 链接 .then 来处理成功的结果
userDeferred.then { innerScope, user ->
// Kotlin 中 Map 取值需要用 [] 或 get
_console.log("成功获取到用户数据!用户名: " + user["name"])
// 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
val welcomeMessage = "欢迎您," + user["name"]
innerScope.resolve(welcomeMessage)
}.then { innerScope, message ->
_console.log("处理后的消息: " + message)
// 链条的末端也需要返回一个 Deferred
innerScope.resolve(null)
}.onError { error ->
// 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
_console.error("获取用户数据时发生错误: " + error.getMessage())
}
/*
* 完整示例 3.2: 使用 async 获取一个模拟的用户数据
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true)
def scope = $coroutines.newScope(null)
$console.log("准备开始异步获取用户数据...")
// scope.async 启动一个会返回结果的协程
def userDeferred = scope.async(null, null, { coroutineScope ->
// async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
// 这个 Map 将成为 userDeferred 的未来结果
[id: "user-001", name: "张三"]
})
// 链接 .then 来处理成功的结果
userDeferred.then({ innerScope, user ->
$console.log("成功获取到用户数据!用户名: " + user.name)
// 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
def welcomeMessage = "欢迎您," + user.name
innerScope.resolve(welcomeMessage)
}).then({ innerScope, message ->
$console.log("处理后的消息: " + message)
// 链条的末端也需要返回一个 Deferred
innerScope.resolve(null)
}).onError({ error ->
// 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
$console.error("获取用户数据时发生错误: " + error.getMessage())
})
/*
* 完整示例 3.2: 使用 async 获取一个模拟的用户数据
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true);
const scope = $coroutines.newScope(null);
$console.log("准备开始异步获取用户数据...");
// scope.async 启动一个会返回结果的协程
const userDeferred = scope.async(null, null, coroutineScope => {
// async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
// 这个 Map 将成为 userDeferred 的未来结果
return {id: "user-001", name: "张三"};
});
// 链接 .then 来处理成功的结果
userDeferred.then((innerScope, user) => {
$console.log("成功获取到用户数据!用户名: " + user.name);
// 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
const welcomeMessage = "欢迎您," + user.name;
return innerScope.resolve(welcomeMessage);
}).then((innerScope, message) => {
$console.log("处理后的消息: " + message);
// 链条的末端也需要返回一个 Deferred
return innerScope.resolve(null);
}).onError(error => {
// 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
$console.error("获取用户数据时发生错误: " + error.getMessage());
});
--[[
* 完整示例 3.2: 使用 async 获取一个模拟的用户数据
]]
-- --- 样板代码 ---
_threads:getMain():setBackground(true)
local scope = _coroutines:newScope(nil)
_console:log("准备开始异步获取用户数据...")
-- scope:async 启动一个会返回结果的协程
local userDeferred = scope:async(nil, nil, function(coroutineScope)
-- async 的闭包会隐式返回最后一行的结果,这里是一个 Lua table 对象
-- Lua-Java 桥接器会自动将其转为 Map, 这个 table 将成为 userDeferred 的未来结果
return { id = "user-001", name = "张三" }
end)
-- 链接 ._then 来处理成功的结果
userDeferred:_then(function(innerScope, user)
_console:log("成功获取到用户数据!用户名: " .. user.name)
-- 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 _then
local welcomeMessage = "欢迎您," .. user.name
return innerScope:resolve(welcomeMessage)
end):_then(function(innerScope, message)
_console:log("处理后的消息: " .. message)
-- 链条的末端也需要返回一个 Deferred
return innerScope:resolve(nil)
end):onError(function(error)
-- 如果 async 内部或任何一个 _then 环节抛出异常,这里会捕获到
_console:error("获取用户数据时发生错误: " .. 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;
/*
* 完整示例 3.2: 使用 async 获取一个模拟的用户数据
*/
// --- 样板代码 ---
$threads->getMain()->setBackground(true);
$scope = $coroutines->newScope(function ($context) {
$context->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
$console->log(javaString("准备开始异步获取用户数据..."));
// scope.async 启动一个会返回结果的协程
$userDeferred = $scope->async(null, null, function ($coroutineScope) {
// async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
// 这个 Map 将成为 userDeferred 的未来结果
return ['id' => javaString("user-001"), 'name' => javaString("张三")];
});
// 链接 .then 来处理成功的结果
$userDeferred->then(function ($innerScope, $user) {
global $console;
$console->log(javaString("成功获取到用户数据!用户名: ") . $user['name']);
// 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
$welcomeMessage = javaString("欢迎您,") . $user['name'];
return $innerScope->resolve($welcomeMessage);
})->then(function ($innerScope, $message) {
global $console;
$console->log(javaString("处理后的消息: ") . $message);
// 链条的末端也需要返回一个 Deferred
return $innerScope->resolve(null);
})->onError(function ($error) {
global $console;
// 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
$console->error(javaString("获取用户数据时发生错误: ") . $error->getMessage());
});
#
# 完整示例 3.2: 使用 async 获取一个模拟的用户数据
#
# --- 样板代码 ---
# 导入所需的全局变量
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 dispatchers: dispatchers.getScriptMain())
)
_console.log("准备开始异步获取用户数据...")
# scope.async 启动一个会返回结果的协程
userDeferred = scope._async(None, None, lambda coroutineScope: (
# async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
# 这个 Map 将成为 userDeferred 的未来结果
# Groovy 的 [key: value] 映射转换为 Python 的 {'key': value} 字典
{'id': "user-001", 'name': "张三"}
))
# 链接 .then 来处理成功的结果
userDeferred.then(lambda innerScope, user: (
# Groovy 的 user.name 是对 Map 的便捷访问,Python 中使用 user['name']
_console.log("成功获取到用户数据!用户名: " + user['name']),
# 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
(welcomeMessage := "欢迎您," + user['name']),
innerScope.resolve(welcomeMessage)
# 记住并应用新规则:返回元组的最后一个元素,确保 then 链的返回值正确
)[-1]).then(lambda innerScope, message: (
# 为了安全,对 message 使用 str() 转换
_console.log("处理后的消息: " + str(message)),
# 链条的末端也需要返回一个 Deferred
innerScope.resolve(None)
# 记住并应用新规则:返回元组的最后一个元素
)[-1]).onError(lambda error: (
# 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
_console.error("获取用户数据时发生错误: " + str(error.getMessage()))
))
# encoding: utf-8
#
# 完整示例 3.2: 使用 async 获取一个模拟的用户数据
#
# --- 样板代码 ---
$threads.getMain().setBackground(true)
scope = $coroutines.newScope(nil)
$console.log("准备开始异步获取用户数据...")
# scope.async 启动一个会返回结果的协程
userDeferred = scope.async(nil, nil) do |coroutineScope|
# async 的闭包会隐式返回最后一行的结果,这里是一个 Map 对象
# 这个 Map 将成为 userDeferred 的未来结果
# Ruby 中 Hash 使用 {}
{id: "user-001", name: "张三"}
end
# 链接 .then 来处理成功的结果
userDeferred.then do |innerScope, user|
$console.log("成功获取到用户数据!用户名: " + user[:name])
# 我们可以对数据进行转换,并用 resolve 包装成新的 Deferred 传递给下一个 then
welcomeMessage = "欢迎您," + user[:name]
innerScope.resolve(welcomeMessage)
end.then do |innerScope, message|
$console.log("处理后的消息: " + message)
# 链条的末端也需要返回一个 Deferred
innerScope.resolve(nil)
end.onError do |error|
# 如果 async 内部或任何一个 then 环节抛出异常,这里会捕获到
$console.error("获取用户数据时发生错误: " + error.getMessage())
end
链式异步操作
.then 的真正威力在于,当它返回另一个由异步操作(如 async 或 delay)创建的 Deferred 时,整个链条会自动等待这个新的 Deferred 完成。这使得组织复杂的、有依赖关系的异步流程变得异常清晰。
import com.m8test.script.GlobalVariables.*
/*
* 完整示例 3.3 (已修正为完全非阻塞的链式实现):
* 先获取用户信息,再根据用户信息获取其帖子列表
*/
// --- 样板代码 ---
_threads.getMain().setBackground(true)
val scope = _coroutines.newScope(null)
// --- 核心修正点 ---
// 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
// 模拟的 API 函数 1: 获取用户 (已修正)
// 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
val fetchUser = { userId: String ->
_console.log("正在准备获取用户 " + userId + " 的信息 (延时500ms)...")
// 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
scope.delay(500).then { s, _ ->
// 2. 在延迟结束后,这个 .then 闭包被执行。
// 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
// 立即成功的 Deferred<Map> 并返回。
_console.log(" -> 用户信息延时获取完成。")
s.resolve(mapOf("id" to userId, "name" to "用户" + userId))
}
}
// 模拟的 API 函数 2: 获取帖子 (已修正)
// 同样,这个函数也直接返回一个 Deferred 链。
val fetchPosts = { user: Map<String, String> ->
_console.log("正在准备获取 " + user["name"] + " 的帖子 (延时800ms)...")
scope.delay(800).then { s, _ ->
_console.log(" -> 帖子列表延时获取完成。")
// 模拟一个可能发生的错误
if (user["id"] == "002") {
// 修复:去掉 'builder ->',直接在 Lambda 中调用方法,此时 this 即为 builder
val error = _exceptions.newThrowable {
setMessageAndClassName("用户 " + user["name"] + " 的帖子列表为空或无权访问。", "java.io.IOException")
}
// 使用 s.reject() 创建并返回一个立即失败的 Deferred。
s.reject(error)
} else {
// 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
s.resolve(listOf("帖子一:协程入门", "帖子二:高级技巧"))
}
}
}
// --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
_console.log("准备开始执行主异步链...")
fetchUser("001").then { innerScope, user ->
// 此处 `user` 是正确的 Map 对象!
_console.log("主链第一步:成功获取到用户 -> " + user["name"])
// 直接返回 fetchPosts 返回的 Deferred 对象。
// .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
fetchPosts(user)
}.then { innerScope, posts ->
// 此处 `posts` 是正确的 List 对象!
_console.log("主链第二步:成功获取到帖子列表 -> " + posts)
innerScope.resolve(null)
}.onError { error ->
// 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
_console.error("错误:在主链处理中发生异常 -> " + error.getMessage())
}
// 同时测试一下失败路径
scope.delay(3000).then { s, _ ->
_console.log("\n准备测试失败路径...")
fetchUser("002").then { innerScope, user ->
fetchPosts(user)
}.onError { error ->
_console.error("错误(失败路径测试):成功捕获到预期的异常 -> " + error.getMessage())
}
}
/*
* 完整示例 3.3 (已修正为完全非阻塞的链式实现):
* 先获取用户信息,再根据用户信息获取其帖子列表
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true)
def scope = $coroutines.newScope(null)
// --- 核心修正点 ---
// 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
// 模拟的 API 函数 1: 获取用户 (已修正)
// 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
def fetchUser = { userId ->
$console.log("正在准备获取用户 " + userId + " 的信息 (延时500ms)...")
// 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
scope.delay(500).then({ s, _ ->
// 2. 在延迟结束后,这个 .then 闭包被执行。
// 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
// 立即成功的 Deferred<Map> 并返回。
$console.log(" -> 用户信息延时获取完成。")
s.resolve([id: userId, name: "用户" + userId])
})
}
// 模拟的 API 函数 2: 获取帖子 (已修正)
// 同样,这个函数也直接返回一个 Deferred 链。
def fetchPosts = { user ->
$console.log("正在准备获取 " + user.name + " 的帖子 (延时800ms)...")
scope.delay(800).then({ s, _ ->
$console.log(" -> 帖子列表延时获取完成。")
// 模拟一个可能发生的错误
if (user.id == "002") {
def error = $exceptions.newThrowable({ builder ->
builder.setMessageAndClassName("用户 " + user.name + " 的帖子列表为空或无权访问。", "java.io.IOException")
})
// 使用 s.reject() 创建并返回一个立即失败的 Deferred。
s.reject(error)
} else {
// 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
s.resolve(["帖子一:协程入门", "帖子二:高级技巧"])
}
})
}
// --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
$console.log("准备开始执行主异步链...")
fetchUser("001").then({ innerScope, user ->
// 此处 `user` 是正确的 Map 对象!
$console.log("主链第一步:成功获取到用户 -> " + user.name)
// 直接返回 fetchPosts 返回的 Deferred 对象。
// .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
fetchPosts(user)
}).then({ innerScope, posts ->
// 此处 `posts` 是正确的 List 对象!
$console.log("主链第二步:成功获取到帖子列表 -> " + posts)
innerScope.resolve(null)
}).onError({ error ->
// 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
$console.error("错误:在主链处理中发生异常 -> " + error.getMessage())
})
// 同时测试一下失败路径
scope.delay(3000).then({s, _ ->
$console.log("\n准备测试失败路径...")
fetchUser("002").then({ innerScope, user ->
fetchPosts(user)
}).onError({ error ->
$console.error("错误(失败路径测试):成功捕获到预期的异常 -> " + error.getMessage())
})
})
/*
* 完整示例 3.3 (已修正为完全非阻塞的链式实现):
* 先获取用户信息,再根据用户信息获取其帖子列表
*/
// --- 样板代码 ---
$threads.getMain().setBackground(true);
const scope = $coroutines.newScope(null);
// --- 核心修正点 ---
// 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
/**
* 模拟的 API 函数 1: 获取用户 (已修正)
* 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
* @param {string} userId
* @returns {Deferred<{id: string, name: string}>}
*/
const fetchUser = userId => {
$console.log("正在准备获取用户 " + userId + " 的信息 (延时500ms)...");
// 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
return scope.delay(500).then((s, _) => {
// 2. 在延迟结束后,这个 .then 闭包被执行。
// 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
// 立即成功的 Deferred<Map> 并返回。
$console.log(" -> 用户信息延时获取完成。");
return s.resolve({id: userId, name: "用户" + userId});
});
};
/**
* 模拟的 API 函数 2: 获取帖子 (已修正)
* 同样,这个函数也直接返回一个 Deferred 链。
* @param {{id: string, name: string}} user
* @returns {Deferred<string[]>}
*/
const fetchPosts = user => {
$console.log("正在准备获取 " + user.name + " 的帖子 (延时800ms)...");
return scope.delay(800).then((s, _) => {
$console.log(" -> 帖子列表延时获取完成。");
// 模拟一个可能发生的错误
if (user.id == "002") {
const error = $exceptions.newThrowable(builder => {
builder.setMessageAndClassName("用户 " + user.name + " 的帖子列表为空或无权访问。", "java.io.IOException");
});
// 使用 s.reject() 创建并返回一个立即失败的 Deferred。
return s.reject(error);
} else {
// 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
return s.resolve(["帖子一:协程入门", "帖子二:高级技巧"]);
}
});
};
// --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
$console.log("准备开始执行主异步链...");
fetchUser("001").then((innerScope, user) => {
// 此处 `user` 是正确的 Map 对象!
$console.log("主链第一步:成功获取到用户 -> " + user.name);
// 直接返回 fetchPosts 返回的 Deferred 对象。
// .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
return fetchPosts(user);
}).then((innerScope, posts) => {
// 此处 `posts` 是正确的 List 对象!
$console.log("主链第二步:成功获取到帖子列表 -> " + posts);
return innerScope.resolve(null);
}).onError(error => {
// 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
$console.error("错误:在主链处理中发生异常 -> " + error.getMessage());
});
// 同时测试一下失败路径
scope.delay(3000).then((s, _) => {
$console.log("\n准备测试失败路径...");
fetchUser("002").then((innerScope, user) => {
return fetchPosts(user);
}).onError(error => {
$console.error("错误(失败路径测试):成功捕获到预期的异常 -> " + error.getMessage());
});
});
--[[
* 完整示例 3.3 (已修正为完全非阻塞的链式实现):
* 先获取用户信息,再根据用户信息获取其帖子列表
]]
-- --- 样板代码 ---
_threads:getMain():setBackground(true)
local scope = _coroutines:newScope(nil)
-- --- 核心修正点 ---
-- 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
-- 模拟的 API 函数 1: 获取用户 (已修正)
-- 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
local fetchUser = function(userId)
_console:log("正在准备获取用户 " .. userId .. " 的信息 (延时500ms)...")
-- 1. 以 scope:delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
return scope:delay(500):_then(function(s, _)
-- 2. 在延迟结束后,这个 ._then 闭包被执行。
-- 3. 我们在这里创建用户数据,并用 s:resolve() 将其包装成一个新的、
-- 立即成功的 Deferred<Map> 并返回。
_console:log(" -> 用户信息延时获取完成。")
return s:resolve({ id = userId, name = "用户" .. userId })
end)
end
-- 模拟的 API 函数 2: 获取帖子 (已修正)
-- 同样,这个函数也直接返回一个 Deferred 链。
local fetchPosts = function(user)
_console:log("正在准备获取 " .. user.name .. " 的帖子 (延时800ms)...")
return scope:delay(800):_then(function(s, _)
_console:log(" -> 帖子列表延时获取完成。")
-- 模拟一个可能发生的错误
if user.id == "002" then
local errorObj = _exceptions:newThrowable(function(builder)
builder:setMessageAndClassName("用户 " .. user.name .. " 的帖子列表为空或无权访问。", "java.io.IOException")
end)
-- 使用 s:reject() 创建并返回一个立即失败的 Deferred。
return s:reject(errorObj)
else
-- 使用 s:resolve() 创建并返回一个立即成功的 Deferred。
return s:resolve(_iterables:listOf("帖子一:协程入门", "帖子二:高级技巧"))
end
end)
end
-- --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
_console:log("准备开始执行主异步链...")
fetchUser("001"):_then(function(innerScope, user)
-- 此处 `user` 是正确的 table 对象!
_console:log("主链第一步:成功获取到用户 -> " .. user.name)
-- 直接返回 fetchPosts 返回的 Deferred 对象。
-- ._then 会自动处理这个返回的 "Promise",等待它完成后再继续。
return fetchPosts(user)
end):_then(function(innerScope, posts)
-- 此处 `posts` 是正确的 List 对象!
_console:log("主链第二步:成功获取到帖子列表 -> " .. tostring(posts))
return innerScope:resolve(nil)
end):onError(function(error)
-- 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
_console:error("错误:在主链处理中发生异常 -> " .. error:getMessage())
end)
-- 同时测试一下失败路径
scope:delay(3000):_then(function(s, _)
_console:log("\n准备测试失败路径...")
fetchUser("002"):_then(function(innerScope, user)
return fetchPosts(user)
end):onError(function(error)
_console:error("错误(失败路径测试):成功捕获到预期的异常 -> " .. error:getMessage())
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;
/** @var m8test_java\com\m8test\script\core\api\exception\Exceptions $exceptions */
global $exceptions;
/*
* 完整示例 3.3 (已修正为完全非阻塞的链式实现):
* 先获取用户信息,再根据用户信息获取其帖子列表
*/
// --- 样板代码 ---
$threads->getMain()->setBackground(true);
$scope = $coroutines->newScope(function ($context) {
$context->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
// --- 核心修正点 ---
// 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
// 模拟的 API 函数 1: 获取用户 (已修正)
// 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
$fetchUser = function ($userId) use ($scope) {
global $console;
$console->log(javaString("正在准备获取用户 ") . $userId . javaString(" 的信息 (延时500ms)..."));
// 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
return $scope->delay(500)->then(function ($s, $_) use ($userId) {
global $console;
// 2. 在延迟结束后,这个 .then 闭包被执行。
// 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
// 立即成功的 Deferred<Map> 并返回。
$console->log(javaString(" -> 用户信息延时获取完成。"));
return $s->resolve(['id' => $userId, 'name' => javaString("用户") . $userId]);
});
};
// 模拟的 API 函数 2: 获取帖子 (已修正)
// 同样,这个函数也直接返回一个 Deferred 链。
$fetchPosts = function ($user) use ($scope) {
global $console, $exceptions;
$console->log(javaString("正在准备获取 ") . $user['name'] . javaString(" 的帖子 (延时800ms)..."));
return $scope->delay(800)->then(function ($s, $_) use ($user) {
global $console, $exceptions;
$console->log(javaString(" -> 帖子列表延时获取完成。"));
// 模拟一个可能发生的错误
if ($user['id'] == "002") {
$error = $exceptions->newThrowable(function ($builder) use ($user) {
$builder->setMessageAndClassName(javaString("用户 ") . $user['name'] . javaString(" 的帖子列表为空或无权访问。"), javaString("java.io.IOException"));
});
// 使用 s.reject() 创建并返回一个立即失败的 Deferred。
return $s->reject($error);
} else {
// 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
return $s->resolve([javaString("帖子一:协程入门"), javaString("帖子二:高级技巧")]);
}
});
};
// --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
$console->log(javaString("准备开始执行主异步链..."));
$fetchUser("001")->then(function ($innerScope, $user) use ($fetchPosts) {
global $console;
// 此处 `user` 是正确的 Map 对象!
$console->log(javaString("主链第一步:成功获取到用户 -> ") . $user['name']);
// 直接返回 fetchPosts 返回的 Deferred 对象。
// .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
return $fetchPosts($user);
})->then(function ($innerScope, $posts) {
global $console;
// 此处 `posts` 是正确的 List 对象!
$console->log(javaString("主链第二步:成功获取到帖子列表 -> "), $posts); // Assuming PHP array to string
return $innerScope->resolve(null);
})->onError(function ($error) {
global $console;
// 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
$console->error(javaString("错误:在主链处理中发生异常 -> ") . $error->getMessage());
});
// 同时测试一下失败路径
$scope->delay(3000)->then(function ($s, $_) use ($fetchUser, $fetchPosts) {
global $console;
$console->log(javaString("\n准备测试失败路径..."));
$fetchUser("002")->then(function ($innerScope, $user) use ($fetchPosts) {
return $fetchPosts($user);
})->onError(function ($error) {
global $console;
$console->error(javaString("错误(失败路径测试):成功捕获到预期的异常 -> ") . $error->getMessage());
});
return $s->resolve(null); // The outer then needs to return a deferred.
});
#
# 完整示例 3.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)
# 使用您指定的 scope 创建方式
scope = _coroutines.newScope(lambda it:
it.setDispatcher(lambda dispatchers: dispatchers.getScriptMain())
)
# --- 核心修正点 ---
# 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
# 模拟的 API 函数 1: 获取用户 (已修正)
# 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
def fetchUser(userId):
_console.log("正在准备获取用户 " + str(userId) + " 的信息 (延时500ms)...")
# 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
return scope.delay(500).then(lambda s, _: (
# 2. 在延迟结束后,这个 .then 闭包被执行。
# 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
# 立即成功的 Deferred<Map> 并返回。
_console.log(" -> 用户信息延时获取完成。"),
s.resolve({'id': userId, 'name': "用户" + str(userId)})
)[-1])
# 模拟的 API 函数 2: 获取帖子 (已修正)
# 同样,这个函数也直接返回一个 Deferred 链。
def fetchPosts(user):
_console.log("正在准备获取 " + user['name'] + " 的帖子 (延时800ms)...")
return scope.delay(800).then(lambda s, _: (
_console.log(" -> 帖子列表延时获取完成。"),
# 模拟一个可能发生的错误
# 使用 Python 的条件表达式 (三元运算符) 来处理 if/else 逻辑
(s.reject(
_exceptions.newThrowable(lambda builder:
builder.setMessageAndClassName(
"用户 " + user['name'] + " 的帖子列表为空或无权访问。", "java.io.IOException")
)
) if user['id'] == "002" else
# 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
s.resolve(["帖子一:协程入门", "帖子二:高级技巧"]))
)[-1])
# --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
_console.log("准备开始执行主异步链...")
fetchUser("001").then(lambda innerScope, user: (
# 此处 `user` 是正确的 Map 对象!
# Groovy 的 user.name 变为 Python 的 user['name']
_console.log("主链第一步:成功获取到用户 -> " + user['name']),
# 直接返回 fetchPosts 返回的 Deferred 对象。
# .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
fetchPosts(user)
)[-1]).then(lambda innerScope, posts: (
# 此处 `posts` 是正确的 List 对象!
# 使用 str() 确保 posts 可以被安全地打印
_console.log("主链第二步:成功获取到帖子列表 -> " + str(posts)),
innerScope.resolve(None)
)[-1]).onError(lambda error: (
# 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
_console.error("错误:在主链处理中发生异常 -> " + str(error.getMessage()))
))
# 同时测试一下失败路径
scope.delay(3000).then(lambda s, _: (
_console.log("\n准备测试失败路径..."),
fetchUser("002").then(
# 这里的 lambda 是单行表达式,可以直接返回 fetchPosts 的结果,无需元组
lambda innerScope, user: fetchPosts(user)
).onError(
# 这里的 lambda 也是单行表达式
lambda error: _console.error("错误(失败路径测试):成功捕获到预期的异常 -> " + str(error.getMessage()))
)
# 外层 then 只是为了触发任务,不需要返回链条,所以不需要 [-1]
)[-1])
# encoding: utf-8
#
# 完整示例 3.3 (已修正为完全非阻塞的链式实现):
# 先获取用户信息,再根据用户信息获取其帖子列表
#
# --- 样板代码 ---
$threads.getMain().setBackground(true)
scope = $coroutines.newScope(nil)
# --- 核心修正点 ---
# 我们不再在 async 内部创建链条,而是让函数本身就是链条的起点。
# 模拟的 API 函数 1: 获取用户 (已修正)
# 这个函数现在直接返回一个从 delay 开始的 Deferred 链。
# Ruby 中使用 lambda 或 proc 定义可调用的闭包
fetchUser = lambda do |userId|
$console.log("正在准备获取用户 " + userId + " 的信息 (延时500ms)...")
# 1. 以 scope.delay(500) 作为链条的起点。它返回一个 Deferred<Unit>。
scope.delay(500).then do |s, _|
# 2. 在延迟结束后,这个 .then 闭包被执行。
# 3. 我们在这里创建用户数据,并用 s.resolve() 将其包装成一个新的、
# 立即成功的 Deferred<Map> 并返回。
$console.log(" -> 用户信息延时获取完成。")
s.resolve({id: userId, name: "用户" + userId})
end
end
# 模拟的 API 函数 2: 获取帖子 (已修正)
# 同样,这个函数也直接返回一个 Deferred 链。
fetchPosts = lambda do |user|
$console.log("正在准备获取 " + user[:name] + " 的帖子 (延时800ms)...")
scope.delay(800).then do |s, _|
$console.log(" -> 帖子列表延时获取完成。")
# 模拟一个可能发生的错误
if user[:id] == "002"
error = $exceptions.newThrowable do |builder|
builder.setMessageAndClassName("用户 " + user[:name] + " 的帖子列表为空或无权访问。", "java.io.IOException")
end
# 使用 s.reject() 创建并返回一个立即失败的 Deferred。
s.reject(error)
else
# 使用 s.resolve() 创建并返回一个立即成功的 Deferred。
s.resolve(["帖子一:协程入门", "帖子二:高级技巧"])
end
end
end
# --- 外部的异步链调用现在不仅能工作,而且其结构与内部实现完全一致! ---
$console.log("准备开始执行主异步链...")
# Ruby 中调用 lambda 需要使用 .call()
fetchUser.call("001").then do |innerScope, user|
# 此处 `user` 是正确的 Map 对象!
$console.log("主链第一步:成功获取到用户 -> " + user[:name])
# 直接返回 fetchPosts 返回的 Deferred 对象。
# .then 会自动处理这个返回的 "Promise",等待它完成后再继续。
fetchPosts.call(user)
end.then do |innerScope, posts|
# 此处 `posts` 是正确的 List 对象!
# Ruby 数组转字符串直接使用 to_s
$console.log("主链第二步:成功获取到帖子列表 -> " + posts.to_s)
innerScope.resolve(nil)
end.onError do |error|
# 这个 onError 可以捕获 fetchUser 或 fetchPosts 中任何一个环节的错误
$console.error("错误:在主链处理中发生异常 -> " + error.getMessage())
end
# 同时测试一下失败路径
scope.delay(3000).then do |s, _|
$console.log("\n准备测试失败路径...")
fetchUser.call("002").then do |innerScope, user|
fetchPosts.call(user)
end.onError do |error|
$console.error("错误(失败路径测试):成功捕获到预期的异常 -> " + error.getMessage())
end
end
resolve 和 reject: 融入同步逻辑
scope.resolve(value) 和 scope.reject(error) 是将同步代码无缝融入异步链的关键工具。
scope.resolve(value): 将一个已知的值包装成一个立即成功的 Deferred。
scope.reject(error): 将一个已知错误包装成一个立即失败的 Deferred。
import com.m8test.script.GlobalVariables.*
import com.m8test.script.core.api.coroutines.Deferred
val scope = _coroutines.newScope(null)
// 示例:从缓存或网络获取数据
val cachedData: String? = null // or "缓存数据"
val dataDeferred: Deferred<String?> = if (cachedData != null) {
_console.log("命中了缓存!")
scope.resolve(cachedData) // 直接使用缓存
} else {
_console.log("缓存未命中,从网络获取...")
// 修复:async 块移除显式参数 ss ->
scope.delay(5000).then { s, _ ->
s.async(null, null) { "从网络获取的数据" }
}
}
dataDeferred.then { s, data ->
_console.log("最终获取到的数据: " + data)
s.resolve(null)
}
_threads.getMain().setBackground(true)
import com.m8test.script.core.api.coroutines.Deferred
def scope = $coroutines.newScope(null)
// 示例:从缓存或网络获取数据
def cachedData = null // or "缓存数据"
Deferred<String> dataDeferred = null
if (cachedData != null) {
$console.log("命中了缓存!")
dataDeferred = scope.resolve(cachedData) // 直接使用缓存
} else {
$console.log("缓存未命中,从网络获取...")
dataDeferred = scope.delay(5000).then({ s, _ -> s.async(null, null) { ss -> "从网络获取的数据" } })
}
dataDeferred.then({ s, data ->
$console.log("最终获取到的数据: " + data)
s.resolve(null)
})
$threads.getMain().setBackground(true)
const scope = $coroutines.newScope(null);
// 示例:从缓存或网络获取数据
let cachedData = null; // or "缓存数据"
/** @type {Deferred<string>} */
let dataDeferred = null;
if (cachedData != null) {
$console.log("命中了缓存!");
dataDeferred = scope.resolve(cachedData); // 直接使用缓存
} else {
$console.log("缓存未命中,从网络获取...");
dataDeferred = scope.delay(5000).then((s, _) => s.async(null, null, ss => "从网络获取的数据"));
}
dataDeferred.then((s, data) => {
$console.log("最终获取到的数据: " + data);
return s.resolve(null);
});
$threads.getMain().setBackground(true);
local scope = _coroutines:newScope(nil)
-- 示例:从缓存或网络获取数据
local cachedData = nil -- or "缓存数据"
local dataDeferred = nil
if cachedData ~= nil then
_console:log("命中了缓存!")
dataDeferred = scope:resolve(cachedData) -- 直接使用缓存
else
_console:log("缓存未命中,从网络获取...")
dataDeferred = scope:delay(5000):_then(function(s, _) return s:async(nil, nil, function(ss) return "从网络获取的数据" end) end)
end
dataDeferred:_then(function(s, data)
_console:log("最终获取到的数据: " .. data)
return s:resolve(nil)
end)
_threads:getMain():setBackground(true)
<?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;
/** @var m8test_java\com\m8test\script\core\api\coroutines\Deferred $dataDeferred */
$scope = $coroutines->newScope(function ($context) {
$context->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
// 示例:从缓存或网络获取数据
$cachedData = null; // or javaString("缓存数据")
$dataDeferred = null;
if ($cachedData != null) {
$console->log(javaString("命中了缓存!"));
$dataDeferred = $scope->resolve($cachedData); // 直接使用缓存
} else {
$console->log(javaString("缓存未命中,从网络获取..."));
$dataDeferred = $scope->delay(5000)->then(function ($s, $_) {
return $s->async(null, null, function ($ss) {
return javaString("从网络获取的数据");
});
});
}
$dataDeferred->then(function ($s, $data) {
global $console;
$console->log(javaString("最终获取到的数据: ") . $data);
return $s->resolve(null);
});
$threads->getMain()->setBackground(true);
# 导入所需的全局变量
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
# 导入所需的Java类
scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain()))
# 示例:从缓存或网络获取数据
cachedData = None # or "缓存数据"
dataDeferred = None
# Use Python's conditional expression for if/else
if cachedData is not None:
_console.log("命中了缓存!")
dataDeferred = scope.resolve(cachedData) # 直接使用缓存
else:
_console.log("缓存未命中,从网络获取...")
# Remember to use _async for scope.async
dataDeferred = scope.delay(5000).then(lambda s, _:
s._async(None, None, lambda ss: "从网络获取的数据")
)
dataDeferred.then(lambda s, data: (
_console.log("最终获取到的数据: " + str(data)),
s.resolve(None)
)[-1])
_threads.getMain().setBackground(True)
# encoding: utf-8
# import com.m8test.script.core.api.coroutines.Deferred # Ruby不需要显式import泛型类型
scope = $coroutines.newScope(nil)
# 示例:从缓存或网络获取数据
cachedData = nil # or "缓存数据"
dataDeferred = nil
if cachedData != nil
$console.log("命中了缓存!")
dataDeferred = scope.resolve(cachedData) # 直接使用缓存
else
$console.log("缓存未命中,从网络获取...")
dataDeferred = scope.delay(5000).then { |s, _| s.async(nil, nil) { |ss| "从网络获取的数据" } }
end
dataDeferred.then do |s, data|
$console.log("最终获取到的数据: " + data)
s.resolve(nil)
end
$threads.getMain().setBackground(true)
09 December 2025