【问题标题】:Am I using this Promise functionality properly我是否正确使用了这个 Promise 功能
【发布时间】:2018-07-16 04:39:39
【问题描述】:

我正在使用 node 来使用cheerio 从一个 url 中获取一些数据。

const request=require('request');
const cheerio=require('cheerio');
const Promise = require('promise');

函数getDataParms(parm1, parm2) 返回一个承诺对象。

getDataParms 被retrieveAllData(parm1, limit) 调用以获取一组变化的参数

最终输出来自于

var test2 = retrieveAllData('foo','2015');
console.log(test2);

node script.js 的输出

// [ Promise { _75: 0, _83: 0, _18: null, _38: null } ]

在某个地方我没有正确使用 Promise 方法,而且我不知道在哪里。我需要一些有经验的眼睛来帮助我找出我做错了什么。

代码:

const request=require('request');
const cheerio=require('cheerio');
const Promise = require('promise');

var dateVal = new Date();
var test2 = [];

function retrieveAllData(parm1, limit){
    var output = [];
    var intermediate;

    for (var j=1; j <= limit; j++){
        var objKey = parm1 + "_data";
        var results = {
            "data1": null,
            [objKey]: null
        };

        results.data1 = j;
        objKey = objKey + "_" + j;
        results[objKey] = getDataParms(parm1, j).then(function(value){
            //console.log(value);
            return value;
        });

        //console.log(results[objKey]);
        output.push(results[objKey]);
    }
    return output;
}

// Returns a Promise array
function getDataParms(parm1, parm2){
    var sourceURL = "http://website/source=" + material + "&parm1=" + parm1 + "&parm2=parm2";
    var parsedResults = [];
    var metadata = {
      record_parm2: time_period,
      record_no: null,
      record_date: null,
      col1: null,
      col2: null,
      col3: null
    };

    return new Promise(function(fulfill, reject){
            request(sourceURL, function(error,response,html){
              if (error){
                reject(error);
              } else if (!error && response.statusCode == 200){
                var $ = cheerio.load(html);
                $(".data tr").each(function(i, element){
                    metadata.record_no = i;
                        $(this).find("td").each(function(cellindex){
                          switch(cellindex){
                           case 0:
                                metadata.record_date = $(this).text();
                            break;
                           case 1:
                                metadata.col1 = parseFloat($(this).text());
                            break;
                           case 2:
                                metadata.col2 = parseFloat($(this).text());
                            break;
                           case 3:
                                metadata.col3 = parseFloat($(this).text());
                            break;
                          }
                      });   

                    parsedResults.push(metadata);
                });

                fulfill(parsedResults);
                }
        });
    });
}

var test2 = retrieveAllData('foo','2015');
console.log(test2);

【问题讨论】:

  • 不,我不是什么? 4.8.2

标签: javascript node.js promise es6-promise


【解决方案1】:

因为每个getDataParms 调用都会返回一个Promise,所以您应该等待所有此类Promise 首先用Promise.all 解决。此外,因为getDataParms 返回一个PromiseretrieveAllData,它消耗getDataParams,也应该返回一个Promise,以便最终的results 稍后可用。您应该在 retrieveAllData 调用中调用 .then,而不是 var test2 = retrieveAllData(...

function retrieveAllData(parm1, limit){
  // Create an array of Promises, with `j`'s values being 0 to `limit - 1`:
  const allPromises = Array.from(
    { length: limit },
    (_, j) => {
      // Make j start at 1 rather than 0:
      j++;
      const objKey = parm1 + "_data_" + j;
      // After getDataParms resolves, return an object with keys `data1` and `[objKey]`:
      return getDataParms(parm1, j)
        .then((parms) => ({
          data1: j,
          [objKey]: parms
        }));
    }
  );
  return Promise.all(allPromises);
}

并使用.then:

retrieveAllData('foo','2015')
  .then(test2 => {
    console.log(test2);
  });

使用for 循环而不是函数式看起来像这样:

function retrieveAllData(parm1, limit){
  const allPromises = [];
  for (let year = 1990; year <= limit; year++) {
    const objKey = parm1 + "_data_" + year;
    allPromises.push(
      getDataParms(parm1, j)
      .then((parms) => ({
        data1: j,
        [objKey]: parms
      }))
    )
  }
  return Promise.all(allPromises);
}

【讨论】:

  • 谢谢,这是有道理的,但我还不了解函数的粗箭头形式。所以我正在以另一种方式做,我现在更好地理解了。 (_,j) 中 _ 的目的是什么?为什么 j 从 1 而不是 0 开始?
  • 我很困惑。then((parms) => ({ data1: j, [objKey]: parms }));另一种形式的函数表示法是 .then(function(parms){return {data1: j, [objKey]: Parms } ?
  • 在这种情况下,箭头函数的工作方式与普通函数完全相同(除了它们更简洁)。 Array.from回调的第二个参数是map函数,第一个值是被迭代元素的值(undefined),第二个值是index i> 被迭代的元素(这是有意义的,保持值 0 到 limit - 1。所以,第一个参数称为 _ 以表明它不会被使用。我做了j++ 所以模仿你在做什么——你也从for (var j=1; j &lt;= limit;开始。
  • 但是,如果可能的话,从 0 开始而不增加 j 会更好。是的,一个箭头函数后跟一个值意味着该值是隐式返回的。 (不能单独使用花括号,因为那样会被解释为 block 而不是对象字面量)
  • 没有意识到我从 1 开始。它应该从 1900 开始。我希望能够输入年份范围;特定的开始年份和结束年份或特定的结束年份。我不太明白 Array.from() 内部发生了什么
【解决方案2】:

您需要在您的情况下使用Promise.all,以下示例可能会对您有所帮助

function retrieveAllData(parm1, limit) {
    var output = [];
    for (var j = 1; j <= limit; j++) {
        output.push(getDataParms(parm1, j));
    }
    return Promise.all(output);
}

var test2 = retrieveAllData('foo', '2015'); // this will return a promise
test2.then(function (result) {
    console.log(result);
})

【讨论】:

  • 他在寻找一个对象数组,比如[{ "data1": null, [objKey]: null }, ...],而不是一个值数组
  • 没有。您似乎跳过了我正在使用的代码的整个关键元素。
猜你喜欢
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
相关资源
最近更新 更多