--LuaTaskAwaiter
--@module LuaTaskAwaiter
local TaskAwaiter = class("TaskAwaiter")
function TaskAwaiter:ctor()
self.IsCompleted=false
self.Packaged = false
self.actions = {}
end
function TaskAwaiter:GetException()
return self.exception
end
function TaskAwaiter:GetResult()
if not self.IsCompleted then
error("The task is not finished yet")
end
if self.exception then
error(self.exception)
end
return self.result
end
function TaskAwaiter:SetResult(result,exception,packaged)
if exception then
self.exception = exception
else
self.result = result
end
self.IsCompleted = true
self.Packaged = packaged
if not self.actions then
return
end
for _, v in pairs(self.actions) do
if v then
xpcall(v,function(err)
log:error("%s \n%s",err,debug.traceback())
end)
end
end
end
function TaskAwaiter:OnCompleted(action)
if not action then
return
end
if self.IsCompleted then
xpcall(action,function(err)
log:error("%s \n%s",err,debug.traceback())
end)
return
end
table.insert(self.actions,action)
end
---
--AsyncTask
--@module AsyncTask
local M = class("AsyncTask",TaskAwaiter)
function async(action)
return function(...)
local task = M()
if type(action)~='function' then
task:SetResult(nil,"please enter a function")
return task
end
local co = coroutine.create(function(...)
local results = table.pack(xpcall(action,function(err)
task:SetResult(nil,err,false)
log:error("%s \n%s",err,debug.traceback())
end,...))
local status = results[1]
if status then
table.remove(results,1)
if #results <=1 then
task:SetResult(results[1],nil,false)
else
task:SetResult(results,nil,true)
end
end
end)
coroutine.resume(co,...)
return task
end
end
function await(result)
assert(result ~= nil,"The result is nil")
local status, awaiter
if type(result)=='table' and iskindof(result,"TaskAwaiter") then
awaiter = result
elseif type(result) == 'userdata' or type(result) == 'table' then
status, awaiter = pcall(result.GetAwaiter,result)
if not status then
error("The parameter of the await() is error,not found the GetAwaiter() in the "..tostring(result))
end
else
error("The parameter of the await() is error, this is a function, please enter a table or userdata")
end
if awaiter.IsCompleted then
local value = awaiter:GetResult()
if type(value) == 'table' and awaiter.Packaged then
return table.unpack(value)
else
return value
end
end
local id = coroutine.running()
local isYielded= false
awaiter:OnCompleted(function()
if isYielded then
coroutine.resume(id)
end
end)
if not awaiter.IsCompleted then
isYielded = true
coroutine.yield()
end
local value = awaiter:GetResult()
if type(value) == 'table' and awaiter.Packaged then
return table.unpack(value)
else
return value
end
end
function try(block)
local main = block[1]
local catch = block.catch
local finally = block.finally
local results = table.pack(pcall(main))
local status = results[1]
local e = results[2]
table.remove(results,1)
local result = results
local catched = false
if (not status) and catch and type(catch)=='function' then
catched = true
local results = table.pack(pcall(catch,e))
if results[1] then
table.remove(results,1)
result = results
e = nil
else
e = results[2]
end
end
if finally and type(finally)=='function' then
pcall(finally)
end
if status then
return table.unpack(result)
elseif catched then
if not e then
return table.unpack(result)
else
error(e)
end
else
error(e)
end
end
function M.Run(func,...)
local action = async(func)
return action(...)
end
return M
使用示例
-- 异步操作1:定时器
local function timerAsync(seconds)
return async(function()
print("timerAsync start")
await(delay(seconds))
print("timerAsync end")
return "timerAsync done"
end)
end
-- 异步操作2:计时器
local function stopwatchAsync(count)
return async(function()
print("stopwatchAsync start")
for i = 1, count do
await(delay(1))
print("stopwatchAsync time: " .. i)
end
print("stopwatchAsync end")
return "stopwatchAsync done"
end)
end
-- 异步操作3:网络请求
local function requestAsync(url)
return async(function()
print("requestAsync start")
local response = await(http.request(url))
print("requestAsync end")
return response
end)
end
-- 使用 async/await 进行异步编程
local function main()
print("main start")
local timerTask = timerAsync(2)
local stopwatchTask = stopwatchAsync(5)
local requestTask = requestAsync("https://httpbin.org/get")
local result1 = await(timerTask)
print("timerTask result: " .. result1)
local result2 = await(stopwatchTask)
print("stopwatchTask result: " .. result2)
local result3 = await(requestTask)
print("requestTask result: " .. result3)
print("main end")
end