【问题标题】:addEventListener() gets called only on the last loop cycleaddEventListener() 仅在最后一个循环周期被调用
【发布时间】:2018-11-27 04:09:44
【问题描述】:

我已经尝试解决这个问题好几个小时了,但没有成功。 查看了在 stackoverflow 上提出的所有类似问题,但这些解决方案似乎都不适合我。

我正在循环播放一系列视频。我需要将每个视频插入到音频元素中,以快速获取其持续时间以及它出现在播放列表中的确切时间。

我原来是这样的:

// Set time in playlist for each video
for (let index=0; index<this.playlist.length; index++) {
  var audio = document.getElementById('audio');
  console.log('INDEX: ' + index);
  self.playlist[index].timeInPlaylist = [];
  self.playlist[index].duration = 0;
  audio.setAttribute('src', self.playlist[index].bucketRef);
  audio.addEventListener('canplaythrough', function(e){
     videoDuration = Math.round(e.currentTarget.duration);
     console.log("Duration of video number " + index + ": " + 
     videoDuration + " seconds");
     self.playlist[index].duration = videoDuration;
     self.playlist[index].timeInPlaylist[0] = playlistLength;
     playlistLength = playlistLength + videoDuration;
     self.playlist[index].timeInPlaylist[1] = playlistLength;
  });
};

运行此代码保持索引不变,输出是数组中最后一个视频的长度,记录了 3 次。然后在深入研究之后,我意识到我需要某种类型的闭包,因为在循环中添加了事件侦听器。所以我做了一点重构,来到了这个当前版本:

function log(e, index) {
  videoDuration = Math.round(e.currentTarget.duration);
  console.log("Duration of video number " + index + ": " + videoDuration + " seconds");
  self.playlist[index].duration = videoDuration;
  self.playlist[index].timeInPlaylist[0] = playlistLength;
  playlistLength = playlistLength + videoDuration;
  self.playlist[index].timeInPlaylist[1] = playlistLength;
}

// Set time in playlist for each video
for (let index=0; index<this.playlist.length; index++) {
  var audio = document.getElementById('audio');
  console.log('INDEX: ' + index);
  self.playlist[index].timeInPlaylist = [];
  self.playlist[index].duration = 0;
  audio.setAttribute('src', self.playlist[index].bucketRef);
  debugger;
  (function() {
      var i = index;
      audio.addEventListener("canplaythrough", function(e) { log(e, i); });
  })();
};

这解决了我的索引问题;但是,我仍然只能获取数组中最后一个视频的持续时间。

console output

非常感谢您的反馈。这个问题一直在杀死我。

【问题讨论】:

    标签: javascript arrays loops closures addeventlistener


    【解决方案1】:

    您正在循环中同步重置同一音频元素的源属性,并向一个音频元素添加额外的事件侦听器。

    在循环终止并且音频元素为它设置的最后一个src 属性加载音频后,所有事件侦听器都将调用one-and-the-same的详细信息最后一个播放列表项。

    您需要重新设计代码以异步运行并按顺序加载具有不同音频源的一个音频元素,或者为每个播放列表项创建一个新的 AUDIO 元素。或者将持续时间留空,直到用户选择要播放的项目(只是一个想法)。

    请注意,您不需要创建一个闭包来保存 index 的值 - 这是调试中的错误:letindex 的 for 循环声明中创建一个单独的对变量的词法引用 for每次循环迭代。在循环内的函数表达式中看到的index 的值是在计算表达式时迭代的值。

    【讨论】:

    • 谢谢!你所说的一切都很有道理,用新的眼光看待代码真的很有帮助。我可能会为每个数组项创建一个单独的音频元素实例。不幸的是,让用户选择视频的想法不适用于我正在构建的播放器的概念。我的应用程序仅向用户显示从片段中创建的单个视频。它使用单个搜索栏无缝播放/拼接来自任何给定视频阵列的视频;所以我需要在安装组件时知道每个视频的持续时间。
    【解决方案2】:

    您创建了一个闭包,但方式不正确。

    在你的代码代码中替换这部分

    (function() { var i = index; audio.addEventListener("canplaythrough", function(e) { log(e, i); }); })();

    audio.addEventListener("canplaythrough", (function(audioObj, index) {
        return function(){
          log(audioObj, index); 
        }
      })(this, index)
     );
    

    这样做应该可以让您直接访问 log 函数中的音频对象以获取其持续时间,而不是依赖于事件对象。

    【讨论】:

    • 感谢您的快速回答!但是,在插入此代码并将 e.currentTarget.duration 切换为 e.duration 后,这(NotANumber)是我在控制台中登录的“视频编号 0 的持续时间:NaN 秒,视频编号 1 的持续时间:NaN 秒,视频编号 2 的持续时间:NaN 秒”
    • 能否请您为您的代码创建一个 JsFiddle 以便我检查可能出现的问题?
    猜你喜欢
    • 2016-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 1970-01-01
    相关资源
    最近更新 更多