Node.js中的异步功能

时间:2019-02-10 16:59:44

标签: javascript node.js api asynchronous semaphore

我的Node.js API中有一个端点,该端点返回由Google-Search-Scrapper库提供的结果的JSON数组。

app.get('/google_image_search', (req, res) => {
    var options = {
        query: 'grenouille',
        age: 'y', // last 24 hours ([hdwmy]\d? as in google URL)
        limit: 10,
        params: {} // params will be copied as-is in the search URL query string
    };

    var results = [];
    scraper.search(options, function(err, url, meta) {
        sem.take(function() { 
            if(err) throw err;

            var result = {
                title: meta.title,
                meta: meta.meta,
                description: meta.desc
            }
            results.push(result);
            sem.leave();
        });
    })

    console.log(results);

    res.json({
        results
    });
})

我需要console.log(results)和res.json({results})在scraper.search函数完成之后发生。当前,它总是返回一个空数组。

为每个结果调用传递给scraper.search()函数的函数。因此,如果有10个结果该函数运行10次,这就是为什么我要等到数组已满以发送响应。

我尝试在不同的地方使用信号灯和互斥锁,但是没有运气。任何建议表示赞赏。


这可以通过使用LIMIT变量来检查我的结果数组来解决。在答案下面概述了标记为正确的内容。

感谢大家的投入。


3 个答案:

答案 0 :(得分:2)

Trott的答案是正确的,但是每次有一个变量递增时,然后等于10(或9,取决于实现方式)时,运行完成代码。您也可以只计算数组中的元素。

app.get('/google_image_search', (req, res) => {
    var options = {
        query: 'grenouille',
        age: 'y', // last 24 hours ([hdwmy]\d? as in google URL)
        limit: 10,
        params: {} // params will be copied as-is in the search URL query string
    };

    var results = [];
    scraper.search(options, function(err, url, meta) {
        sem.take(function() { 
            if(err) throw err;

            var result = {
                title: meta.title,
                meta: meta.meta,
                description: meta.desc
            }
            results.push(result);
            sem.leave();
        });
        if(results.length==10) {
            console.log(results);

            res.json({
                results
            });
        }
    })
})

答案 1 :(得分:1)

  

我需要console.log(results)和res.json({results})在scraper.search函数完成之后发生。

将其放在scraper.search()的最里面的回调中。

scraper.search(options, function(err, url, meta) {
        if(err) throw err;

        var result = {
            title: meta.title,
            meta: meta.meta,
            description: meta.desc
        };
        results.push(result);
        console.log(result);
        res.json({results});
});

每次运行回调时,它将调用console.log()res.json()。如果您只想在10个结果或其他结果之后执行此操作,请添加代码以检查条件,并仅在正确的时间运行console.log()和/或res.json()

您还可以查看类似async / await之类的东西,但是考虑到您已发布的代码,以上可能是最具增量性的解决方案。

现在拥有console.log()res.json()的位置的问题是,它将异步回调使用函数视为同步函数。

答案 2 :(得分:1)

res.send放在回调之外将导致竞争状况类似于this problemgoogle-search-scraper库的缺点是它并非旨在收集结果。

此问题应解决:

var LIMIT = 10;
var options = { limit: LIMIT, ... };

var results = [];
var errs = [];
var resultsCount = 0;

function resultsHandler() {
    if (errs.length) {
       // handle error
    } else
       res.json({ results });
}

scraper.search(options, function resultHandler(err, url, meta) {
    if (err)
        errs.push(err);
    else {
        var result = {
            title: meta.title,
            meta: meta.meta,
            description: meta.desc
        };

        results.push(result);
    });

    resultsCount++;

    if (resultsCount === LIMIT)
       resultsHandler();
});

如果search在某些情况下可能不调用回调,则此方法将无效。