2016-10-01 25 views
1

目前我正在试图从与承诺Spotify的API获取数据,昨天我得到了另外一个问题很大的帮助,就同一主题:“Loop the object returned from node promise and feed to the next .then”。从节点返回数据有望

我所做的是首先从我的播放列表中获取曲目,然后调用另一个获取艺术家的api。最后,我打电话给另一个获取艺术家图像的api。 现在我的问题是:我如何返回从我的承诺中获得的数据?

这是我函数获取播放列表网址:

function getPlaylists(access_token) { 

    var options = { 
     url: 'https://api.spotify.com/v1/me/playlists', 
     headers: { 'Authorization': 'Bearer ' + access_token }, 
     json: true 
    }; 

    return new Promise(function(resolve, reject) { 

     request.get(options, function(error, response, body) { 
     var playlists = body.items; 
     var playlistArray = []; 
     playlists.forEach(function(playlist) { 
      var name = playlist.name; 
      var url = playlist.tracks.href; 

      playlistArray.push(url); 
     }); 

     if(!error) { 
      resolve(playlistArray); 
     } else { 
      reject(error); 
     } 

    }); 

    }); 
} 

这一次得到的艺术家:

function getArtists(url,access_token) { 

    var params = { 
    url: url, 
    headers: { 'Authorization': 'Bearer ' + access_token }, 
    json: true 
    }; 

    return new Promise(function(resolve, reject) { 

    request.get(params, function(error, response, body) { 

     var tracks = body.items; 
     var artistArray = []; 
     tracks.forEach(function(artists) { 
      let allArtists = artists.track.artists; 
      allArtists.forEach(function(artist) { 
       artistArray.push(artist); 
      }); 
     }) 

     if(!error) { 
      resolve(artistArray); 
     } else { 
      reject(error); 
     } 

    }); 

    }) 

} 

而这一次得到的艺术家形象:

function getArtistImages(artistId) { 
    var options = { 
     url: 'https://api.spotify.com/v1/artists/' + artistId, 
     json: true 
    }; 

    return new Promise(function(resolve, reject) { 
     request.get(options, function(error, response, body) { 
      if(error != null) { 
       reject(error); 
      } else { 
       resolve(body); 
      } 
     }); 
    }) 

} 

编辑编辑 我的方式cal及L这些功能是这样的:

getPlaylists(access_token) 
     .then(playlists => Promise.all(playlists.map(playlist => 
     getArtists(playlist, access_token))) 
     .then(artists => { 

     artists.map(artist => { 
      artist.map(a => { 
      console.log(a); 
      let component = renderToString(
       <App> 
        <Table artists={a} /> 
       </App> 
      ); 

      res.send(
       component 
      ) 
      }) 


     }) 

     })); 

它只返回的第一个结果 - 很明显,因为它只能通过foreach循环到达循环一次后,才“res.send()”,让我怎么确保它在我渲染视图之前遍历所有艺术家?我相信我必须做另一个Promise.all(),但我不确定在哪里 - 有没有人有想法?

我很感激:)

+0

我仍然没有弄清楚问题的解决方案是什么,但我现在可以说的是,您不会在'artist.map()'函数内返回任何东西。另外,我没有看到'array.push(obj [key])'中的'key'是什么。 –

+0

哦,是的,我忘了从测试中删除变量键。我相信我必须做另一个Promise.all在某处让我的艺术家图像正确吗? –

+0

你能解释一下数据和它的结构吗?因为用你的代码告诉它很混乱。例如'getArtists'似乎会返回一个*(Promise of)*艺术家阵列阵列,而'getArtistImages'会返回一个'img'?持有包含实际图像的*(可选)*图像数组 – Thomas

回答

0

如果我正确理解你的问题,这听起来像你是如何实际使用的Promises结果绊倒了。

异步应用:

Promises封装的异步结果,这是通过传递给then()回调提供。

这个异步ism将在整个应用程序中级联。

有多种方式的应用管理异步结果的现实:事件,回调,观测,承诺...

例子(使用事件):

这是原油和来自异步请求的数据如何被注入您的视图的未经测试的示例。当我的异步请求调用我的then()回调函数时,我更新了触发事件的模型,以重新呈现我的视图。如果我不想重新渲染我的整个视图,怎么办?如果我的getArtists()比我的视图返回的时间快,我的视图可以呈现它的加载状态?)。但为了简单起见,我们不会去那里。

+function(){ 


    var _view = $('#viewport'); 
    var _model = {...} 
    var _spotifyClient = new SpotifyClient(); // this contains method similar to those you included in your question 

    _view.on('load', onLoad); 
    _view.on('model:update', onModelUpdate); 

    function onLoad() { 
     _spotifyClient 
     .getArtists() 
     .then(function(result) { 
      // when the getArtists() request has responded, I can update my model. 
      updateModel({ isLoading: false, artists: result }); 
     })   

     // this will happen immediately after starting the "getArtists()" request. 
     udpateModel({ isLoading: true }); 
    } 

    function updateModel(mod) { 
     for(var p in mod) { 
      _model[p] = mod[p]; 
     } 
     _view.trigger('model:update', _model); 
    }   

    function onModelUpdate(model) { 
     refreshView(); 
    } 

    function refreshView() { 
     var viewModel = buildTemplateModel(_model); 
     renderTemplate(_view, viewModel); 
    } 

}(); 

我鼓励你研究一些视图框架,如角度,挖空或反应。我也鼓励你研究Reactive Extensions,它提供了一个可观察的接口和许多关于异步流的实用工具。对副作用

注:

有一个承诺,触发事件可以被归类为一种“副作用”的结果。在我们的应用程序中,您应该将副作用降到最低,并且它们只属于应用程序的控制器/主要部分。

如果您在您的应用程序中使用promise,那么对promise进行操作的可重用的库类和函数应返回promise。

+0

是的,我还没有真正地将我的头包裹在诺言中,我想:)请检查新的编辑,我想我差不多有 –

0

你需要调用res.send所有结果的阵列上,而不是在每一个单独:

getPlaylists(access_token).then(playlists => 
    Promise.all(playlists.map(playlist => 
     getArtists(playlist, access_token) 
    )) 
).then(artists => { 
    res.send(artists.map(artist => 
     artist.map(a => { 
      console.log(a); 
      return renderToString(
       <App> 
        <Table artists={a} /> 
       </App> 
      ); 
     }) 
    )) 
}); 

而且你的括号里略misnested(不匹配then调用的缺口),但没不会导致问题。

+0

嗨,嗯,它返回一个html数组 - 非常奇怪。 –

+0

恩,是不是你想要的? – Bergi

+0

我想要的就是关于返回所有结果的数组。但是,这会返回整个页面的数组:如下所示:“

0

它的旧帖子,但我认为它可以帮助某人。

我写了一个插件来执行基于承诺支持并发的foreach。我发现你不需要并发性,这使得事情变得更简单,适用于其他解决方案。

我用你的代码使用我的插件编写了一个代码。有用!

'use strict'; 

var request = require('request') 
var promiseForeach = require('promise-foreach') 

function getPlaylists(access_token) { 

    var options = { 
     url: 'https://api.spotify.com/v1/me/playlists', 
     headers: { 'Authorization': 'Bearer ' + access_token }, 
     json: true 
    }; 

    return new Promise(function (resolve, reject) { 

     request.get(options, function (error, response, body) { 
      var playlists = body.items; 
      var playlistArray = []; 
      playlists.forEach(function (playlist) { 
       var name = playlist.name; 
       var url = playlist.tracks.href; 
       playlistArray.push(url); 
      }); 
      if (!error) { 
       resolve(playlistArray); 
      } else { 
       reject(error); 
      } 
     }); 

    }); 
} 

function getArtists(url, access_token) { 

    var params = { 
     url: url, 
     headers: { 'Authorization': 'Bearer ' + access_token }, 
     json: true 
    }; 

    return new Promise(function (resolve, reject) { 

     request.get(params, function (error, response, body) { 

      var tracks = body.items; 
      var artistArray = []; 
      tracks.forEach(function (artists) { 
       let allArtists = artists.track.artists; 
       allArtists.forEach(function (artist) { 
        artistArray.push(artist); 
       }); 
      }) 

      if (!error) { 

       promiseForeach.each(artistArray, 
        [function (artist) { 
         return getArtistImages(artist.id) 
        }], 
        function (arrayOfResultOfTask, currentList) { 
         return { 
          artistId: currentList.id, 
          artistName: currentList.name, 
          artistImages: arrayOfResultOfTask[0].images 
         } 
        }, 
        function (err, newList) { 
         if (err) { 
          console.error(err) 
          return; 
         } 
         resolve(newList) 
        }) 

      } else { 
       reject(error); 
      } 

     }); 

    }) 

} 

function getArtistImages(artistId) { 
    var options = { 
     url: 'https://api.spotify.com/v1/artists/' + artistId, 
     headers: { 'Authorization': 'Bearer ' + access_token }, 
     json: true 
    }; 

    return new Promise(function (resolve, reject) { 
     request.get(options, function (error, response, body) { 
      if (error != null) { 
       reject(error); 
      } else { 
       resolve(body); 
      } 
     }); 
    }) 

} 

var access_token = 'YOUR-TOKEN'; 


getPlaylists(access_token) 
    .then(playlists => { 

     promiseForeach.each(playlists, 
      [function (playlist) { 
       return getArtists(playlist, access_token) 
      }], 
      function (arrayOfResultOfTask, currentList) { 
       return { 
        playlistURL: currentList, 
        artist: arrayOfResultOfTask[0] 
       } 
       //return renderToString(
       // <App> 
       //  <Table artists={render} /> 
       // </App> 
       //); 
      }, 
      function (err, newList) { 
       if (err) { 
        console.error(err) 
        return; 
       } 
       res.send(newList) 
      }) 

    }); 

插件:https://www.npmjs.com/package/promise-foreach

我希望它可以帮助别人!