如何在nodejs中结合同步和异步功能

Posted

技术标签:

【中文标题】如何在nodejs中结合同步和异步功能【英文标题】:how to combine sync and async function in nodejs 【发布时间】:2020-04-08 03:44:57 【问题描述】:

我在 NodeJS 上的同步和异步函数有问题,这是我的问题,

我有 4 个函数、一个全局变量(用户)和一个渲染函数来生成 html 页面。

scraper1和scraper2函数可以异步执行,它们抓取一个网站并填写全局用户变量,data_selector1不能完成,除非scraper1用scraper2函数对data_selector2做了同样的事情。

1-我需要scraper1 和scraper2 异步工作并填充可用用户,并且仅在2 个scraper 完成工作后才呈现HTML 页面。

2-我需要在钻孔过程中在浏览器中显示动画,我该怎么做

这是我尝试过的..

var express = require('express');
var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var router = express.Router();

 /*  globale variable to populate */

    var users =  
                'name':null,
                'age':null,
               

            ;

//function of scraping link1

function scarper1(callback)
    console.log("-------------scraper---------");
    var url = 'link1';

request(
  
    method: 'GET',
    url: 'http://api.myscarperwebservice.com/?url=' + url,
    headers: 
      Accept: 'application/json',
    ,
  ,
  function(error, response, body) 
    if (error) throw error;
    // call the data-selector1 after scraper are finish rendering
    data_selector1(body);
    
    


  
);




//function of scraping link2
function scarper2(callback)
  console.log("-------------scraper2---------");
  var url = 'link2';

request(
  
    method: 'GET',
    url: 'http://api.myscarperwebservice.com/?url=' + url,
    headers: 
      Accept: 'application/json',
    ,
  ,
   function(error, response, body) 
    if (error) throw error;
    // call the data-selector2 after scraper are finish rendering
    data_selector2(body);
    
    


  
);





function data_selector1(body)

console.log("-------------data-selector---------");
  const $ = cheerio.load(body);
  $("div[class='.user']").each(function(i,elem)
    

            users['name'] =$(elem).find('span[class=".name]').text();
          
            users['age'] =$(elem).find('span[class=".age]').text();
            
            
  );



function data_selector2(body)

console.log("-------------data-selector2---------");
  const $ = cheerio.load(body);
  $("ul[class='.user']").each(function(i,elem)
    

        users['name'] =$(elem).find('li[class=".name]').text();
          
        users['age'] =$(elem).find('li[class=".age]').text();
      
        
  );






/* GET home page. */

router.post('/recherche', function(req, res, next) 
   // i dont know how to make it here to say that scraper1 and scraper2 can be executed async and to render page after that the two scraper are finished 
   // and while scraper are working to display animation in the client
    scarper1(function(results)
        console.log(results);res.render('rechercher',  title: 'Express' );
        
    );
    
    
  
);

【问题讨论】:

LOL Scarper 是逃跑的意思。你的意思是刮刀。 【参考方案1】:

您可以使用promise.all() 来执行此操作,但在使用它之前,您需要承诺您的功能:

function scarper1(callback) 
    return new Promise((resolve, reject) => 
        console.log("-------------scraper---------");
        var url = 'link1';

        request(
            
                method: 'GET',
                url: 'http://api.myscarperwebservice.com/?url=' + url,
                headers: 
                    Accept: 'application/json',
                ,
            ,
            function (error, response, body) 
                if (error) reject(error);
                // call the data-selector1 after scraper are finish rendering
                data_selector1(body);
                resolve('Done successfully');
            
        );
    );


function scarper2(callback) 
    return new Promise((resolve, reject) => 
        console.log("-------------scraper2---------");
        var url = 'link2';
        request(
            
                method: 'GET',
                url: 'http://api.myscarperwebservice.com/?url=' + url,
                headers: 
                    Accept: 'application/json',
                ,
            ,
            function (error, response, body) 
                if (error) reject(error);
                // call the data-selector2 after scraper are finish rendering
                data_selector2(body);
                resolve('Done successfully');
            
        );
    );


let scarper1 = scarper1(function(results)
    console.log(results);res.render('rechercher',  title: 'Express' );

);
let scarper2 = scarper2(function(results)
    console.log(results);res.render('rechercher',  title: 'Express' );

);

Promise.all([scarper1, scarper2]).then(function(values) 
    console.log(values);
);

有关promise.all 的更多信息,请查看此文档。

更好的方法是使用async.eachLimit() 循环请求(异步),但首先您需要安装async 包,然后合并两个scraper 函数:

const async = require("async");
let urls = [
    'link1',
    'link2'
]
async.eachLimit(urls, 2, (url) => 
    console.log("-------------scraper---------");
    request(
        
            method: 'GET',
            url: 'http://api.myscarperwebservice.com/?url=' + url,
            headers: 
                Accept: 'application/json',
            ,
        ,
        function (error, response, body) 
            if (error) reject(error);
            // call the data-selector1 after scraper are finish rendering
            if(url == 'link1')
                data_selector1(body);
            else
                data_selector2(body);

            resolve('Done successfully');
        
    );
, (err) => 
    console.log("Finished all urls")
);

【讨论】:

以上是关于如何在nodejs中结合同步和异步功能的主要内容,如果未能解决你的问题,请参考以下文章

nodejs异步到同步

nodejs异步数据库功能需要同步回答

Nodejs FileReads 同步到异步

nodejs异步转同步

如何在nodejs中获得同步readline,或使用异步“模拟”它?

结合同步和异步方法调用,并根据异步的结果,我们需要循环同步方法调用