处理Moment JS(Angular)时遇到问题

时间:2015-04-20 14:28:53

标签: angularjs momentjs

我遇到了Moment JS的问题。基本上,我有一些广播电台的元数据,在我的php电话中,我得到了歌曲的“持续时间”,歌曲开始时的“时间戳”。

我用Moment JS做了一些计算,以获得完成歌曲的时间,然后我找到了区别。然而,差异是返回负数,然后打破应用程序。

如果有人可以帮助我那会很棒。

这是我的插件http://plnkr.co/edit/joVLYdTKY5dZBOTNfTOI

服务

angular.module('starter', [])

.run(function(CurrentTrack){
   CurrentTrack.refreshTrackData();
})

.controller('radioCtrl', function($scope,CurrentTrack) {  
   console.log(CurrentTrack);
   $scope.CurrentTrack = CurrentTrack;  
})

.service('CurrentTrack',function(radioData,$timeout){

   var currentTrack = this;

   this.setTrackData = function(trackData){

      currentTrack.coverUrl = trackData.cover_url;
      currentTrack.title = trackData.title;
      currentTrack.artist = trackData.artist;
      currentTrack.duration = moment.duration(parseInt(trackData.duration));
      currentTrack.startedAt = moment.unix(trackData.timestamp);
      currentTrack.finishesAt = moment(this.startedAt.add(this.duration));
      currentTrack.updateIn = this.finishesAt.diff(moment());

      currentTrack.refreshing = false;
      return currentTrack.updateIn;
   }

   this.refreshTrackData = function(){
      currentTrack.refreshing = true;
      return radioData.refresh()
         .then(currentTrack.setTrackData.bind(currentTrack))
         .then(currentTrack.scheduleUpdate);
   }

   this.scheduleUpdate = function(ms){
      console.log(ms)
      $timeout(function(){
         currentTrack.refreshTrackData()
      },ms);
      return;
   }  
})

.factory('radioData', function($http,$timeout) {
   var retries = 0;

   function parseResponse(response){
      retries = 0;
      if(!response.data.results){
         console.log('no results')
         return false;
      }
      console.log('refreshed...')
      return response.data.results[0];
   }

   function makeRequest(){
      console.log('refreshing...')
      return $http.get('http://radio-sante-animale.fr/blah11.php?  callback=jsonpCallback')
   }

   function retry(errResponse){
      console.error('timed out');
      //wait for a sec
      retries++;
      if(retries > 5){
         throw new Error('timed out after 5 attempts!');
      }
      //oops
      return $timeout(makeRequest,1000).then(null,retry);
   }

   var radioData = {
      refresh: function() {
         return makeRequest()
           .then(null,retry)
           .then(parseResponse)
           .catch(function(err){
               console.log(err);
           });
      }
   };
   return radioData;
});

3 个答案:

答案 0 :(得分:1)

首先我改变了:

currentTrack.finishesAt = moment(this.startedAt.add(this.duration));

到:

currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration);

在原始代码中,您正在改变startedAt时间然后克隆。我还将所有this更改为currentTrack以使其更加一致。

问题

当服务器保留的时间和客户端保持的时间不同时(不是因为您有任何相反的情况),错误就会显示出来。

服务器基本上会向您发送trackData.timestamp您解析并转换为片刻以用作startedAt时间。然后,您将trackData.duration更改为moment.duration并将其添加到startedAt时间,以获得finishesAt时间。

如果客户端保持的时间超过了服务器的时间,则计算的finishesAt时间将早于实际歌曲结束的时间。一个夸张的例子使这更清楚。

var app = angular.module('app', []);

app.controller('myController', function($scope, $timeout, $interval, Server) {
  function updateTime() {
    $scope.serverTime = moment().subtract(1,'s');
    $scope.clientTime = moment();  
  }
  
  function refreshInfo() {
    Server.getSongInfo().then(parseInfo).then(scheduleRefresh);
  };
  
  function parseInfo(trackData) {
    $scope.songInfo = trackData;
    var startedAt = trackData.timestamp;
    $scope.finishesAt = moment(startedAt).add(trackData.duration, 'ms');
    $scope.updateIn = $scope.finishesAt.diff(moment());
    return $scope.updateIn;
  }
  
  function scheduleRefresh(updateIn) {
    if (updateIn < 0) {
      $scope.bugged = true;
    } else {
      $scope.bugged = false;
    }
    $timeout(refreshInfo, updateIn);
  }
  
  $scope.songInfo = "loading";
  updateTime();
  refreshInfo();
  
  $interval(updateTime, 1000);
});

app.service('Server', function($timeout, $interval) {
  var song = {
    duration: 5000
  };
  
  this.getSongInfo = function() {
    return $timeout(function() { return this.trackData });
  };
  
  function nextSong() {  
    this.trackData = {
      duration: song.duration,
      timestamp: moment().subtract(1,'s')
    };
  }
  
  nextSong();
  
  $interval(nextSong, song.duration);
});
.container {
  display: flex;
  flex-flow: row wrap;
}
.row {  
  display: flex;
  flex-direction: row;
  flex-flow: space-around;
  width: 100%;
}
.col {
  margin: auto;
  text-align: center;
}
.red {
  background-color: red;
}
<head>
  <script data-require="angular.js@1.4.0-beta.3" data-semver="1.4.0-beta.3" src="https://code.angularjs.org/1.4.0-beta.3/angular.js"></script>
  <script data-require="moment.js@2.8.3" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
</head>

<div ng-app='app' ng-controller='myController'>
  <div class="container">
    <div class='row'>
      <div class='col' ng-class='{red:bugged}'>
        <h3>Song Info</h3>
        <div>{{ songInfo }}</div>
      </div>
    </div>
    <div class="row">
      <div class='col'>
        <h3>Server</h3>
        <div>{{ serverTime.format("hh:mm:ss") }}</div>
      </div>
      <div class='col'>
        <h3>Finishes At</h3>
        <div>{{ finishesAt.format("hh:mm:ss") }}</div>
      </div>   
      <div class='col'>
        <h3>Update In</h3>
        <div>{{ updateIn }}</div>
      </div>  
      <div class='col'>
        <h3>Client</h3>
        <div>{{ clientTime.format("hh:mm:ss") }}</div>
      </div>
    </div>
  </div>
</div>

  

每当歌曲信息div为红色时,客户端就处于循环中,它正在请求新的曲目信息并解析出比当前时刻更早的结束时间,这会立即使其请求新的曲目信息。

angular.module('starter', [])

.run(function(CurrentTrack) {
  CurrentTrack.refreshTrackData();
})

.controller('radioCtrl', function($scope, CurrentTrack) {
  $scope.CurrentTrack = CurrentTrack;

})

.service('CurrentTrack', function(radioData, $timeout) {

  var currentTrack = this;

  this.setTrackData = function(trackData) {
    currentTrack.coverUrl = trackData.cover_url;
    currentTrack.title = trackData.title;
    currentTrack.artist = trackData.artist;
    currentTrack.duration = moment.duration(parseInt(trackData.duration));
    currentTrack.startedAt = moment.unix(trackData.timestamp);
    currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration);
    currentTrack.updateIn = currentTrack.finishesAt.diff(moment())
    
    console.log(currentTrack, trackData);
    currentTrack.refreshing = false;
    return currentTrack.updateIn;
  }

  this.refreshTrackData = function() {
    currentTrack.refreshing = true;
    return radioData.refresh()
      .then(currentTrack.setTrackData)
      .then(currentTrack.scheduleUpdate);
  }

  this.scheduleUpdate = function(ms) {
    console.log("update in " + ms)
    $timeout(function() {
      currentTrack.refreshTrackData()
    }, ms);
    return;
  }
})


.factory('radioData', function($http, $timeout) {

  var retries = 0;

  function parseResponse(response) {
    retries = 0;
    if (!response.data.results) {
      console.log('no results')
      return false;
    }
    console.log('response parsed.')
    return response.data.results[0];
  }

  function makeRequest() {
    console.log('making request.')
    return $http.get('http://radio-sante-animale.fr/blah11.php?callback=jsonpCallback')
  }

  function retry(errResponse) {
    console.error('timed out');
    //wait for a sec
    retries++;
    if (retries > 5) {
      throw new Error('timed out after 5 attempts!');
    }
    //oops
    return $timeout(makeRequest, 1000).then(parseResponse, retry);
  }

  var radioData = {
    refresh: function() {
      return makeRequest()
        .then(parseResponse, retry)
        .catch(function(err) {
          console.log(err);
        });
    }
  };
  return radioData;
});
<!DOCTYPE html>
<html ng-app="starter">

<head>
  <script data-require="angular.js@1.4.0-beta.3" data-semver="1.4.0-beta.3" src="https://code.angularjs.org/1.4.0-beta.3/angular.js"></script>
  <script data-require="moment.js@2.8.3" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
</head>

<body ng-controller="radioCtrl">
  <h3>Current Music Information</h3>
  <p ng-show="CurrentTrack.refreshing">refreshing...</p>

  <img style="width:300px;height:300px;" src="{{CurrentTrack.coverUrl}}" alt="">
  <p>
    Title : {{ CurrentTrack.title }}
    <br />Artist : {{ CurrentTrack.artist }}
    <br />The song started at {{ CurrentTrack.startedAt }}
    <br />Duration of the song {{ CurrentTrack.duration.asSeconds() }} seconds
    <br />Finishes At {{ CurrentTrack.finishesAt }}
    <br />Update In {{ CurrentTrack.updateIn }}
    <br />
</body>

</html>

我实际上不确定解决此问题的最佳方法,但希望有人能有更好的答案。

黑客解决方案是为finishesAt添加更多时间(一些可接受的错误量),以提供一点余地。

currentTrack.finishesAt = moment(currentTrack.startedAt).add(currentTrack.duration).add(1, 's');

答案 1 :(得分:1)

在我的方面,它通过在$ timeout方法中添加 Math.abs 来实现

this.scheduleUpdate = function(ms) {
    console.log( 'update in :' + ms)
    $timeout(function() {
        currentTrack.refreshTrackData()
    }, Math.abs(ms));
    return;
}

答案 2 :(得分:-1)

来自http://momentjs.com/docs/#/displaying/difference/

  

如果时刻早于你传递的那一刻   moment.fn.diff,返回值为负。

您需要撤消差异中的日期。

编辑:喜欢这个 -

currentTrack.updateIn = moment().diff(this.finishesAt);