草庐IT

javascript - 在React/Flux中处理计时器

coder 2024-05-05 原文

我正在开发一个应用程序,在该应用程序中,我希望计时器从60秒倒计时到0,然后更改一些内容,然后计时器在60再次重启。

我已经在React和Flux中实现了它,但是由于我是新手,所以我仍然遇到一些问题。

我现在想为计时器添加一个开始/停止按钮。我不确定在哪里放置/处理计时器状态。

我有一个组件Timer.jsx,看起来像这样:

var React = require('react');
var AppStore = require('../stores/app-store.js');
var AppActions = require('../actions/app-actions.js');

function getTimeLeft() {
  return {
    timeLeft: AppStore.getTimeLeft()
  }
}

var Timer = React.createClass({
  _tick: function() {
    this.setState({ timeLeft: this.state.timeLeft - 1 });
    if (this.state.timeLeft < 0) {
      AppActions.changePattern();
      clearInterval(this.interval);
    }
  },
  _onChange: function() {
    this.setState(getTimeLeft());
    this.interval = setInterval(this._tick, 1000);
  },
  getInitialState: function() {
    return getTimeLeft();
  },
  componentWillMount: function() {
    AppStore.addChangeListener(this._onChange);
  },
  componentWillUnmount: function() {
    clearInterval(this.interval);
  },
  componentDidMount: function() {
    this.interval = setInterval(this._tick, 1000);
  },
  render: function() {
    return (
      <small>
        ({ this.state.timeLeft })
      </small>
    )
  }
});

module.exports = Timer;

它从商店那里获取倒计时持续时间,我在那里:
var _timeLeft = 60;
现在,当我想实现启动/停止按钮时,我觉得我也应该通过Flux Actions来实现,对吗?所以我想在我的商店里放这样的东西:
dispatcherIndex: AppDispatcher.register(function(payload) {
  var action = payload.action;

  switch(action.actionType) {
    case AppConstants.START_TIMER:
      // do something
      break;
    case AppConstants.STOP_TIMER:
      // do something
      break;
    case AppConstants.CHANGE_PATTERN:
      _setPattern();
      break;
  }

  AppStore.emitChange();

  return true;
})

但是,由于我的Timer组件当前正在处理setInterval,所以我不知道如何使我的START / STOP_TIMER事件正常工作。我应该将setInterval内容从Timer组件移到Store并以某种方式传递给我的组件吗?

完整代码可以在here中找到。

最佳答案

我最终下载了您的代码并实现了所需的启动/停止/重置功能。我认为这可能是解释问题的最佳方法-显示可以运行和测试的代码以及一些注释。

实际上,我最终得到了两种实现。我将它们称为实现A和实现B。

我认为展示这两种实现会很有趣。希望它不会引起太多困惑。

记录下来,实现A是更好的版本。

以下是这两种实现的简要说明:

实现A

此版本在App组件级别跟踪状态。通过将props传递到Timer组件来管理计时器。计时器组件确实会跟踪自己的剩余时间状态。

实现B

此版本使用TimerStore和TimerAction模块来管理组件的状态和事件,从而在Timer组件级别跟踪计时器状态。

实现B的最大(可能是致命的)缺点是您只能拥有一个Timer组件。这是由于TimerStore和TimerAction模块本质上是Singletons。

|

|

实现A

|

|

此版本在App组件级别跟踪状态。这里的大多数注释都在该版本的代码中。

通过将props传递给计时器来管理计时器。

此实现的代码更改 list :

  • app-constants.js
  • app-actions.js
  • app-store.js
  • App.jsx
  • Timer.jsx

  • app-constants.js

    在这里,我只是添加了一个用于重置计时器的常量。
    module.exports = {
      START_TIMER: 'START_TIMER',
      STOP_TIMER: 'STOP_TIMER',
      RESET_TIMER: 'RESET_TIMER',
      CHANGE_PATTERN: 'CHANGE_PATTERN'
    };
    

    app-actions.js

    我刚刚添加了一个调度方法来处理重置计时器操作。
    var AppConstants = require('../constants/app-constants.js');
    var AppDispatcher = require('../dispatchers/app-dispatcher.js');
    
    var AppActions = {
      changePattern: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.CHANGE_PATTERN
        })
      },
      resetTimer: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.RESET_TIMER
        })
      },
      startTimer: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.START_TIMER
        })
      },
      stopTimer: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.STOP_TIMER
        })
      }
    };
    
    module.exports = AppActions;
    

    app-store.js

    这是情况有所改变的地方。我在进行更改的地方添加了详细的注释。
    var AppDispatcher = require('../dispatchers/app-dispatcher.js');
    var AppConstants = require('../constants/app-constants.js');
    var EventEmitter = require('events').EventEmitter;
    var merge = require('react/lib/Object.assign');
    
    
    // I added a TimerStatus model (probably could go in its own file)
    // to manage whether the timer is "start/stop/reset".
    //
    // The reason for this is that reset state was tricky to handle since the Timer
    // component no longer has access to the "AppStore". I'll explain the reasoning for
    // that later.
    //
    // To solve that problem, I added a `reset` method to ensure the state
    // didn't continuously loop "reset". This is probably not very "Flux".
    //
    // Maybe a more "Flux" alternative is to use a separate TimerStore and
    // TimerAction? 
    //
    // You definitely don't want to put them in AppStore and AppAction
    // to make your timer component more reusable.
    //
    var TimerStatus = function(status) {
      this.status = status;
    };
    
    TimerStatus.prototype.isStart = function() {
      return this.status === 'start';
    };
    
    TimerStatus.prototype.isStop = function() {
      return this.status === 'stop';
    };
    
    TimerStatus.prototype.isReset = function() {
      return this.status === 'reset';
    };
    
    TimerStatus.prototype.reset = function() {
      if (this.isReset()) {
        this.status = 'start';
      }
    };
    
    
    var CHANGE_EVENT = "change";
    
    var shapes = ['C', 'A', 'G', 'E', 'D'];
    var rootNotes = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'];
    
    var boxShapes = require('../data/boxShapes.json');
    
    
    // Added a variable to keep track of timer state. Note that this state is
    // managed by the *App Component*.
    var _timerStatus = new TimerStatus('start');
    
    
    var _pattern = _setPattern();
    
    function _setPattern() {
      var rootNote = _getRootNote();
      var shape = _getShape();
      var boxShape = _getBoxForShape(shape);
    
      _pattern = {
        rootNote: rootNote,
        shape: shape,
        boxShape: boxShape
      };
    
      return _pattern;
    }
    
    function _getRootNote() {
      return rootNotes[Math.floor(Math.random() * rootNotes.length)];
    }
    
    function _getShape() {
      return shapes[Math.floor(Math.random() * shapes.length)];
    }
    
    function _getBoxForShape(shape) {
      return boxShapes[shape];
    }
    
    
    // Simple function that creates a new instance of TimerStatus set to "reset"
    function _resetTimer() {
      _timerStatus = new TimerStatus('reset');
    }
    
    // Simple function that creates a new instance of TimerStatus set to "stop"
    function _stopTimer() {
      _timerStatus = new TimerStatus('stop');
    }
    
    // Simple function that creates a new instance of TimerStatus set to "start"
    function _startTimer() {
      _timerStatus = new TimerStatus('start');
    }
    
    
    var AppStore = merge(EventEmitter.prototype, {
      emitChange: function() {
        this.emit(CHANGE_EVENT);
      },
    
      addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
      },
    
      removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
      },
    
    
      // Added this function to get timer status from App Store
      getTimerStatus: function() {
        return _timerStatus;
      },
    
    
      getPattern: function() {
        return _pattern;
      },
    
      dispatcherIndex: AppDispatcher.register(function(payload) {
        var action = payload.action;
    
        switch(action.actionType) {
          case AppConstants.RESET_TIMER:
            // Handle reset action
            _resetTimer();
            break;
          case AppConstants.START_TIMER:
            // Handle start action
            _startTimer();
            break;
          case AppConstants.STOP_TIMER:
            // Handle stop action
            _stopTimer();
            break;
          case AppConstants.CHANGE_PATTERN:
            _setPattern();
            break;
        }
    
        AppStore.emitChange();
    
        return true;
      })
    });
    
    module.exports = AppStore;
    

    App.jsx

    App.jsx中有许多更改,特别是我们已将状态从计时器组件移至App组件。再次在代码中详细注释。
    var React = require('react');
    
    var Headline = require('./components/Headline.jsx');
    var Scale = require('./components/Scale.jsx');
    var RootNote = require('./components/RootNote.jsx');
    var Shape = require('./components/Shape.jsx');
    var Timer = require('./components/Timer.jsx');
    
    
    // Removed AppActions and AppStore from Timer component and moved
    // to App component. This is done to to make the Timer component more
    // reusable.
    var AppActions = require('./actions/app-actions.js');
    var AppStore = require('./stores/app-store.js');
    
    
    // Use the AppStore to get the timerStatus state
    function getAppState() {
      return {
        timerStatus: AppStore.getTimerStatus()
      }
    }
    
    var App = React.createClass({
      getInitialState: function() {
        return getAppState();
      },
    
    
      // Listen for change events in AppStore
      componentDidMount: function() {
        AppStore.addChangeListener(this.handleChange);
      },
    
    
      // Stop listening for change events in AppStore
      componentWillUnmount: function() {
        AppStore.removeChangeListener(this.handleChange);
      },
    
    
      // Timer component has status, defaultTimeout attributes.
      // Timer component has an onTimeout event (used for changing pattern)
      // Add three basic buttons for Start/Stop/Reset
      render: function() {
        return (
          <div>
            <header>
              <Headline />
              <Scale />
            </header>
            <section>
              <RootNote />
              <Shape />
              <Timer status={this.state.timerStatus} defaultTimeout="15" onTimeout={this.handleTimeout} />
              <button onClick={this.handleClickStart}>Start</button>
              <button onClick={this.handleClickStop}>Stop</button>
              <button onClick={this.handleClickReset}>Reset</button>
            </section>
          </div>
        );
      },
    
    
      // Handle change event from AppStore
      handleChange: function() {
        this.setState(getAppState());
      },
    
    
      // Handle timeout event from Timer component
      // This is the signal to change the pattern.
      handleTimeout: function() {
        AppActions.changePattern();
      },
    
    
      // Dispatch respective start/stop/reset actions
      handleClickStart: function() {
        AppActions.startTimer();
      },
      handleClickStop: function() {
        AppActions.stopTimer();
      },
      handleClickReset: function() {
        AppActions.resetTimer();
      }
    });
    
    module.exports = App;
    

    Timer.jsx

    自从我删除了TimerAppStore依赖项以使AppActions组件更可重用以来,Timer也进行了许多更改。详细注释在代码中。
    var React = require('react');
    
    
    // Add a default timeout if defaultTimeout attribute is not specified.
    var DEFAULT_TIMEOUT = 60;
    
    var Timer = React.createClass({
    
      // Normally, shouldn't use props to set state, however it is OK when we
      // are not trying to synchronize state/props. Here we just want to provide an option to specify
      // a default timeout.
      //
      // See http://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html)
      getInitialState: function() {
        this.defaultTimeout = this.props.defaultTimeout || DEFAULT_TIMEOUT;
        return {
          timeLeft: this.defaultTimeout
        };
      },
    
    
      // Changed this to `clearTimeout` instead of `clearInterval` since I used `setTimeout`
      // in my implementation
      componentWillUnmount: function() {
        clearTimeout(this.interval);
      },
    
      // If component updates (should occur when setState triggered on Timer component
      // and when App component is updated/re-rendered)
      //
      // When the App component updates we handle two cases:
      // - Timer start status when Timer is stopped
      // - Timer reset status. In this case, we execute the reset method of the TimerStatus
      //   object to set the internal status to "start". This is to avoid an infinite loop
      //   on the reset case in componentDidUpdate. Kind of a hack...
      componentDidUpdate: function() {
        if (this.props.status.isStart() && this.interval === undefined) {
          this._tick();
        } else if (this.props.status.isReset()) {
          this.props.status.reset();
          this.setState({timeLeft: this.defaultTimeout});
        }
      },
    
      // On mount start ticking
      componentDidMount: function() {
        this._tick();
      },
    
    
      // Tick event uses setTimeout. I find it easier to manage than setInterval.
      // We just keep calling setTimeout over and over unless the timer status is
      // "stop".
      //
      // Note that the Timer states is handled here without a store. You could probably
      // say this against the rules of "Flux". But for this component, it just seems unnecessary
      // to create separate TimerStore and TimerAction modules.
      _tick: function() {
        var self = this;
        this.interval = setTimeout(function() {
          if (self.props.status.isStop()) {
            self.interval = undefined;
            return;
          }
          self.setState({timeLeft: self.state.timeLeft - 1});
          if (self.state.timeLeft <= 0) {
            self.setState({timeLeft: self.defaultTimeout});
            self.handleTimeout();
          }
          self._tick();
        }, 1000);
      },
    
      // If timeout event handler passed to Timer component,
      // then trigger callback.
      handleTimeout: function() {
        if (this.props.onTimeout) {
          this.props.onTimeout();
        }
      }
      render: function() {
        return (
          <small className="timer">
            ({ this.state.timeLeft })
          </small>
        )
      },
    });
    
    module.exports = Timer;
    

    |

    |

    实现B

    |

    |

    代码更改 list :
  • app-constants.js
  • timer-actions.js(新)
  • timer-store.js(新)
  • app-store.js
  • App.jsx
  • Timer.jsx

  • app-constants.js

    因为它们处理Timer组件,所以它们可能应该放在一个名为timer-constants.js的文件中。
    module.exports = {
      START_TIMER: 'START_TIMER',
      STOP_TIMER: 'STOP_TIMER',
      RESET_TIMER: 'RESET_TIMER',
      TIMEOUT: 'TIMEOUT',
      TICK: 'TICK'
    };
    

    timer-actions.js

    该模块是不言自明的。我添加了三个事件-超时,滴答和重置。有关详细信息,请参见代码。
    var AppConstants = require('../constants/app-constants.js');
    var AppDispatcher = require('../dispatchers/app-dispatcher.js');
    
    module.exports = {
    
      // This event signals when the timer expires.
      // We can use this to change the pattern.
      timeout: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.TIMEOUT
        })
      },
    
      // This event decrements the time left
      tick: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.TICK
        })
      },
    
      // This event sets the timer state to "start"
      start: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.START_TIMER
        })
      },
    
      // This event sets the timer state to "stop"
      stop: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.STOP_TIMER
        })
      },
    
      // This event resets the time left and sets the state to "start"
      reset: function() {
        AppDispatcher.handleViewAction({
          actionType: AppConstants.RESET_TIMER
        })
      },
    };
    

    timer-store.js

    我从AppStore中分离出了计时器内容。这是为了使Timer组件更具可重用性。

    计时器存储区跟踪以下状态:
  • 计时器状态-可以“开始”或“停止”
  • 剩余时间-计时器
  • 剩余时间

    计时器存储处理以下事件:
  • 计时器启动事件将计时器状态设置为启动。
  • 计时器停止事件将计时器状态设置为停止。
  • 节拍事件将剩余的时间减少1
  • 计时器重置事件将剩余时间设置为默认时间,并将计时器状态设置为启动

  • 这是代码:
    var AppDispatcher = require('../dispatchers/app-dispatcher.js');
    var AppConstants = require('../constants/app-constants.js');
    var EventEmitter = require('events').EventEmitter;
    var merge = require('react/lib/Object.assign');
    
    var CHANGE_EVENT = "change";
    var TIMEOUT_SECONDS = 15;
    
    var _timerStatus = 'start';
    var _timeLeft = TIMEOUT_SECONDS;
    
    function _resetTimer() {
      _timerStatus = 'start';
      _timeLeft = TIMEOUT_SECONDS;
    }
    
    function _stopTimer() {
      _timerStatus = 'stop';
    }
    
    function _startTimer() {
      _timerStatus = 'start';
    }
    
    function _decrementTimer() {
      _timeLeft -= 1;
    }
    
    var TimerStore = merge(EventEmitter.prototype, {
      emitChange: function() {
        this.emit(CHANGE_EVENT);
      },
    
      addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
      },
    
      removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
      },
    
      getTimeLeft: function() {
        return _timeLeft;
      },
    
      getStatus: function() {
        return _timerStatus;
      },
    
      dispatcherIndex: AppDispatcher.register(function(payload) {
        var action = payload.action;
    
        switch(action.actionType) {
          case AppConstants.START_TIMER:
            _startTimer();
            break;
          case AppConstants.STOP_TIMER:
            _stopTimer();
            break;
          case AppConstants.RESET_TIMER:
            _resetTimer();
            break;
          case AppConstants.TIMEOUT:
            _resetTimer();
            break;
          case AppConstants.TICK:
            _decrementTimer();
            break;
        }
    
        TimerStore.emitChange();
    
        return true;
      })
    });
    
    module.exports = TimerStore;
    

    app-store.js

    可以将其命名为pattern-store.js,尽管您需要进行一些更改以使其可重用。具体来说,我直接在监听Timer的TIMEOUT Action /事件以触发模式更改。如果要重用模式更改,则可能不希望依赖。例如,如果您想通过单击按钮或其他方式来更改图案。

    除此之外,我刚刚从AppStore中删除了所有与Timer相关的功能。
    var AppDispatcher = require('../dispatchers/app-dispatcher.js');
    var AppConstants = require('../constants/app-constants.js');
    var EventEmitter = require('events').EventEmitter;
    var merge = require('react/lib/Object.assign');
    
    var CHANGE_EVENT = "change";
    
    var shapes = ['C', 'A', 'G', 'E', 'D'];
    var rootNotes = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'];
    
    var boxShapes = require('../data/boxShapes.json');
    
    var _pattern = _setPattern();
    
    function _setPattern() {
      var rootNote = _getRootNote();
      var shape = _getShape();
      var boxShape = _getBoxForShape(shape);
    
      _pattern = {
        rootNote: rootNote,
        shape: shape,
        boxShape: boxShape
      };
    
      return _pattern;
    }
    
    function _getRootNote() {
      return rootNotes[Math.floor(Math.random() * rootNotes.length)];
    }
    
    function _getShape() {
      return shapes[Math.floor(Math.random() * shapes.length)];
    }
    
    function _getBoxForShape(shape) {
      return boxShapes[shape];
    }
    
    var AppStore = merge(EventEmitter.prototype, {
      emitChange: function() {
        this.emit(CHANGE_EVENT);
      },
    
      addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
      },
    
      removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
      },
    
      getPattern: function() {
        return _pattern;
      },
    
      dispatcherIndex: AppDispatcher.register(function(payload) {
        var action = payload.action;
    
        switch(action.actionType) {
          case AppConstants.TIMEOUT:
            _setPattern();
            break;
        }
    
        AppStore.emitChange();
    
        return true;
      })
    });
    
    module.exports = AppStore;
    

    App.jsx

    在这里,我只添加了一些用于开始/停止/重置的按钮。单击时,将调度TimerAction。因此,如果您单击“停止”按钮,我们称为TimerAction.stop()
    var React = require('react');
    
    var Headline = require('./components/Headline.jsx');
    var Scale = require('./components/Scale.jsx');
    var RootNote = require('./components/RootNote.jsx');
    var Shape = require('./components/Shape.jsx');
    var Timer = require('./components/Timer.jsx');
    var TimerActions = require('./actions/timer-actions.js');
    
    
    var App = React.createClass({
      render: function() {
        return (
          <div>
            <header>
              <Headline />
              <Scale />
            </header>
            <section>
              <RootNote />
              <Shape />
              <Timer />
              <button onClick={this.handleClickStart}>Start</button>
              <button onClick={this.handleClickStop}>Stop</button>
              <button onClick={this.handleClickReset}>Reset</button>
            </section>
          </div>
        );
      },
      handleClickStart: function() {
        TimerActions.start();
      },
      handleClickStop: function() {
        TimerActions.stop();
      },
      handleClickReset: function() {
        TimerActions.reset();
      }
    });
    
    module.exports = App;
    

    Timer.jsx

    主要变化之一是我们使用的是TimerAction和TimerStore而不是最初使用的AppAction和AppStore。原因是尝试使Timer组件更具可重用性。

    计时器具有以下状态:
  • 状态计时器状态可以是“开始”或“停止”
  • 时间左计时器
  • 剩余时间

    请注意,我使用了setTimeout而不是setInterval。我发现setTimeout更易于管理。

    大部分逻辑都在_tick方法中。基本上,只要状态为“开始”,我们就继续调用setTimeout

    当计时器达到零时,我们发出timeout事件的信号。 TimerStore和AppStore正在侦听此事件。
  • TimerStore只会重置计时器。相同的重置事件。
  • AppStore将更改模式。

  • 如果计时器未达到零,我们通过发信号“滴答”事件减去一秒钟。

    最后,我们需要处理计时器停止然后再启动的情况。这可以通过componentDidUpdate钩子(Hook)来处理。当组件的状态更改或父组件被重新渲染时,将调用此挂钩。

    componentDidUpdate方法中,只有在状态为“开始”且未定义超时标识符的情况下,我们才确保启动“计时”。我们不希望运行多个setTimeouts。
    var React = require('react');
    
    var TimerActions = require('../actions/timer-actions.js');
    var TimerStore = require('../stores/timer-store.js');
    
    function getTimerState() {
      return {
        status: TimerStore.getStatus(),
        timeLeft: TimerStore.getTimeLeft()
      }
    }
    
    var Timer = React.createClass({
      _tick: function() {
        var self = this;
        this.interval = setTimeout(function() {
          if (self.state.status === 'stop') {
            self.interval = undefined;
            return;
          }
    
          if (self.state.timeLeft <= 0) {
            TimerActions.timeout();
          } else {
            TimerActions.tick();
          }
          self._tick();
        }, 1000);
      },
      getInitialState: function() {
        return getTimerState();
      },
      componentDidMount: function() {
        TimerStore.addChangeListener(this.handleChange);
        this._tick();
      },
      componentWillUnmount: function() {
        clearTimeout(this.interval);
        TimerStore.removeChangeListener(this.handleChange);
      },
      handleChange: function() {
        this.setState(getTimerState());
      },
      componentDidUpdate: function() {
        if (this.state.status === 'start' && this.interval === undefined) {
          this._tick();
        }
      },
      render: function() {
        return (
          <small className="timer">
            ({ this.state.timeLeft })
          </small>
        )
      }
    });
    
    module.exports = Timer;
    

    关于javascript - 在React/Flux中处理计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27604431/

    有关javascript - 在React/Flux中处理计时器的更多相关文章

    1. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    2. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

      我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

    3. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

      我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

    4. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

      我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

    5. ruby - Ruby 性能中的计时器 - 2

      我正在寻找一个用ruby​​演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent

    6. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

      我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

    7. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

      我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

    8. ruby-on-rails - 使用 Ruby 正确处理 Stripe 错误和异常以实现一次性收费 - 2

      我查看了Stripedocumentationonerrors,但我仍然无法正确处理/重定向这些错误。基本上无论发生什么,我都希望他们返回到edit操作(通过edit_profile_path)并向他们显示一条消息(无论成功与否)。我在edit操作上有一个表单,它可以POST到update操作。使用有效的信用卡可以正常工作(费用在Stripe仪表板中)。我正在使用Stripe.js。classExtrasController5000,#amountincents:currency=>"usd",:card=>token,:description=>current_user.email)

    9. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

      我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

    10. ruby-on-rails - Rails 处理 .Erb 与 Nils - 2

      当profile为nil时,总是让我感到悲伤...我该怎么办? 最佳答案 在View中使用变量之前,始终检查变量是否为nil。我确信这个问题有更优雅的解决方案,但这应该能让您入门。 关于ruby-on-rails-Rails处理.Erb与Nils,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/2709605/

    随机推荐