Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node JS:如何承诺循环_Javascript_Node.js_Express - Fatal编程技术网

Javascript Node JS:如何承诺循环

Javascript Node JS:如何承诺循环,javascript,node.js,express,Javascript,Node.js,Express,我正在尝试创建一个NodeJS应用程序。下面是管理员创建新产品时应该调用的代码。大多数代码都能正常工作,但只有在其余代码执行完DB函数异步后,我才有问题呈现视图。我已将大部分代码包装在承诺中,以确保某些块按正确的顺序执行,并通过控制台日志查明问题 我想指出的是,console.dirrejproductsj必须位于console.log111日志和空数组下面。另外,在for循环的结束括号之前添加console.dirrejProducts会记录一个空数组。谢谢如果你需要更多信息,请告诉我 app

我正在尝试创建一个NodeJS应用程序。下面是管理员创建新产品时应该调用的代码。大多数代码都能正常工作,但只有在其余代码执行完DB函数异步后,我才有问题呈现视图。我已将大部分代码包装在承诺中,以确保某些块按正确的顺序执行,并通过控制台日志查明问题

我想指出的是,console.dirrejproductsj必须位于console.log111日志和空数组下面。另外,在for循环的结束括号之前添加console.dirrejProducts会记录一个空数组。谢谢如果你需要更多信息,请告诉我

app.post('/products/new', function (req, res, next) {
  // Async function: find all categories
  Category.find(function(err, categories) {
    // Hidden count that tells num products to be created by form
    var numProducts = req.body[`form-item-count`];
    // Array of all rejected products adds
    var rejProducts = [];

    var promiseLoopProducts = new Promise(function(resolve, reject) {
      var promiseProducts = [];
      // Loop through all addded products
      for (let i = 0; i < numProducts; i++) {
        var promiseProductCheck = new Promise(function(resolve, reject) {
          var name = validate.sanitize(req.body[`name_${i}`]);
          var category = validate.sanitize(req.body[`category_${i}`]);
          var price = validate.sanitize(req.body[`price_${i}`].replace(/\$/g, ""));
          var stock = validate.sanitize(req.body[`stock_${i}`]);
          var image = validate.sanitize(req.body[`image_${i}`]);
          var description = validate.sanitize(req.body[`description_${i}`]);

          var rejProduct;
          var rejFields = { 'name': name, 'category': category, 'price': price,
                            'stock': stock, 'image': image,
                            'description': description };
          var rejErrors = {};

          var productData = {
            name: name,
            category: category,
            price: price,
            stock: stock,
            image: image,
            description: description
          };
          var promiseCategoryCheck = new Promise(function(resolve, reject) {
            if (ObjectId.isValid(category)) {
              var promiseCategoryCount = new Promise(function(resolve, reject) {
                Category.count({'_id': category}, function(error, count) {
                  rejErrors['name'] = validate.isEmpty(name);
                  if (count == 0) rejErrors['category'] = true;
                  rejErrors['price'] = !validate.isPrice(price);
                  rejErrors['stock'] = !validate.isInt(stock);

                  if( validate.isEmpty(name) || !validate.isPrice(price) ||
                      count == 0 || !validate.isInt(stock) ) {
                    rejProduct = { 'fields': rejFields, 'errors': rejErrors };
                    rejProducts.push(rejProduct);
                    console.dir(rejProducts);
                    console.log(count);
                    return resolve();
                  }
                  else {
                    Product.create(productData, function (error, product) {
                      if (error) return next(error);
                      console.log(77);
                        console.dir(rejProducts);
                      return resolve();
                    });
                  }
                  if (error) return next(error);
                });
              });
              promiseCategoryCount.then(function() {
                console.dir(rejProducts);
                return resolve();
              });
            } else {
              rejErrors['category'] = true;
              rejProduct = { 'fields': rejFields, 'errors': rejErrors };
              rejProducts.push(rejProduct);
              console.dir(rejProducts);
            }
          });
          promiseCategoryCheck.then(function() {
            console.dir(rejProducts);
            promiseProducts.push(promiseProductCheck);
            console.log(promiseProductCheck);
            console.log(promiseProducts);
            return resolve();
          });
        });
        promiseProductCheck.then(function() {
          console.log(106);
          console.dir(rejProducts);
        });
      }
      Promise.all(promiseProducts).then(function() {
        console.log(111);
        console.dir(rejProducts); // Empty array!
        return resolve();
      });
    });

    promiseLoopProducts.then(function() {
      console.log(118);
      console.dir(rejProducts); // Empty array!
      res.render('products/new', { categories: categories, rejProducts: rejProducts });
    });

  });

});

一些提示:如果你的函数超过100行,你可能在函数中做了很多事情

如果您必须以获取请求产品的方式从请求中获取数据,那么编写更好的客户端代码产品应该是一组不需要清理的产品对象。需要在服务器上进行验证,因为您永远不信任客户端发送给您的内容。但是,看一下“净化”,你甚至不相信客户端脚本发送给你的内容

试着写一些小函数来做一些小事情,并试着使用它们

使用.map将类型a映射到类型b,例如req.body映射到产品数组,如示例代码中所示

使用.map的结果作为Promise.all的参数

使用util.promisify将回调函数更改为返回承诺的函数,因为您使用的是旧版本的node,我添加了promisify的一个实现:

var promisify = function(fn) {
  return function(){
    var args = [].slice.apply(arguments);
    return new Promise(
      function(resolve,reject){
        fn.apply(
          null,
          args.concat([
            function(){
              var results = [].slice.apply(arguments);
              (results[0])//first argument of callback is error
                ? reject(results[0])//reject with error
                : resolve(results.slice(1,results.length)[0])//resolve with single result
            }
          ])
        )
      }
    );
  }
};

module.exports = function(app){
  const validate = require('../functions/validate');
  const Category = require('../db/categories');
  const Product = require('../db/products');
  var ObjectId = require('mongoose').Types.ObjectId;
  //Category.find as function that returns a promise
  const findCategories = promisify(Category.find.bind(Category));
  const countCategories = (categoryId) => {
    promisify(Category.count.bind(Category))({'_id': categoryId});
  };
  const createProduct = promisify(Product.create.bind(Product));
  const REJECTED = {};
  const bodyToProduct = (body, i) => {
    var name = validate.sanitize(body[`name_${i}`]);
    var category = validate.sanitize(body[`category_${i}`]);
    var price = validate.sanitize(body[`price_${i}`].replace(/\$/g, ""));
    var stock = validate.sanitize(body[`stock_${i}`]);
    var image = validate.sanitize(body[`image_${i}`]);
    var description = validate.sanitize(body[`description_${i}`]);
    return {
      name: name,
      category: category,
      price: price,
      stock: stock,
      image: image,
      description: description
    };
  };

  const setReject = product => {
    var rejErrors;
    var rejName = validate.isEmpty(product.name);
    var rejCategory;
    var rejPrice = !validate.isPrice(product.price);
    var rejStock = !validate.isInt(product.stock);
    const countPromise = (ObjectId.isValid(product.category))
      ? countCategories()
      : Promise.resolve(0);
    return countPromise
    .then(
      count => {
        if (count == 0) rejCategory = true;

        if (rejName || rejCategory || rejPrice || rejStock) {
          rejErrors = {
            type:REJECTED,
            name: rejName,
            category: rejCategory,
            price: rejPrice,
            stock: rejStock
          }
          return rejErrors;
        }
        return false;
      }
    );
  };

  const productWithReject = product =>
    Promise.all([
      product,
      setReject(product)
    ]);

  const saveProductIfNoRejected = ([product,reject]) =>
    (reject===false)
      ? Product.create(product)
        .catch(
          err=>({
            type:REJECTED,
            error:err
          })
        )
      : reject;

  app.post('/products/new', function (req, res, next) {
    // Async function: find all categories
    return findCategories()
    .then(
      categories => {
        // Hidden count that tells num products to be created by form
        var numProducts = req.body[`form-item-count`];
        // Array of all rejected products adds
        var rejProducts = [];
        return Promise.all(
          Array.from(new Array(numProducts), (v, i) => i)
            .map(//map [0...numProducts] to product object
              i => bodyToProduct(req.body, i)
            )
            .map(
              product=>
                productWithReject(product)
              .then(saveProductIfNoRejected)
            )
        ).then(
          results =>
            res.render(
              'products/new',
              { 
                categories: categories,
                rejProducts: results.filter(x=>(x&&x.type)===REJECTED)
              }
            )
        ).catch(
          error=>
            console.log("Promise all products failed.",error)
        );
      }
    ).catch(
      error=>
        console.log("Find categories failed.",error)
    )
  });
}

您正在异步地将承诺推送到列表中,例如,在内部代码执行之前,您的承诺不会填充到列表中。因此,Promise.allpromiseProducts会在列表中实际有任何内容之前到达列表。@AlekseyBilogur嗨!谢谢你的回复。我想一个更好的问题是:我如何执行Promise.allpromiseProducts.then函数{只有在所有for循环代码完成后才可以执行?您好!非常感谢您的响应!我想这已经基本解决了我的问题,只是我收到了一个未处理的PromisejectionWarning:未处理的承诺拒绝拒绝拒绝id:2:TypeError:在我运行代码时无法读取undefined的属性“Query”。@Wallie您能更新您的qu吗您正在使用的当前代码是否有问题?我现在可能没有时间,但稍后会查看。刚刚更新。新代码是底部的代码。嗯……我仍然收到相同的错误-实际代码可能没有问题。我需要所有必要的模块吗?@Wallie无法读取未定义的属性“Query”中没有查询e提供的代码。
var promisify = function(fn) {
  return function(){
    var args = [].slice.apply(arguments);
    return new Promise(
      function(resolve,reject){
        fn.apply(
          null,
          args.concat([
            function(){
              var results = [].slice.apply(arguments);
              (results[0])//first argument of callback is error
                ? reject(results[0])//reject with error
                : resolve(results.slice(1,results.length)[0])//resolve with single result
            }
          ])
        )
      }
    );
  }
};

module.exports = function(app){
  const validate = require('../functions/validate');
  const Category = require('../db/categories');
  const Product = require('../db/products');
  var ObjectId = require('mongoose').Types.ObjectId;
  //Category.find as function that returns a promise
  const findCategories = promisify(Category.find.bind(Category));
  const countCategories = (categoryId) => {
    promisify(Category.count.bind(Category))({'_id': categoryId});
  };
  const createProduct = promisify(Product.create.bind(Product));
  const REJECTED = {};
  const bodyToProduct = (body, i) => {
    var name = validate.sanitize(body[`name_${i}`]);
    var category = validate.sanitize(body[`category_${i}`]);
    var price = validate.sanitize(body[`price_${i}`].replace(/\$/g, ""));
    var stock = validate.sanitize(body[`stock_${i}`]);
    var image = validate.sanitize(body[`image_${i}`]);
    var description = validate.sanitize(body[`description_${i}`]);
    return {
      name: name,
      category: category,
      price: price,
      stock: stock,
      image: image,
      description: description
    };
  };

  const setReject = product => {
    var rejErrors;
    var rejName = validate.isEmpty(product.name);
    var rejCategory;
    var rejPrice = !validate.isPrice(product.price);
    var rejStock = !validate.isInt(product.stock);
    const countPromise = (ObjectId.isValid(product.category))
      ? countCategories()
      : Promise.resolve(0);
    return countPromise
    .then(
      count => {
        if (count == 0) rejCategory = true;

        if (rejName || rejCategory || rejPrice || rejStock) {
          rejErrors = {
            type:REJECTED,
            name: rejName,
            category: rejCategory,
            price: rejPrice,
            stock: rejStock
          }
          return rejErrors;
        }
        return false;
      }
    );
  };

  const productWithReject = product =>
    Promise.all([
      product,
      setReject(product)
    ]);

  const saveProductIfNoRejected = ([product,reject]) =>
    (reject===false)
      ? Product.create(product)
        .catch(
          err=>({
            type:REJECTED,
            error:err
          })
        )
      : reject;

  app.post('/products/new', function (req, res, next) {
    // Async function: find all categories
    return findCategories()
    .then(
      categories => {
        // Hidden count that tells num products to be created by form
        var numProducts = req.body[`form-item-count`];
        // Array of all rejected products adds
        var rejProducts = [];
        return Promise.all(
          Array.from(new Array(numProducts), (v, i) => i)
            .map(//map [0...numProducts] to product object
              i => bodyToProduct(req.body, i)
            )
            .map(
              product=>
                productWithReject(product)
              .then(saveProductIfNoRejected)
            )
        ).then(
          results =>
            res.render(
              'products/new',
              { 
                categories: categories,
                rejProducts: results.filter(x=>(x&&x.type)===REJECTED)
              }
            )
        ).catch(
          error=>
            console.log("Promise all products failed.",error)
        );
      }
    ).catch(
      error=>
        console.log("Find categories failed.",error)
    )
  });
}