【问题标题】:Node JS promise - run function multiple times with parameter from former runNode JS promise - 使用以前运行的参数多次运行函数
【发布时间】:2018-09-19 18:29:07
【问题描述】:

在我的former post 中,通过查看该社区提供的一些示例,我能够解决我的 Promise 问题。我希望这个问题也很容易解决,尽管我无法理解它。我有生以来第一次体验到流利的 PHP 语言是一种负担。

我的代码如下所示:

let getProducts = function(){
  countProducts
    .then(function(number){
      var name = '';
      let list = [];
      getProductNames(name)
        .then(function(names){
          names.forEach(function(el){
            list.push(el);
          });
          name = list.pop();
          getProductNames(name)
            .then(function(names){
              names.forEach(function(el){
                list.push(el);
              });
              ... and some more code to put the names in a table

getProductNames 函数如下所示:

var getProductNames = 
function(name) {
  return new Promise(
        function(resolve, reject){
            xyz.api.checkProducts(name, 1000, function(err, names){
              if (err){
                reject(err);
              } else {
                resolve(names);
              } 
            });
        }
  );
}

这行得通,因为我知道我的产品少于 2000 个,每次检查返回 1000 个产品,所以我必须运行两次 getProductNames 函数。

我正在寻找一种将其变为循环的方法,以便它自动运行所需的运行次数。

api 调用的问题是它需要以产品名称开头。第一次运行没有名称,它返回第一个 1000。第二次运行我需要运行 1 的最后找到的产品名称,运行 3 我需要最后找到的产品名称 2,依此类推。

有不同的方法可以确定是否需要再次运行:

  • 将数组长度与生成的 countProducts 数量进行比较
  • 通过将生成的 countProducts 数除以 1000 (ceil()) 来确定正手击球次数
  • 将最后找到的名称与新的最后找到的名称进行比较

我只是不知道如何循环以及在哪里循环。我假设解决方案是通过添加一个辅助函数找到的,但是当我尝试时我陷入了不可用的值等等。

您不必解决我的问题,但如果有人可以提供所需结构的示例或描述此结构的一些互联网资源,我将不胜感激。我发现的示例不使用以前运行的值。

【问题讨论】:

  • 什么是countProducts?您能确定 API 调用之间的项目数不会改变吗?
  • 你不能把限制参数从checkProducts中去掉吗?
  • 尝试递归,而不是循环。或者使用async/await 语法。
  • 您需要从每个 function 为它return 一个值或承诺,包括then 回调函数
  • @Bergi 就像它所说的那样,它是产品的总数。它可能会改变,但我可以处理。我担心的是多次运行。限制不可更改,是对第三方系统的api调用。

标签: node.js promise


【解决方案1】:
let getProducts = function () {
    let list = [];
    const fn = function (name, number) {
        return getProductNames(name).then(function (names) {
            names.forEach(function (el) {
                list.push(el);
            });

            if(list.length >= number || names.length == 0) {
                return list;
            }

            return fn(list.pop(), number); // Add promise to your chain
        });
    }
    return countProducts.then(function (number) {
        return fn('', number);
    });
}

// Use
getProducts().then(function(items) {
    console.log(items.length);
}, function(err) {
    console.error(err);
});

【讨论】:

    【解决方案2】:

    我已将 cmets 放在需要更好地理解代码的地方。随便问什么。

    注意:此代码未经测试,可能无法正常工作。这只是为了向您展示如何实际操作。

    注意1:你可能还想看看async-await,它们和promise是一样的,但语法上更易读更清晰

    let getProducts = function() {
      // return your promise, you may want to getProducts.then()
      return countProducts() 
        .then(function(number) {
          return getProductNames(number);
        })
        .catch(function(err) { // always put a catch
           console.log('there was an error', err)
        })
    }
    
    
    // make your getProductsName take in number value
    // the name it takes is empty by default, we will provide name when we recursively call it
    let getProductNames = function(number, name = ''){
      // check if your number is less than -1000 here , why ? keep reading the code
      if (number < -1000) return [];
      const nameCount = 1000;
      let names = []
      return callAPI({name, nameCount})
        .then(function(namesFromCallAPI) {
           names = names.concat(namesFromCallAPI); // you can concat two arrays at once
           // I do not know why you are poping the names, since it will mutate the array
           // use any one as per requirement
           let newName = names.pop();
           // OR let newName = names[names.length-1]; which will not mutate the array
           // recursively call the function by decreasing it by your nameCount
           // when your number is 500, it can still call but the result will be -500, which will run
           // in the next iteration -500-1000 will be -1500 which is < -1000 (explanation of base condition)
           return getProductNames(number - nameCount, newName)
        })
        .then(function(res) {
          // the result from getProductNames is again concatinated to our names and returned
          return names.concat(res);
        })
        .catch(function(err) {
           // always put a catch in your chain
           console.log('There was an error in our recursive function', err);
        })
    }
    
    
    // make a separate function that would api call
    // put any parameters that you may need to make customizable here
    let callAPI = function(params) {
      return new Promise(function(resolve,reject) {
        xyz.api.checkProducts(params.name, params.nameCount, function(err, names){
          if (err){
            reject(err);
          } else {
            resolve(names);
          } 
        });
      })
    }
    

    【讨论】:

    • 我必须 pop() 这个名字,因为它会在下次运行结果中使用。否则,该产品名称将显示两次。我不明确 .then(function(res) 的用途。
    • return getProductNames(number - nameCount, newName) 将返回新名称的名称;需要与我们的原始名称连接!否则我们只会从 api 调用中获取单个请求的名称。这是因为names 变量的范围。如果你在函数之外声明它,在 global scope 中,你不需要那个特定的行
    猜你喜欢
    • 2016-08-24
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多