簡體   English   中英

從節點承諾返回數據

[英]Return data from node promises

我目前正在嘗試使用承諾從 Spotify API 獲取數據,昨天我在另一個問題上得到了巨大的幫助,關於同一主題:“ 循環從節點承諾返回的對象並提供給下一個 .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);
          }
      });
    })

}

EDIT EDIT我調用這些函數的方式是這樣的:

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
            )
          })


        })

      }));

它只返回第一個結果——顯然是因為它只能在“res.send()”之前循環一次 forEach 循環,那么在渲染視圖之前,我如何確保它循環遍歷所有藝術家? 我相信我必須再做一次 Promise.all(),但我不確定在哪里 - 有沒有人有想法?

我很感激 :)

它的舊帖子,但我認為它可以對某人有所幫助。

我寫了一個插件來基於支持並發的承諾來執行 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

我希望它可以幫助某人!

如果我正確理解您的問題,聽起來您似乎對如何實際使用Promises的結果感到Promises

異步應用:

Promises封裝了一個異步結果,該結果通過傳遞給then()的回調可用。

這種異步機制將在整個應用程序中級聯。

應用程序可以通過多種方式管理異步結果的現實:事件、回調、可觀察對象、承諾......

示例(使用事件):

這是一個粗略且未經測試的示例,說明如何將來自異步請求的數據注入您的視圖中。 當我的異步請求調用我的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);
    }

}(); 

我鼓勵您研究一些視圖框架,例如 angular、knockout 或 react。 我還鼓勵你研究 Reactive Extensions,它提供了一個可觀察的接口和許多關於異步流的實用程序。

副作用注意事項:

承諾的結果觸發事件可以歸類為“副作用”。 您應該在我們的應用程序中將副作用保持在最低限度,並且它們實際上只屬於您的應用程序的控制器/主要部分。

如果您在應用程序中使用了 Promise,則對 Promise 進行操作的可重用庫類和函數應該返回 Promise。

您需要對所有結果的數組調用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>
            );
        })
    ))
});

此外,您的括號有點錯誤(與then調用的縮進不匹配),但這並沒有導致問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM