Lua脚本不按顺序执行

Posted

技术标签:

【中文标题】Lua脚本不按顺序执行【英文标题】:Lua script does not execute in sequence 【发布时间】:2015-07-04 19:21:50 【问题描述】:

我想花时间使用带有 nodeMCU 的 EPS8266 来设置我的 RTC over I2C。

这是我的剧本:

-- file print.lua     
local file = assert(loadfile("httpget.lua"))    
file()                  --get Date and Time from google    
print("Print follows:") --this should be executed after "file()"    
print(date)

这是文件httpget.lua

-- file httpget.lua
print('httpget.lua started')
conn=net.createConnection(net.TCP, 0)
-- show the retrieved web page
conn:on("receive", function(conn, payload) 
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +6,string.find(payload,"Date: ")+35)
                     conn:close()
                     end) 

conn:on("connection", function(conn, payload) 
                       print('\nConnected') 
                       conn:send("HEAD /  HTTP/1.1\r\n" 
                        .."Host: google.com\r\n" 
                        .."Accept: */*\r\n" 
                        .."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"
                        .."\r\n\r\n")
                        end)

-- when disconnected, let it be known
conn:on("disconnection", function(conn, payload)
                         print("Disconnected\r\n"..date)
                         end)                                             
conn:connect(80,'google.com')
conn = nil

结果是:

> dofile("print.lua")
httpget.lua started
Print follows:              -- this should be at the end
nil                         -- date==nil because httpget.lua not executed
> 
Connected
Disconnected
Sun, 26 Apr 2015 10:30:03 GMT

如果我再次执行 scipt(没有重置),我会从之前的执行中获取日期。 如何执行“httpget.lua”并在后面的 scipt 中获取“日期”?

我使用 ESP8266 和 NodeMCU 0.9.6 build 20150406,由 Lua 5.1.4 提供支持。 https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en#index

我通过带有 ESPlorer v2.0 的 USB 将脚本加载到我的 ESP8266。 conn.net... 命令是 NodeMCU 固件的一部分(参见链接)。您只能使用 EPS8288 和 NodeMCU 固件运行脚本。我的问题是:我找不到正确结束 conn:net 例程并将数据返回到下一个程序部分的方法。

【问题讨论】:

connect调用可能是异步的,但我不知道你用的是什么库。 顺便说一句,您已经定义了事件处理程序,并且 print.lua 在继续下一行之前不会等待连接成功。另外,我不知道lua是否会将date的值传递到不同的范围内。 我使用 ESP8266 和 NodeMCU 0.9.6 build 20150406,由 Lua 5.1.4 提供支持。我用 ESPloer 加载脚本。 Google nodemcu 非官方常见问题解答并阅读。 【参考方案1】:

正如评论者指出的那样,网络代码将异步运行,即 conn:on 调用将立即返回,并在稍后调用它们的回调。 conn:connect 调用可能不是异步的,但这无济于事。

conn:connect 调用完成后,您的print 调用将立即运行,尝试打印全局变量date。大多数情况下,这将打印nil,因为从 Google 获取数据的网络延迟将在 10 毫秒以上,这意味着您的代码已经有足够的时间来执行打印语句。在极少数情况下,如果您对网络延迟非常幸运,您实际上可能会得到正确的日期(不过这会非常令人惊讶)。

要解决此问题,您需要将要在网络请求完成时执行的代码放入您传递给接收数据的conn:on 的回调中。不过,在您当前的代码结构中,这有点难以以一种好的方式完成。

一个简单的解决办法是:

local function onReceiveCb(str)
 print("Print follows:")
 print(str)
end
local file = assert(loadfile("httpget.lua"))
....

请注意,在包含 httpget 代码之前,我已经添加了一个 onReceiveCb 函数。在 httpget 你调用回调:

conn:on("receive", function(conn, payload) 
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +6,string.find(payload,"Date: ")+35)
                     conn:close()
                     onReceiveCb(date) -- Call the callback!
                     end) 

【讨论】:

【参考方案2】:

带有回调函数的提案不起作用。我得到一个编译器错误。我现在用另一种方式解决了它。 在 conn:on("disconnection", function(conn, payload) 中,我加载文件来设置我的 RTC。这样我可以将数据传递给设置 RTC 的程序。(见我的输出)

感谢您的帮助!!!

> dofile("httpget.lua");
httpget.lua started
> 
Connected
Disconnected

----------------
Date: Mon, 27 Apr 2015 12:02:17 GMT -- printed in httpget.lua
Date: Mon, 27 Apr 2015 12:02:17 GMT -- printed in set_date.lua
Set RTC:
23 2 19 2 39 4 21  -- Bytes 0-6 in decimal of the DS1307 (1h for Daylight Savings Time added)
done

--这是工作脚本:

print('httpget.lua started')

conn=net.createConnection(net.TCP, 0) 

-- show the retrieved web page
conn:on("receive", function (conn, payload)  
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +0,string.find(payload,"Date: ")+35)
                     conn:close()
                     end) 

-- when connected, request page (send parameters to a script)
conn:on("connection", function(conn, payload) 
                       print('\nConnected') 
                       conn:send("HEAD /  HTTP/1.1\r\n" 
                        .."Host: google.com\r\n" 
                        .."Accept: */*\r\n" 
                        .."User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"
                        .."\r\n\r\n")
                        end)

-- when disconnected, let it be known
conn:on("disconnection", function(conn, payload)
                         print("Disconnected\r\n")
                         print("----------------")
                         print(date)
                         dofile("set_date.lua");
                         end)

conn:connect(80,'google.com')
conn=nil

【讨论】:

太好了,你解决了!您可以将自己的答案标记为正确答案(因此显示为已回答)。如果我的回答对您有帮助,请点赞。

以上是关于Lua脚本不按顺序执行的主要内容,如果未能解决你的问题,请参考以下文章

Lua脚本在Redis事务中的应用实践

lua脚本怎么获取当前正在执行的脚本的当前路径

C#中执行Lua脚本

redis使用lua

Redis | 第9章 Lua 脚本与排序《Redis设计与实现》

防止多次执行 Lua 脚本