避免Lua Callback Hell

时间:2013-06-13 10:15:56

标签: callback lua corona

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

我想知道是否有任何设计模式或库(如JavsScript的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})

我发现代码很快变得非常密集,但通常内部闭包依赖于外部变量。我理解自律是创建干净代码的一个重要因素,但有一个结构强制使用自律是有用的。除了命名闭包之外,有没有人遇到过管理这个问题的有用方法?

2 个答案:

答案 0 :(得分:2)

使用协同程序可能会有所帮助:

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) 

答案 1 :(得分:0)

一种方法是将回调定义为全局或upvalue,并通过将回调包装在另一个函数中来注入回调所需的upvalues:

function foo(upvalue)
    return function(...) -- thats the actual callback
        return print(upvalue, ...);
    end
end

然后你可以把它作为回调附加,如

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

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