如何避免慢 setInterval?

Posted

技术标签:

【中文标题】如何避免慢 setInterval?【英文标题】:How to avoid Slow 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 【参考方案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 获取请求,否则会导致性能问题吗?

以上是关于如何避免慢 setInterval?的主要内容,如果未能解决你的问题,请参考以下文章

React.js/Redux:Reducers 中的 setInterval 和 clearInterval

setInterval方法怎么了?

在哪里调用 setInterval 反应

setInterval的使用和停用

在 setInterval 中调用 clearInterval() 不会停止 setinterval

第一次立即执行 setInterval 函数