堆栈溢出 - 递归回调 - JavaScript
Stack Overflow - Recursive Callback - JavaScript
我正在用 node.js 使用 cylon.js 编写一些电机控制。我有一个舵机,当你给它一个角度时,它有一个回调函数。当它完成那个功能时,我想再读一次,给它一个新的角度,用回调做另一次读...等等。
当前代码是:
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), controlServo(servo, angleSensor));
}
这让堆栈在四分之一秒内溢出。
解决这个问题的更好方法是使用 timeout
而不是递归。这最终会在下一次滴答时调用您的函数,它永远不会溢出。
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), function() {
setTimeout(function() { ControlServo(servo, angleSensor)}, 0);
});
};
您可以通过将 timeout
移动到 servo.angle
函数来缩短它,但您可能需要它作为其他用途的回调。上面的方法不需要其他更改,因为回调只是设置超时。
另一个选项是 setImmediate
,它似乎将函数调用放在当前报价的末尾,而不是下一个报价的开头。由于 setTimeout
总是会引入轻微的延迟,因此 setImmediate
可能会更快;但是,我不知道使用它还可以做出哪些其他权衡,因为我自己用得不多。
无法用 Cylon.js 做您想做的事。 Cylon.js 的内部 "write" 操作 "callback" 不是异步的,并且在机械完成移动时不会被调用。它在写入操作后立即被调用。 Cylon 只能将角度值写入伺服系统,伺服系统以其最大速度机械移动喇叭。如果它是一个慢速伺服系统,从 0 度到 180 度可能需要整整 2 秒才能真正完成机械操作。与此同时,赛昂已经回调了。这样做的原因是因为没有办法在不做一些额外工作的情况下以对所有伺服模型始终正确的方式概括回调行为。
在约翰尼五号中,我们通过提供 "time to complete" 参数实现了速度控制。这是通过将到新角度的距离分成步数以在指定的 "time to complete" 中移动来完成的。这个过程的副作用是 Johnny-Five 伺服实例 可以 知道移动何时机械完成,因为步长更小并且时间受控。因此,我们有一个 "move:complete" 事件,该事件会在任何定时移动完成时发出。
var servo = new five.Servo(9);
servo.on("move:complete", 函数() {
// 我们到了!
});
// 更改需要 500 毫秒才能完成
servo.to(180, 500);
可以很容易地与模拟传感器结合使用:
var servo = new five.Servo(9);
var 传感器 = 新 five.Sensor({
引脚:"A0",比例:[ 0, 180 ]
});
servo.on("move:complete", 函数() {
更新();
});
功能更新(){
// 更改需要 200 毫秒才能完成
servo.to(sensor.value, 200);
}
更新();
更简单:
var servo = new five.Servo(9);
var sensor = new five.Sensor("A0");
sensor.scale(0, 180).on("change", 函数() {
servo.to(this.value);
});
我正在用 node.js 使用 cylon.js 编写一些电机控制。我有一个舵机,当你给它一个角度时,它有一个回调函数。当它完成那个功能时,我想再读一次,给它一个新的角度,用回调做另一次读...等等。
当前代码是:
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), controlServo(servo, angleSensor));
}
这让堆栈在四分之一秒内溢出。
解决这个问题的更好方法是使用 timeout
而不是递归。这最终会在下一次滴答时调用您的函数,它永远不会溢出。
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), function() {
setTimeout(function() { ControlServo(servo, angleSensor)}, 0);
});
};
您可以通过将 timeout
移动到 servo.angle
函数来缩短它,但您可能需要它作为其他用途的回调。上面的方法不需要其他更改,因为回调只是设置超时。
另一个选项是 setImmediate
,它似乎将函数调用放在当前报价的末尾,而不是下一个报价的开头。由于 setTimeout
总是会引入轻微的延迟,因此 setImmediate
可能会更快;但是,我不知道使用它还可以做出哪些其他权衡,因为我自己用得不多。
无法用 Cylon.js 做您想做的事。 Cylon.js 的内部 "write" 操作 "callback" 不是异步的,并且在机械完成移动时不会被调用。它在写入操作后立即被调用。 Cylon 只能将角度值写入伺服系统,伺服系统以其最大速度机械移动喇叭。如果它是一个慢速伺服系统,从 0 度到 180 度可能需要整整 2 秒才能真正完成机械操作。与此同时,赛昂已经回调了。这样做的原因是因为没有办法在不做一些额外工作的情况下以对所有伺服模型始终正确的方式概括回调行为。
在约翰尼五号中,我们通过提供 "time to complete" 参数实现了速度控制。这是通过将到新角度的距离分成步数以在指定的 "time to complete" 中移动来完成的。这个过程的副作用是 Johnny-Five 伺服实例 可以 知道移动何时机械完成,因为步长更小并且时间受控。因此,我们有一个 "move:complete" 事件,该事件会在任何定时移动完成时发出。
var servo = new five.Servo(9); servo.on("move:complete", 函数() { // 我们到了! }); // 更改需要 500 毫秒才能完成 servo.to(180, 500);
可以很容易地与模拟传感器结合使用:
var servo = new five.Servo(9); var 传感器 = 新 five.Sensor({ 引脚:"A0",比例:[ 0, 180 ] }); servo.on("move:complete", 函数() { 更新(); }); 功能更新(){ // 更改需要 200 毫秒才能完成 servo.to(sensor.value, 200); } 更新();
更简单:
var servo = new five.Servo(9); var sensor = new five.Sensor("A0"); sensor.scale(0, 180).on("change", 函数() { servo.to(this.value); });