【问题标题】:Node.js call async function from within do while loopNode.js 从 do while 循环中调用异步函数
【发布时间】:2017-01-17 19:39:44
【问题描述】:

我想从 do while 循环中调用一个异步函数,并且仅当该函数没有返回值时才退出。 有没有一种方法来管理这个而不必在回调之外实际等待?

这是显然总是在第一个循环中退出的代码,因为函数还没有回调,当 while () 被评估时:

var i = 0;
do {
  var foundListing;
  if (i) {
    listing.slug = listing.slug + '-' + (i + 1);
  }
  listingService.getListingBySlug(listing, function(error, pFoundListing) {
    if (error) {
      return callback(util.errorParser(error));
    } else if (Object.keys(pFoundListing).length) {
      foundListing = pFoundListing;
      i++;
    }
  });
  //Do I have to wait here???
} while (foundListing && Object.keys(foundListing).length);

澄清: 这里的重点是生成一个独特的 slug。如果蛞蝓已经存在,我会附加一个数字并再次检查它是否存在。当我到达尚不存在的号码时,我就完成了。

更新: 我找到了一种使用递归的方法。我将工作的 sn-p 发布为answer。

【问题讨论】:

  • 变量'i'的声明在哪里..
  • 您正在尝试将异步调用放入同步结构中。基本上,代码在循环的每次迭代中不断地调用listingService.getListingBySlug,javascript 可以以最大速度执行该循环。你确定是你想做的吗?
  • @GiacomoCosimato 恰恰相反。由于foundListing 在开始时为空,while() 部分在第一个循环中始终评估为 false,因为它是在尚未执行的回调中设置的。不管怎样,这不是我想要的。如果在 listingService.getListingBySlug 中找到了列表,我只想再次进入循环。

标签: javascript node.js asynchronous async-await do-while


【解决方案1】:

我没有能力对其进行测试,但也许应该使用递归函数:

const listingService = {
  getListingBySlug(listing, callback) {
    setTimeout(() => {
      if (listing.slug === 'listing-5') {
        callback(
          false,
          {
            name: 'Listing 1',
            slug: 'listing-1',
          }
        );
      }
      else {
        callback(false, {});
      }
    }, 1000);
  },
};

function checkListingExists(slug) {
  return new Promise((resolve, reject) => {
		const listing = { slug };
    listingService.getListingBySlug(listing, (error, pFoundListing) => {
      if (error) {
        reject(error);
      } else if (Object.keys(pFoundListing).length) {
        resolve(pFoundListing);
      } else {
        resolve(false);
      }
    });
  });
}

function nextListing(prefix, index) {
  checkListingExists(prefix + '-' + index)
  .then((listing) => {
    if (listing === false) {
      nextListing(prefix, index + 1);
    } else {
      console.log(listing);
    }
  })
  .catch(() => {
    // deal with error response
  });
}

nextListing('listing', 0);

【讨论】:

  • 嘿!泰来回答!我只是在研究一种递归方式来解决这个问题。我也相信这是唯一的方法。我会测试和更新。
  • 考虑这种方法是循环服务器请求,直到找到“未使用的 slug”,但这远非最佳性能。我不知道你是否拥有 API,但如果你拥有,最好实现类似 getFirstAvailableListing(slug) 或类似的方法
  • 我确实拥有 API,但循环必须位于服务器上的某个位置,不是吗?我能想到的唯一其他方法是从数据库中获取所有带有slug = newSlug* 的列表,然后通过正则表达式确定哪个是第一个未使用的 slug
  • 没错。问题是,如果您有一千个列表,并且您必须按顺序检查每个列表,每次都等待服务器响应。如果是唯一的选择,那就去吧。
  • 考虑的是,这应该是一个边缘情况。允许用户创建列表。用户创建的列表标题变成了 slug。如果两个用户创建具有生成相同 slug 的标题的列表,则此逻辑将生效。我只检查蛞蝓是否存在,如果存在,我附加一个数字并检查蛞蝓是否存在,等等。即使有 10k 个列表+,这也不太可能执行多次。值得考虑的好点,仍然。
【解决方案2】:

在这种情况下你应该使用 Promise。你可以这样做。

    var DEFERRED = require('deferred');
    var deferred = new DEFERRED();
    var i =0;

    while(1) {      
      listingService.getListingBySlug(listing, function(error, pFoundListing) {
    if (error) {
      return callback(util.errorParser(error));
      deferred.reject();
      break;
    } else if (Object.keys(pFoundListing).length) {         
      i++;
      listing.slug = listing.slug + '-' + (i + 1); 
      if(pFoundListing) {deferred.resolve()}
      break;
    }
  });


  deferred.promise.then(function() {
    // You will have the listing.slug value here.
  });

顺便说一句,您不应该使用 Object.keys() 来确定对象是否为空。只需在 utils 文件中的某处创建自己的 isEmpty 方法并检查属性。如果您的 pFoundListing 非常大,则会出现严重的性能问题。对于小对象(数组),您不会注意到差异。

【讨论】:

  • 回答问题!但是,如果回调需要足够长的时间,那不是可能循环 1.000 次吗?
  • SyntaxError: Illegal break statement
【解决方案3】:

我按照 Giacomo Cosimato 的建议使用递归使其工作。

这是有效的 sn-p:

listingController.js

saveListing: function(listing, callback) {
  listingService.findOpenSlug(listing, listing.slug, 1, function(error, listing) {
    if (error) {
      return callback(util.errorParser(error));
    } else {
      listingService.saveListing(listing, function(error, savedListing) {
        //do some work
      });
    }
  });
}

listingService.js

var classMethods = {
  findOpenSlug: function(listing, baseSlug, i, callback) {
    listingRepository.getListingBySlug(listing.slug, function(error, foundListing) {
      if (error) {
        return callback(error);
      } else if (Object.keys(foundListing).length) {
        listing.slug = baseSlug + '-' + (i + 1)
        i++;
        classMethods.findOpenSlug(listing, baseSlug, i, callback);
      } else {
        callback(null, listing);
      }
    });
  },
  [...]
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 2022-01-26
    • 2021-03-08
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多