Nodejs同步循环阻止执行

时间:2018-01-30 11:38:39

标签: javascript node.js

当我尝试在后台运行一个函数时,它会阻止所有其他请求,直到完成...

例如,如果我执行该函数然后尝试向从数据库返回一些信息的路由发出get请求,那么响应将在该函数执行完成后才会出现,我不明白为什么。

这是我在后台运行的函数的基本结构(它从页面中找到第三方请求,然后查找每个请求的发起者请求):

  const thirdPartyReq = [];
  let allRequests = [];

  const findInitiatorReq = async () => {
    allRequests = allRequests.reverse();
    for(const [_, request] of thirdPartyReq.entries()) {
      if(!request["Initiator Request"]) {
        const fullRequest = request['Request URL'];
        const parseUrl = new URL(fullRequest);
        let hostname = parseUrl.hostname || null;

        const domain = await extractDomain(hostname);
        let pathname = parseUrl.pathname || null;
        hostname = hostname.replace(/www./g, '')
        let checkUrl;

        const domainIndex = hostname.indexOf(domain) - 1;
        const subdomain = (hostname.substr(0, domainIndex));
        const queryString = parseUrl.search || '';
        const noProtocol = hostname + pathname + queryString;
        const noQueryString = hostname + pathname;
        const requestProcessing = [fullRequest, noProtocol, noQueryString, hostname];

        const requestIndex = allRequests.findIndex((el) => {
          return (el.url == request['Request URL'] && el.thirdParty);
        });

        for(const [_, query] of requestProcessing.entries()) {
          for(const [index, checkRequest] of allRequests.entries()) {
            if(index > requestIndex) {
              if(checkRequest.content && checkRequest.content.body) {
                const contentBody = checkRequest.content.body;
                if(contentBody.includes(query)) {
                  request['Initiator Request'] = checkRequest.url;
                }
              }
            }
          }
        }
      }
    }
  }

  for(const [pageIndex, page] of results.entries()) {
    const pageUrl = page.url;
    const requests = page.requests;
    const savedRequestUrls = [];
    let parseUrl = new URL(pageUrl);
    let hostname = parseUrl.hostname;
    let requestsCounter = 0;

    const pageDomain = await extractDomain(hostname);

    if(!urlList.includes(pageUrl)) {
      crawledUrls.push(pageUrl);
    }

    for(const [_, request] of Object.entries(requests)) {
      if(request.url.indexOf('data:') == -1) {
        parseUrl = new URL(request.url);
        hostname = parseUrl.hostname;
        let requestDomain = await extractDomain(hostname);

        const reqObj = await findThirdPartyReq(pageUrl, request, requestDomain);
        if(reqObj != null) {
          request.thirdParty = true;
          savedRequestUrls.push(reqObj);
        }

        // Store all requests that have a domain
        if(requestDomain) {
          request.page = pageUrl;
          allRequests.push(request);
          requestsCounter++;
        }
      }
    }

    findInitiatorReq();
  }

我注意到如果删除这部分代码,一切都会正常工作:

    for(const [_, query] of requestProcessing.entries()) {
      for(const [index, checkRequest] of allRequests.entries()) {
        if(index > requestIndex) {
          if(checkRequest.content && checkRequest.content.body) {
            const contentBody = checkRequest.content.body;
            if(contentBody.includes(query)) {
              request['Initiator Request'] = checkRequest.url;
            }
          }
        }
      }
    }

这是调用函数的路径:

router.get('/cookies',async (req, res) => {
   res.status(200).send(true);
   const cookies = await myFunc();
}

任何人都可以告诉我为什么该功能会阻止所有内容,直到它返回响应,我该如何解决?

2 个答案:

答案 0 :(得分:0)

嗯,显然你有一个synchronous循环,当然会阻止执行。它最终会阻止无论如何,因为它必须执行几次繁重的操作。发送了对客户端的响应,但您仍然继续处理某些内容,因此其他请求必须等待。

一个可能的解决方案可能是触发另一个node进程并处理其中的东西(类似于浏览器中的WebWorker

您可以尝试使用此库:async,其中有一个eachSeries方法,专门用于处理大块数据/数组。有关详细信息,请参阅文档

答案 1 :(得分:0)

这里显而易见的答案是将您的功能转换为异步功能。 StackOverflow上有关于该主题的多个答案。 要点:在详细说明一些繁重的任务时使用异步函数。请记住,NodeJS是单线程的,因此同步函数阻止执行其他函数这一事实在某种程度上是可以预期的。

您需要用来实现异步功能的工具有:async / await(在最新的NodeJS LTS中包含没有库/转换)和Promises。忘记回调,因为它们是一个非常糟糕的设计。

如何在js:

中使用async / await

如何使用Promise及其内容: