【问题标题】:How to use Promises to send an array of request results?如何使用 Promises 发送请求结果数组?
【发布时间】:2018-03-05 15:09:07
【问题描述】:

我想设置一个快速服务器,它返回一个项目数组的查询结果。我在this question 中读到我可以使用Promise.each 来做这个...

我打算让我的代码做的是:

  • Web 抓取包含电影列表的页面并将标题作为数组返回。
  • 使用电影的标题为每个电影做一个 API 请求
  • 向客户端返回对每部电影的 API 响应结果的响应

这是我的代码:

var express = require('express');
var app = express();

var Xray = require('x-ray');
var x = Xray();

app.get('/', function (req,res){
    var username = 'medicengonzo';
    var pages = 3;

    x('https://letterboxd.com/'+username+'/watchlist/', 'li.poster-container', [{
            movie: 'img@alt'
            }])(function (err,results){
        console.log('Entered x-ray callback fn');
        results.forEach(function(result, index){
            console.log('Iteration');
            console.log(results.length);
            request('http://netflixroulette.net/api/api.php?title='+encodeURIComponent(result.movie),
                    function(err, response, body){
                        movies = [];
                        console.log(count);
                        obj = JSON.parse(body);
                        if(obj.errorcode != 404){
                            movies.push('Movie found: '+obj.show_title, 'ID: '+obj.show_id);
                        }
                        else{
                            movies.push('No movie found');
                        }
                            res.send(movies);
                    }
            );
        });
    })
    .paginate('.paginate-current+li a@href')
    .limit(pages);
});

app.listen(3000, function(){
    console.log('Listening on port 3000!');
});

【问题讨论】:

  • 你是说 Promise.all 吗?
  • 不清楚您的代码究竟打算做什么。现在,您在results.forEach() 循环中执行res.send(movies),因此您可以针对同一个请求多次执行此操作,这绝对是一个编码错误,并且实际上只有第一个请求会作为响应发送。那么,您应该发送什么结果作为响应?
  • @BorisCharpentier 我是新来的承诺,所以我不太明白Promise.all 是如何工作的......
  • @jfriend00 我正在尝试为我从网络报废中获得的每个结果请求一个 API。当所有 api 请求完成后,将结果发送到 express 服务器
  • 但是您在循环中重新初始化movies = [],这样您就不会累积电影。为什么?您的意思是在循环之前只初始化一次并在循环中累积结果吗?

标签: node.js api express promise bluebird


【解决方案1】:

所以...经过一番谷歌搜索和大量关于 Promises 和 Chaining Promises 的学习后,我得到了可以工作的代码:

var express = require('express');
var app = express();

var Xray = require('x-ray');
var x = Xray();

var Promise  = require('bluebird');
var request = require('request');

var debug = true;

app.get('/', function (req,res){

    if(debug) console.log('Page requested!');

    var username = 'medicengonzo';
    var pages = 3;

    var scrapeMovies = function(){
        if(debug) console.log('scrapeMovies()');
        return new Promise((resolve,reject) => {
            x('https://letterboxd.com/'+username+'/watchlist/', 'li.poster-container', [{
                    title: 'img@alt'
                    }])((err, results) => {
                    console.log('x()');
                if(err) reject(err);
                resolve(results);
            })
            .paginate('.paginate-current+li a@href')
            .limit(pages);

        });
    };

    scrapeMovies().then(
            movies => {
        if(debug) console.log('scrapeMovies() resolved');
        return new Promise.all(movies.map((movie, index) => {
            return new Promise((resolve, reject)=> {
                if(debug) console.log('Requesting: ', movie.title);
                request('http://netflixroulette.net/api/api.php?title='+encodeURIComponent(movie.title), (err, response, body) => {
                        if(debug) console.log('Flixroulette requested');
                        var flixMovie = JSON.parse(body);
                        if(flixMovie.errorcode != 404){
                            resolve('Movie found: '+flixMovie.show_title, 'ID: '+flixMovie.show_id);
                        }
                       else{
                            resolve('No movie found...');
                        }
                });
            });
        }));
    }).then((movies) => res.send(movies)).catch((err) => console.log(err));

});

app.listen(3000, function(){
    console.log('Listening on port 3000!');
});

首先,我定义了一个函数,它将抓取我需要的电影标题,并返回一个带有上述标题数组的承诺:scrapeMovies()。

之后,我将该承诺链接到另一个承诺,其中包含将为我提出请求的函数。而不是array.forEach,我使用array.map,这样它返回了一个promise数组,每个promise都使用来自请求的数据进行解析,最后我res.send()解析来自Promise.all()的数据,这是一个包含所有数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    相关资源
    最近更新 更多