Coffeescript 等待直到从回调中设置标志,然后继续执行代码的下一部分

Coffeescript wait until flag is set from a callback and then move on to the next part of the code

我这里有一个使用 coffeescript 的简单程序,它在 Raspberry pi 上创建一个服务器,它从 Windows 机器上的 python 脚本 运行 接收数据在同一个网络上,对该数据进行一些计算并发回结果。

我想做的是保持服务器打开,运行 并接受数据,直到 python 脚本发送的参数要求它关闭。

为了尝试这个,我创建了一个循环来阻塞代码,直到这些标志被设置;然而,这实际上是阻塞了代码,因此没有设置标志(python 脚本甚至无法连接)。所以我想我需要使用某种异步控制 here/promises.

# Functions
process_data = (data) ->
    double_value: data * 2
    triple_value: data * 3

clean_up_actions = () ->
    console.log "Cleaning up..."

# Create server
net = require('net')
domain = '10.1.1.28'
port = 9001

program_complete = false
clean = false

console.log("Creating server...")
server = net.createServer (socket) ->
    console.log "#{socket.remoteAddress} has connected"

    # When data is received, do something and send back a response
    socket.on 'data', (data) ->
        console.log("Data received...")
        if not program_complete
            incoming_data = JSON.parse(data)
            
            some_useful_value = incoming_data["some_useful_value"]
            result = process_data(some_useful_value)
            socket.write JSON.stringify(result)
            
            # Check if end of program
            program_complete = incoming_data["end_program"]
            if program_complete
                clean_up_actions()
                clean = true

console.log "Listening to #{domain}:#{port}"
server.listen port, domain
    
console.log("Waiting until complete...")
loop
    break if program_complete and clean
console.log "--- PROGRAM FINISHED ---"

为了测试这一点,我使用了 Q.delay(10000) 而不是循环,并且它按照我期望的方式工作(我获得了连接并且可以来回传递数据没问题),除了而不是当 end_program 设置为 True 时退出,它将在 10 秒后退出(如预期的那样)。

...
# console.log("Waiting until complete...")
# loop
#     break if program_complete and clean
# console.log "--- PROGRAM FINISHED ---"

Q = require('q')
Q.delay(10000).then ->
    console.log "Done"
.finally ->
  console.log('--- PROGRAM END ---')
  process.exit(0)

我的问题是,我如何使用 promise 或其他异步控制(如 Q.delay(n))而不是延迟一段时间,而是等到这些标志被设置。

如果有兴趣,或者想测试一下,python代码在下面

import socket
import json
import time

REMOTE_HOST = '10.1.1.28'
REMOTE_PORT = 9001

# Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Connect to the remote host and port
sock.connect((REMOTE_HOST, REMOTE_PORT))

# Send some data
data_dictionary = {
    'some_useful_value' : 21,
    'end_program' : False
}
data_to_send = json.dumps(data_dictionary).encode('utf-8')
sock.send(data_to_send)
print(sock.recv(1024))

time.sleep(0.5)

# Send some data, but this time, end
data_dictionary = {
    'some_useful_value' : 13,
    'end_program' : True
}
data_to_send = json.dumps(data_dictionary).encode('utf-8')
sock.send(data_to_send)
print(sock.recv(1024))

time.sleep(0.5)

# Terminate
sock.close()

My question is, how can I use a promise or other asynchronous control (like Q.delay(n)) but instead of delaying for a time, it waits until these flags are set.

我认为简短的回答是否定的,或者至少在不深入研究中断等更深奥的东西的情况下不会。但是您可以通过设置一个短暂的等待来“手动”近似,检查是否设置了值,然后再次等待或退出等待状态并根据该检查的结果继续执行其余逻辑。

我不熟悉您在此处导入(并使用 Q.delay 调用)的 Q 库,但我认为您走在正确的道路上。在一般情况下,我认为你想要做的是使用 setIntervalsetTimeout 在相对较短的时间内“屈服”执行,然后检查是否已设置该值。我想象 Q.delay 在内部使用 setTimeout 或类似的东西。

这里是我的意思的粗略描述:

# here is the flag we'll wait to be set
the_flag = null 

# here is an arbitrary callback method that represents
# the "action" to take once the flag is set
the_callback = (flag)->
  console.log "#{(new Date()).toISOString()}: the_flag is now set to:", flag

# we'll keep a handle to the value returned by setInterval
# so we can cancel it later.
interval_id = null

# here's the method that checks if the flag has been set
# and responds accordingly
check_if_flag_is_set = ()->
  if the_flag?
    # it *is* set now, so clear the interval and callback
    clearInterval(interval_id)
    interval_id = null
    the_callback(the_flag)
  else
    console.log "#{(new Date()).toISOString()}: the flag is not yet set, still waiting..."

# now just kick off the interval to invoke the "check"
# method every 3 seconds
interval_id = setInterval( check_if_flag_is_set, 3000 )

现在 if/when the_flag 的值设置在一些异步代码中 check_if_flag_is_set 方法将检测它并将结果报告给 the_callback。请注意,setInterval 等待期是非阻塞的 - 在我们等待 check_if_flag_is_set.

的下一次调用时,其他代码可以并且将会执行

也就是说,网络 i/o 交互也是非阻塞的,所以如果标志是由一些写入套接字的数据设置的,你真的不需要额外的异步层,非- 通过 setInterval 阻塞等待。您可以等待网络侦听器发出 on('data',handler) 或类似事件。

您可能有几种方法可以实现此目的,我们会等待您的 socket.on 'data' 方法将代码中的标志 end_programclean 设置为 true。

在脚本的末尾,您可以使用一个函数连续 returns 一个承诺,直到满足特定条件(在这种情况下,标志 clean 已设置)。

您使用的 Q 库应该足够了,因为我相信它的 .delay 函数是异步的。例如,在下面的代码中,该函数每秒检查一次标志,如果未设置标志,该函数将再次调用自身,并在一秒钟后检查。如果设置了标志,我们就可以继续执行代码的下一部分。

这可能看起来像这样,使用变量 clean 作为您的标志:

waitForFlag = () -> 
  Q.delay(1000).then -> 
    if (clean)
      console.log "Condition met! We can move on"
    else
      # if condition isn't met, check again in one second
      waitForFlag() 

# Call function
waitForFlag().then ->
  process.exit(0)