避免Lua回调地狱

我经常使用 Lua 和 Corona SDK 进行工作,虽然我很喜欢它作为一种语言,但我意识到我的代码可能会变得非常混乱,因为回调会调用回调等等。

我想知道是否有任何设计模式或库(例如 JavaScript 的 async.js),可以帮助减少这个问题。

一个典型的例子是使用 Corona 的转场调用:

transition.to(obj,{... onComplete=function()
    transition.to(obj,{... onComplete=function()
        if foo then
            transition.to(obj,{... onComplete=function() ... end})
        else
            transition.to(obj,{... onComplete=function() ... end})
        end
    end})
end})

我发现代码很快变得非常紧凑,但通常内部闭包依赖于外部的变量。我知道自律是创建清洁代码的重要因素,但有一个结构来强制使用自律是有用的。除了命名闭包,有人发现了管理此类情况的有用方法吗?

点赞
用户102441
用户102441

使用协程可能有所帮助:

await = function(f)
    return function(...)
        local self = coroutine.running()
        f(..., {onComplete=function(...)
           coroutine.resume(self, ...)
        end})
        return coroutine.yield()
    end
end

await(transition.to)(obj)
await(transition.to)(obj)
if foo then
    await(transition.to)(obj)
else
    await(transition.to)(obj)
end

或者更通用地,解决评论中的问题:

async_call = function(f)
    local self = coroutine.running()
    local is_async
    local results = nil
    local async_continue = function(...)
        if coroutine.running() ~= self then
            is_async = true
            coroutine.resume(self, ...)
        else
            is_async = false
            results = {...}
        end
    end
    f(async_continue)
    if is_async then
        return coroutine.yield()
    else
        return unpack(results)
    end
end

async_call(function(cont) transition.to(obj, {onComplete=cont}) end)
2013-06-13 20:08:29
用户1244588
用户1244588

一种方法是将回调函数定义为全局变量或上值,并通过将回调函数包裹在另一个函数中并注入回调所需的上值来使用:

function foo(upvalue)
    return function(...) -- 这是真正的回调函数
        return print(upvalue, ...);
    end
end

然后,您只需将其作为回调附加到对象上,如下所示

transition.to(obj,{... onComplete=foo(somevar)})

然而,附加额外的函数调用会对性能产生一些小影响。另一方面,如果您有多个类似的回调函数,您可能可以想出某种代码重用。

2013-06-13 22:45:04