首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Javascript -callback& promises -允许jsmediatags在执行函数之前收集专辑图片

Javascript -callback& promises -允许jsmediatags在执行函数之前收集专辑图片
EN

Stack Overflow用户
提问于 2018-06-04 04:50:28
回答 2查看 289关注 0票数 0

我一直在尝试一些我认为在Javascript中与回调和/或承诺相关的相对简单的东西(超过12个小时)。

注意:我正在对一个.js.erb文件使用Rails,但这与我的问题无关,因为我更关注的是Javascript;只是为了说明更大的问题。

我正在使用jsmediatags从远程主机上的mp3s读取元数据(主要集中在收集专辑艺术作品上)。我站点上的每个“文章”都与多个音频文件(@related_titles)相关,所以我循环遍历每个文件(本地变量url),收集图片,然后在coverflow插件中显示它们--这意味着对每个处理的mp3执行一次jsmediatags.read。问题是。在coverflow插件初始化之前,jsmediatags不会读完所有的图片。尽管我对js比较陌生,但它似乎是回调函数的完美用法。

现在,在执行makeitrain函数(在coverflow中)之前,我不得不引入一个8500ms的setTimeout函数。它可以工作,但并不是在所有设备上都可靠(当它们处于负载状态时),而且它不是一个优雅的解决方案。

让我们假设@related_titles中有3个mp3s。为了显示代码没有按正确的顺序执行(不是在等待回调?),我添加了控制台日志。

接收到的输出:

代码语言:javascript
复制
Gathered all art!  Now I will callback and render the Coverflow
Initing Coverflow since gatherArtwork completed/we have art!
Gathering album art for title...
Gathering album art for title...
Gathering album art for title...

预期输出:

代码语言:javascript
复制
Gathering album art for title...
Gathering album art for title...
Gathering album art for title...
Gathered all art!  Now I will callback and render the Coverflow
Initing Coverflow since gatherArtwork completed/we have art!

这是我尝试过的:

代码语言:javascript
复制
function gatherArtwork(_callback) {

  // Read each of the mp3s to gather artwork ('url' == local var for mp3)
  <% @related_titles.each do |url| %>
      jsmediatags.read("<%= url['mp3'] %>", {
          onSuccess: function(tag) {

              console.log('Gathering album art for title...');

              // Convert the image contents to a Base64 encoded str
              var tags = tag.tags;
              albumartwork = _arrayBufferToBase64(tags.picture["data"]);

              // Append to the coverflow list a `<ul><li> </li></ul>` for each mp3
              // The 'albumartwork' Base64 image str is also appended here
              $("#coverflow-item-list").append('<ul><li>...</li></li>');

          }
      });
  <% end %>

  console.log('Gathered all art!  Now I will callback and render the Coverflow');
  _callback();

}

// Gather artwork MUST complete fully before the `makeitrain` function runs (callback)
function renderCoverflow() {
    gatherArtwork(function() {
      console.log('Initing Coverflow since gatherArtwork completed/we have art!');
      makeitrain();
    });
}

// Execute 'renderCoverflow' which will gather art and then "makeitrain"!
renderCoverflow();
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-04 05:10:48

最好的办法就是对此做出承诺。我用来自https://github.com/aadsm/jsmediatags的promise包装器复制了基本的new jsmediatags。可能需要一些微调,但目的是为您提供基本的概念轮廓

我不是一个rails dev,所以我将把你的related_titles数组输出到一个javascript变量,方法是打印JSON,然后由javascript自动读取为数组。

代码语言:javascript
复制
<script>
  var urls = // echo json array
<script>

完成后,脚本的其余部分可以放在单独的文件中或直接放在页面中,无论您喜欢哪一个

代码语言:javascript
复制
// helper function to get tag info and return promise that resolves with the base64 result
function getTags(url) {      
  return new Promise((resolve, reject) => {
      new jsmediatags.Reader(url)
        .read({
          onSuccess: (tag) => {                
            resolve( _arrayBufferToBase64(tag.tags.picture["data"]));
          },
          onError: (error) => {                
            reject(error);
          }
        });
    });
}

// create array of getTags() promises
let promises = urls.map(url => getTags(url))

Promise.all(promises).then(results=>{
  // `results` is array of all the base64 values same order as the urls array
  // loop over the results and add what is needed to DOM

  // then call cover flow

}).catch(err=> console.log('One of the requests failed'))
票数 0
EN

Stack Overflow用户

发布于 2018-06-04 05:16:42

首先,你不应该(永远)像你一样在服务器上复制你的js代码,结果是:

代码语言:javascript
复制
function gatherArtwork() {
  // Read each of the mp3s to gather artwork ('url' == local var for mp3)
  <% @related_titles.each do |url| %>
      console.log("<%= url['mp3'] %>");
  <% end %>
}

是:

代码语言:javascript
复制
function gatherArtwork() {
  // Read each of the mp3s to gather artwork ('url' == local var for mp3)
      console.log("url1");
      console.log("url2");
      ....
      console.log("urln");
}

因此,这意味着您正在向用户发送大量不必要的代码(您的JS文件现在更大了)。相反,您可以执行以下操作:

代码语言:javascript
复制
/**
  * Load all arts from urls
  */
function gatherArtwork(urls) {
  // Read each of the mp3s to gather artwork ('url' == local var for mp3)
  for(url in urls) {
      console.log(url);
  }
}

使用这种方法的好处还在于,您现在可以将gatherArtwork函数声明为async并执行以下操作:

代码语言:javascript
复制
async function gatherArtwork(urls) {
  for(url in urls) {
     await new Promise(function(resolve, reject) {
     jsmediatags.read("<%= url['mp3'] %>", {
       onSuccess: function(tag) {
         console.log('Gathering album art for title...');
         // Convert the image contents to a Base64 encoded str
         var tags = tag.tags;
         albumartwork = _arrayBufferToBase64(tags.picture["data"]);

         // Append to the coverflow list a `<ul><li> </li></ul>` for each mp3
         // The 'albumartwork' Base64 image str is also appended here
         $("#coverflow-item-list").append('<ul><li>...</li></li>');
         resolve(tag);
       },
       onError: function(error) {
         reject(error);
       }
    });
  });
  }
}

然后这样叫它:

代码语言:javascript
复制
await gatherArtwork(urls)
console.log('Gathered all art!  Now I will callback and render the Coverflow');
makeitrain();

小心!触发上述代码的函数也应该是async。如果您想要避免这种情况,您应该使用Promise.all

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50670852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档