1
\$\begingroup\$

I have been trying out AngularJS and developing a mobile application to test out its features and I wanted to see if I could somehow refactor to make my JSON response hopefully quicker in fetching the data. At the moment I have a search functionality that can display from 10 to 30.000 results and usually the application takes over 2 minutes to fetch large amount of results (which is way slower than I hoped for).

I think the reason might lie somewhere where I have the for loop because I am declaring variables inside it which is probably not a good habit but I can't seem to figure out a way to remove the variables out of the loop without breaking the app.

Here is the function fetch() to get the JSON data:

function fetch(){
$http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25000")
.success(function(response){
$scope.songs = [];
$scope.details = response;

for(var i=0; i < response.tracks.length; i++){

  var labelName = response.tracks[i].label_fk;
  var labelLow = labelName.toLowerCase();
  var resultUrl = "http://APIcall.com/stream_music_file.php?lbl="+labelLow+"&alb="+response.tracks[i].album_num+"&trk="+response.tracks[i].track_num+"";
  var imgUrl = "http://www.APIcall.com/online/music/display_album_cover/"+labelLow+"/"+response.tracks[i].album_num+"";

  var allTracks = {
    id: response.tracks[i].track_id,
    lbl_fk: response.tracks[i].label_fk,
    alb_num: response.tracks[i].album_num,
    track_num: response.tracks[i].track_num,
    track_descr: response.tracks[i].description,
    track_dur: response.tracks[i].duration,
    title: response.tracks[i].primary_title,
    artist: response.tracks[i].composers,
    img: imgUrl,
    url: resultUrl
  };

  $scope.songs.push(allTracks);
  }
  });
}

I'm pretty sure this code could be cleaned up better but I would really hope that also it might somehow be faster in fetching the data with some modifications to it.

\$\endgroup\$
2
\$\begingroup\$

Your loop is only executed after the data has been fetched, so improving it will not have any effect on how long it takes for the data to be fetched.

JavaScript doesn't have block scope but does have function scope, so variables declared within a function are hoisted to the top of that function. So the fact that you declare your variables inside the for loop has no effect on the speed of your loop.

function foo () {
    var fruits = ["apple", "banana", "cherry"];

    for (var i = 0; i < fruits.length; i++) {
        var fruit = fruits[i];
        console.log(fruit);
    }
}

is the same as

function foo() {
    var fruits = ["apple", "banana", "cherry"];
    var fruit;

    for (var i = 0; i < fruits.length; i++) {
        fruit = fruits[i];
        console.log(fruit);
    }
}

I think your problem is that you are fetching large amounts of data. Displaying 30000 results in one go is not good practice. Does the api you are calling support paging in any way? Can you specify an offset (or something similar) in the request? For example, can you do

$http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25&offset=0") // get results 1-25        

$http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25&offset=25") // get results 25-50

$http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25&offset=60") // get results 60-85 

If you can't restrict the number of results returned that way, you can at least make sure that you only display a manageable number of results in one go. I.e don't add all the results to the DOM at once, only add them when the user clicks "Next" (if you add some paging controls), or scrolls down far enough (if you implement an "infinite scrolling" solution).

Having said the above, there a couple of small improvements you can make to your loop i.e. cache response.tracks.length and response.tracks[i].

function fetch(){
    $http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25000").success(function(response){
        $scope.songs = [];
        $scope.details = response;

        for(var i=0, numOfTracks = response.tracks.length; i < numOfTracks; i++){
          var track = response.tracks[i];
          var labelName = track.label_fk;
          var labelLow = labelName.toLowerCase();
          var resultUrl = "http://APIcall.com/stream_music_file.php?lbl="+labelLow+"&alb="+track.album_num+"&trk="+track.track_num+"";
          var imgUrl = "http://www.APIcall.com/online/music/display_album_cover/"+labelLow+"/"+track.album_num+"";

          var allTracks = {
              id: track.track_id,
              lbl_fk: track.label_fk,
              alb_num: track.album_num,
              track_num: track.track_num,
              track_descr: track.description,
              track_dur: track.duration,
              title: track.primary_title,
              artist: track.composers,
              img: imgUrl,
              url: resultUrl
          };

          $scope.songs.push(allTracks);
      }
  });
}

Seeing as I don't think the loop is the bottleneck, I would be tempted to use map which arguably results in more readable code.

    var trackToSong = function (track) {var labelName = track.label_fk;
          var labelLow = labelName.toLowerCase();
          var resultUrl = "http://APIcall.com/stream_music_file.php?lbl="+labelLow+"&alb="+track.album_num+"&trk="+track.track_num+"";
          var imgUrl = "http://www.APIcall.com/online/music/display_album_cover/"+labelLow+"/"+track.album_num+"";

          return {
              id: track.track_id,
              lbl_fk: track.label_fk,
              alb_num: track.album_num,
              track_num: track.track_num,
              track_descr: track.description,
              track_dur: track.duration,
              title: track.primary_title,
              artist: track.composers,
              img: imgUrl,
              url: resultUrl
          };
    }

    function fetch(){
      $http.get("http://www.APIcall.com/phrase=" + $scope.search + "&perpage=25000").success(function(response){
            $scope.details = response;
            $scope.songs = response.tracks.map(trackToSong);
          }
      });
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.