【问题标题】:How to avoid Slow setInterval?如何避免慢 setInterval?
【发布时间】:2020-01-06 19:39:01
【问题描述】:

我有一个从数据库中获取的语音 URL,并想使用 react-native-sound 播放它,

所以我制作了一个可重用的组件,它“现在没有动画”呈现播放图标和持续时间

所以在声音播放之后,我先更改播放图标,然后运行setInterval 以每秒增加计数+1

但一开始更改图标和实际持续时间太慢了,以秒为单位:11计时器在9停止

那么我怎样才能让它更快...

代码

this.state = {
      playingNow: false,
      spinValue: new Animated.Value(0),
      timer: 0,
    };

//   get URL sound from DB then play it :)
  play = async () => {
    const {VoiceURL} = this.props;
    console.log('Play Func Object:', VoiceURL);
    const sound = new Sound(VoiceURL, '', error => {
      if (error) {
        console.log('failed to load the sound', error);
        return;
      } else {
        // Animated.timing(this.state.spinValue, {
        //   toValue: 1,
        //   duration: sound. _duration * 1100 || 1000,
        //   easing: Easing.linear,
        //   useNativeDriver: true,
        // }).start(() => {
        //   this.state.spinValue.setValue(0);
        // });
        this.interval = setInterval(
          () =>
            this.setState({
              playingNow: true,
              timer: this.state.timer + 1,
            }),
          1000,
        );
        sound.play(success => {
          if (success) {
            //   That's mean sound is finish
            console.log('success?', success);
            this.setState(
              {playingNow: false, timer: 0},
              () => sound.stop(),
              clearInterval(this.interval),
            );
            console.log('successfully finished playing');
          } else {
            console.log('playback failed due to audio decoding errors');
          }
        });
        console.log(
          'duration in seconds: ' +
            sound.getDuration() +
            'number of channels: ' +
            sound.getNumberOfChannels(),
        );
        sound.getCurrentTime(seconds => console.log('at: ' + seconds));
      }
      sound.setNumberOfLoops(0);
    });
    console.log('in_play??', sound);
    return sound;
  };

这就是渲染一个 UI

  _renderPlayButton = onPress => {
    const {timer} = this.state;
    let icon = this.state.playingNow ? 'pause' : 'play-arrow';
    // const spin = this.state.spinValue.interpolate({
    //   inputRange: [0, 1],
    //   outputRange: [0, -120],
    // });
    return (
      <View
        style={{
          opacity: this.props.opacity,
          alignItems: 'center',
          flexDirection: 'row',
        }}>
        <TouchableOpacity
          style={{backgroundColor: '#1E558E', borderRadius: 100}}
          onPress={onPress}>
          <Icon name={icon} color="#fff" size={25} style={{padding: 2}} />
        </TouchableOpacity>
        <View
          style={{flexDirection: 'row', marginLeft: 5, alignItems: 'center'}}>
          {/* <Animated.View
            style={{
              backgroundColor: '#f00',
              borderRadius: 10,
              width: 15,
              height: 15,
              zIndex: 10,
              transform: [{translateX: spin}],
            }}
          /> */}
          <View
            style={{
              width: 120,
              backgroundColor: '#a7a7a7',
              height: 2,
            }}
          />
          <Text style={{color: '#777', marginBottom: 5, marginLeft: 10}}>
            00:
            {('0' + (timer || 0)).slice(-2)}
            {console.log('timer-state:', timer)}
          </Text>
        </View>
      </View>
    );
  };

JSX

      <View>
        {this._renderPlayButton(() => {
          this.play();
        })}
      </View>

【问题讨论】:

  • 不知道这是否是问题的原因,但您不应在传递给setState 的对象中直接使用this.state。请改用function form
  • @RobinZigmond U 的意思是setState 计时器?
  • 是的。将其更改为this.setState(oldState =&gt; ({playingNow: true, timer: oldState.timer + 1}))。我不能肯定地说这会解决问题(如果我确定我会给出答案),但在我看来这当然是可能的。我链接到的文章应该解释为什么这是必要的。
  • @RobinZigmond 遗憾地没有解决问题:\
  • @RobinZigmond 当我使用这种方式并在_renderPlayButton() 中记录timer 时,它记录了 125 次,虽然声音只有 3 秒:O

标签: javascript reactjs react-native audio


【解决方案1】:

在处理实时数据时,永远不要自己计算,始终使用可用的真实数据。

使用Sound,它看起来像getCurrentTime。起初,它会显示为0 秒,这就是您使用间隔开头的原因。

// Set it playing as soon as possible.
this.setState({ playingNow: true });

this.interval = setInterval(
  () =>
    sound.getCurrentTime(seconds => {
      this.setState({ timer: Math.floor(seconds) });
    }),
  500 // reduce the delay so it don't skip a second.
);

请注意,我没有测试此答案中的代码。此外,对componentWillUnmount 进行正确清理也很重要,例如在声音对象上调用.release()

【讨论】:

  • release() 是做什么的,为什么要在componentWillUnmount 上调用它
  • @DevAS 根据文档,它会释放音频的内存。不过,我从来没有做过 React Native 开发,也没有使用过这个 API,所以我不能确定最好在哪里调用它。
  • @EmileBergeron 感谢您的回答,但我在十进制中得到了秒,像这样 2.072 它不能很好地工作,何时使用 Math.floor(second) 它跳过了一些数字
  • @OliverD 我更新了答案,因此不太可能跳过第二次更新。
  • @EmileBergeron 嗨,希望你一切都好。我有一个简单的问题,是否可以使用 setInterval 并继续每 5 秒调用一次我的 API 获取请求,否则会导致性能问题吗?
猜你喜欢
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
  • 2020-06-20
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
相关资源
最近更新 更多