Backbone trigger()返回typeError

时间:2014-07-20 23:08:13

标签: javascript backbone.js

我从模型中调用事件时不断收到以下错误:

window.Playlist = new PlaylistModel();
Playlist.trigger("playerPlaying");
`Uncaught TypeError: Cannot read property '0' of undefined`

我的堆栈跟踪:

Uncaught TypeError: Cannot read property '0' of undefined
triggerEventsbackbone.js:206
Backbone.Events.triggerbackbone.js:148
onPlayerStateChangeplayer.js:101
g.Iwww-widgetapi-vfldqBTcy.js:13
g.kwww-widgetapi-vfldqBTcy.js:22
g.Jwww-widgetapi-vfldqBTcy.js:30
X.dwww-widgetapi-vfldqBTcy.js:29
Qa.fwww-widgetapi-vfldqBTcy.js:18

我挖掘骨干源代码并找到以下内容

trigger: function(name) {
  if (!this._events) return this;
  var args = slice.call(arguments, 1);
  if (!eventsApi(this, 'trigger', name, args)) return this;
  var events = this._events[name];
  var allEvents = this._events.all;
  if (events) triggerEvents(events, args);
  if (allEvents) triggerEvents(allEvents, arguments);
  return this;

在从chrome控制台设置断点后,我逐行打印了这些行。

arguments = ["playerPlaying"]
args = []
this._events = Object {change:currentSong: Array[3], change:loopActive: Array[3], playerPlaying: Array[3]}
events = [Object, Object, Object]
this = the Backbone model on which `trigger()` was called

我认为问题是arguments应该是[ModelThatTriggeredEvent,eventName],但我只是[eventName],所以args变成一个空数组。有谁知道为什么会这样?

更新

这是整个 PlaylistModel ,其中部分内容已删除。请理解代码中的混乱,因为我正在重构它以遵守Backbone的做事方式。

define([
  // These are path alias that we configured in our bootstrap
  'jquery',     // lib/jquery/jquery
  'backbone',
  '../../common/models/song',
  '../collections/songs'
], function($, Backbone, Song, Songs){

  window.AVAILABLE_CHARTS = {
    billboardChart: {
      source: "billboard",
      chart: [
        {genre: chrome.i18n.getMessage("pop"), url: 'http://www.billboard.com/rss/charts/hot-100'},
        {genre: chrome.i18n.getMessage("rock"), url: "http://www.billboard.com/rss/charts/rock-songs"},
      ]
    }
  };

  var Playlist = Backbone.Model.extend({
    defaults: {
      currentSong: null,
      nextSong: null,
      prevSong: null,
      genre: null, // initial genre
      loopActive: false,
      shuffleActive: false,
      numSongs: 10, // initial number of songs loaded
      musicChart: null
    },

    initialize: function() {
      // Setting collections/songs as its attribute
      var songs = new Songs();
      this.set('songs', songs);

      var userLocale = chrome.i18n.getMessage("@@ui_locale");
      if (userLocale == "ko" || userLocale == 'ko-kr') {
        this.set('musicChart', AVAILABLE_CHARTS.melonChart);
        this.set('genre', this.get('musicChart').chart[0].genre);
      } else {
        this.set('musicChart', AVAILABLE_CHARTS.billboardChart);
        this.set('genre', this.get('musicChart').chart[0].genre);
      }
    },

    // If loop is active, getNextSong repeats the current song
    // If shuffle is active, getNextSong plays a random song from Songs
    getNextSong: function() {
      //var idx = this.indexOf(this.getCurrentSong());
      var songs = this.get('songs');
      var idx = songs.indexOf(songs.findWhere({ title: this.get('currentSong').get('title') }));
      if (this.get('loopActive')) {
        return songs.at(idx);
      }
      if (this.get('shuffleActive')) {
        var randomIndex = Math.floor((Math.random()*songs.length));
        return songs.at(randomIndex);
      }
      if (idx != songs.length-1) return songs.at(idx+1);
      else return songs.at(0);
    },

    getPrevSong: function() {
      var songs = this.get('songs');
      var idx = songs.indexOf(songs.findWhere({ title: this.get('currentSong').get('title') }));
      if (idx != 0) return songs.at(idx-1);
      else return songs.at(songs.length-1);
    },

    // Get new songs from Billboard Chart
    // First parse the top <numSongs> from the selected <genre>
    // from Billboard, and then use YouTube gdata api to fetch
    // the songs.
    getNewSongs: function (callback, genre, numSongs) {
      // FIXME: just trigger progress
      var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
      if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(10);
      var playlist = this;
      playlist.get('songs').reset();
      // Inspect Billboard Chart to find pop songs
        $.get(url+numSongs+'/explicit=true/xml', function (data) {
          var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
          if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(30);
          var $feed = $(data).find('feed')
          var $entries = $feed.find('entry')
          var numAvailableSongs = $entries.length;
          $entries.each(function (idx, entry) {
            var title_artist_pair = $(entry).find('title')[0].innerHTML;
            var title = $.trim(title_artist_pair.split(' - ')[0]);
            var artist = $.trim(title_artist_pair.split(' - ')[1]);
            var rank = idx+1;
            var query = title + " " + artist;
            _searchYouTube(title, artist, rank, query, numAvailableSongs);
          });
          return;
        });
    }

      function _searchYouTube (title, artist, rank, query, numAvailableSongs) {
        var songs = playlist.get('songs');

        $.ajax({
          url: searchUrl,
          type: "GET",
          data: 'q='+encodeURIComponent(query),
          success: function (result) {
            //console.log("\n**** 검색: "+query);
            ajaxCount += 1;

            if (result.items.length)
              var videoId = result.items[0].id.videoId;
            else 
              var videoId = null; // Cannot find the song on YouTube

            var song = new Song({
              title: title,
              artist: artist,
              rank: parseInt(rank),
              query: query,
              videoId: videoId
            });

            // Insert songs into the playlist in the order of their ranks
            // *Note: Songs that do not exist on YouTube are ignored
            if (videoId) songs.add(song, { silent: true });

            // All the ajax calls are finished
            if (ajaxCount == numAvailableSongs) {
              var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
              if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(70);
              songs.comparator = 'rank'
              songs.sort();
              // Remove useless playlsit methods
              if (!playlist.get('currentSong')) {
                playlist.set('currentSong', songs.at(0));
              }
              callback();
            }
          },
          error: function (error) {
            ajaxCount += 1;
            if (ajaxCount == numAvailableSongs) {
              var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
              if (popupWindow) popupWindow.popupView.setProgress(70);
              if (!playlist.get('currentSong')) {
                playlist.set('currentSong', songs.at(0));
              }
              callback();
            }
          } // end of error
        }); // end of second ajax
      } // end of _searchYouTube()
    },

    lookUpAndAddSingleSong: function (query) {
      var playlist = this;
      var youtubeAPIKey = "fdf";
      var initialSearchURL = "df";
      var searchUrl = initialSearchURL + "&key=" + youtubeAPIKey;
      $.ajax({
        url: searchUrl,
        type: "GET",
        data: 'q='+encodeURIComponent(query),
        success: function (result) {
          if (result.items.length) {
            var videoId = result.items[0].id.videoId;
            var song = new Song({
              title: result.items[0].snippet.title,
              query: query,
              videoId: videoId
            });
          } else var videoId = null; // Cannot find the song on YouTube

          if (videoId) {
            playlist.get('songs').add(song);
            song.save(); // save to localStorage
          }
        }, error: function (xhr, status, errorThrown) {
          var errorMessage = "lookUpAndAddSingleSong error: check http://instantmusicapp.com";
          var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
          if (popupWindow && popupWindow.popupView) popupWindow.showErrorMessage(errorMessage);
          return;
        }
      });
    },

    setMusicChart: function (chartName) {
      // if the chart is provided, we pick from Melon, Billboard, iTunes
      if (chartName) {
        if (chartName == chrome.i18n.getMessage("melonChart"))
          this.set('musicChart', AVAILABLE_CHARTS.melonChart);
        else if (chartName == chrome.i18n.getMessage("billboardChart"))
          this.set('musicChart', AVAILABLE_CHARTS.billboardChart);
        else
          this.set('musicChart', AVAILABLE_CHARTS.itunesChart);
      // else, the user is looking for a personal favorite chart
      } else {
        this.set('musicChart', AVAILABLE_CHARTS.myChart);
      }
    },
  });

  return Playlist;
});

2 个答案:

答案 0 :(得分:0)

您的模型中存在相当多的语法错误,这可能是您无法使用bb模型发出触发器甚至是其他任何内容的原因。

第14行有一个悬空逗号(,)。例如。

尝试通过JSLint或JSHint运行模型并修复错误。可能会解决你的问题

答案 1 :(得分:0)

在大多数浏览器中都可以使用悬空逗号,但实际错误是}函数后的额外getNewSongs。我建议使用一些支持JSHint集成的IDE / Editor。你可以试试webstorm。这是更新的代码。

define([
    // These are path alias that we configured in our bootstrap
    'jquery',     // lib/jquery/jquery
    'backbone',
    '../../common/models/song',
    '../collections/songs'
], function ($, Backbone, Song, Songs) {

    window.AVAILABLE_CHARTS = {
        billboardChart: {
            source: "billboard",
            chart: [
                {genre: chrome.i18n.getMessage("pop"), url: 'http://www.billboard.com/rss/charts/hot-100'},
                {genre: chrome.i18n.getMessage("rock"), url: "http://www.billboard.com/rss/charts/rock-songs"},
            ]
        }
    };

    var Playlist = Backbone.Model.extend({
        defaults: {
            currentSong: null,
            nextSong: null,
            prevSong: null,
            genre: null, // initial genre
            loopActive: false,
            shuffleActive: false,
            numSongs: 10, // initial number of songs loaded
            musicChart: null
        },

        initialize: function () {
            // Setting collections/songs as its attribute
            var songs = new Songs();
            this.set('songs', songs);

            var userLocale = chrome.i18n.getMessage("@@ui_locale");
            if (userLocale == "ko" || userLocale == 'ko-kr') {
                this.set('musicChart', AVAILABLE_CHARTS.melonChart);
                this.set('genre', this.get('musicChart').chart[0].genre);
            } else {
                this.set('musicChart', AVAILABLE_CHARTS.billboardChart);
                this.set('genre', this.get('musicChart').chart[0].genre);
            }
        },

        // If loop is active, getNextSong repeats the current song
        // If shuffle is active, getNextSong plays a random song from Songs
        getNextSong: function () {
            //var idx = this.indexOf(this.getCurrentSong());
            var songs = this.get('songs');
            var idx = songs.indexOf(songs.findWhere({ title: this.get('currentSong').get('title') }));
            if (this.get('loopActive')) {
                return songs.at(idx);
            }
            if (this.get('shuffleActive')) {
                var randomIndex = Math.floor((Math.random() * songs.length));
                return songs.at(randomIndex);
            }
            if (idx != songs.length - 1) return songs.at(idx + 1);
            else return songs.at(0);
        },

        getPrevSong: function () {
            var songs = this.get('songs');
            var idx = songs.indexOf(songs.findWhere({ title: this.get('currentSong').get('title') }));
            if (idx != 0) return songs.at(idx - 1);
            else return songs.at(songs.length - 1);
        },

        // Get new songs from Billboard Chart
        // First parse the top <numSongs> from the selected <genre>
        // from Billboard, and then use YouTube gdata api to fetch
        // the songs.
        getNewSongs: function (callback, genre, numSongs) {
            // FIXME: just trigger progress
            var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
            if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(10);
            var playlist = this;
            playlist.get('songs').reset();
            // Inspect Billboard Chart to find pop songs
            $.get(url + numSongs + '/explicit=true/xml', function (data) {
                var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
                if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(30);
                var $feed = $(data).find('feed')
                var $entries = $feed.find('entry')
                var numAvailableSongs = $entries.length;
                $entries.each(function (idx, entry) {
                    var title_artist_pair = $(entry).find('title')[0].innerHTML;
                    var title = $.trim(title_artist_pair.split(' - ')[0]);
                    var artist = $.trim(title_artist_pair.split(' - ')[1]);
                    var rank = idx + 1;
                    var query = title + " " + artist;
                    _searchYouTube(title, artist, rank, query, numAvailableSongs);
                });
                return;
            });


            function _searchYouTube(title, artist, rank, query, numAvailableSongs) {
                var songs = playlist.get('songs');

                $.ajax({
                    url: searchUrl,
                    type: "GET",
                    data: 'q=' + encodeURIComponent(query),
                    success: function (result) {
                        //console.log("\n**** 검색: "+query);
                        ajaxCount += 1;

                        if (result.items.length)
                            var videoId = result.items[0].id.videoId;
                        else
                            var videoId = null; // Cannot find the song on YouTube

                        var song = new Song({
                            title: title,
                            artist: artist,
                            rank: parseInt(rank),
                            query: query,
                            videoId: videoId
                        });

                        // Insert songs into the playlist in the order of their ranks
                        // *Note: Songs that do not exist on YouTube are ignored
                        if (videoId) songs.add(song, { silent: true });

                        // All the ajax calls are finished
                        if (ajaxCount == numAvailableSongs) {
                            var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
                            if (popupWindow && popupWindow.popupView) popupWindow.popupView.setProgress(70);
                            songs.comparator = 'rank'
                            songs.sort();
                            // Remove useless playlsit methods
                            if (!playlist.get('currentSong')) {
                                playlist.set('currentSong', songs.at(0));
                            }
                            callback();
                        }
                    },
                    error: function (error) {
                        ajaxCount += 1;
                        if (ajaxCount == numAvailableSongs) {
                            var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
                            if (popupWindow) popupWindow.popupView.setProgress(70);
                            if (!playlist.get('currentSong')) {
                                playlist.set('currentSong', songs.at(0));
                            }
                            callback();
                        }
                    } // end of error
                }); // end of second ajax
            } // end of _searchYouTube()
        },

        lookUpAndAddSingleSong: function (query) {
            var playlist = this;
            var youtubeAPIKey = "fdf";
            var initialSearchURL = "df";
            var searchUrl = initialSearchURL + "&key=" + youtubeAPIKey;
            $.ajax({
                url: searchUrl,
                type: "GET",
                data: 'q=' + encodeURIComponent(query),
                success: function (result) {
                    if (result.items.length) {
                        var videoId = result.items[0].id.videoId;
                        var song = new Song({
                            title: result.items[0].snippet.title,
                            query: query,
                            videoId: videoId
                        });
                    } else var videoId = null; // Cannot find the song on YouTube

                    if (videoId) {
                        playlist.get('songs').add(song);
                        song.save(); // save to localStorage
                    }
                }, error: function (xhr, status, errorThrown) {
                    var errorMessage = "lookUpAndAddSingleSong error: check http://instantmusicapp.com";
                    var popupWindow = chrome.extension.getViews({ type: "popup" })[0];
                    if (popupWindow && popupWindow.popupView) popupWindow.showErrorMessage(errorMessage);
                    return;
                }
            });
        },

        setMusicChart: function (chartName) {
            // if the chart is provided, we pick from Melon, Billboard, iTunes
            if (chartName) {
                if (chartName == chrome.i18n.getMessage("melonChart"))
                    this.set('musicChart', AVAILABLE_CHARTS.melonChart);
                else if (chartName == chrome.i18n.getMessage("billboardChart"))
                    this.set('musicChart', AVAILABLE_CHARTS.billboardChart);
                else
                    this.set('musicChart', AVAILABLE_CHARTS.itunesChart);
                // else, the user is looking for a personal favorite chart
            } else {
                this.set('musicChart', AVAILABLE_CHARTS.myChart);
            }
        }
    });

    return Playlist;
});