当使用大量异步代码时,我对如何编写像样的代码感到困惑。
在下面的代码片段中,我登录以获取身份验证 cookie 并将该 cookie 用于下一个请求以获取项目名称列表(作为示例):
def self.populateProjectsTable(projects_controller)
payload = {email: "email", password: "pass"}
HTTP.post("http://example.com/login", {payload: payload}) do |response|
authCookie = response.headers['Set-Cookie']
HTTP.get("http://example.com/projects.json", {cookie: authCookie}) do |response|
projects = JSON.parse(response.body.to_str)
projects_controller.projects = projects
projects_controller.reloadData
end
end
end
虽然这会起作用,但代码感觉很脏。没有真正遵循单一职责原则。我想用几种方法提取它:
def self.populateProjectsTable(projects_controller)
@taskList = TaskList.new
@taskList.doLogin
projects = @taskList.getProjects
projects_controller.projects = projects
projects_controller.reloadData
end
def doLogin
payload = {email: "email", password: "pass"}
HTTP.post("http://example.com/login", {payload: payload}) do |response|
@authCookie = response.headers['Set-Cookie']
end
end
def getProjects
HTTP.get("http://example.com/projects.json", {cookie: @authCookie}) do |response|
projects = JSON.parse(response.body.to_str)
end
end
这显然行不通。 getProjects
方法在 doLogin
完成之前调用,项目仅在 block 范围内已知,不会将数据返回给 populateProjectsTable
方法。
如何在没有第一个示例中所示的嵌套的情况下编写此类应用程序?
请您参考如下方法:
您不会完全摆脱嵌套。接受艾伦的回答并稍微修改一下,这就是我想出的。它涉及通过几种方法传递一个 block 。
def self.populateProjectsTable(projects_controller)
@taskList = TaskList.new
@taskList.loginAndGetProjects do |projects|
projects_controller.projects = projects
projects_controller.reloadData
end
end
def loginAndGetProjects(&block)
payload = {email: "email", password: "pass"}
HTTP.post("http://example.com/login", {payload: payload}) do |response|
@authCookie = response.headers['Set-Cookie']
getProjects(&block)
end
end
def getProjects(&block)
HTTP.get("http://example.com/projects.json", {cookie: @authCookie}) do |response|
projects = JSON.parse(response.body.to_str)
block.call(projects)
end
end