Node.js 中的异步函数

Posted

技术标签:

【中文标题】Node.js 中的异步函数【英文标题】:Async Function in Node.js 【发布时间】:2019-07-04 06:03:11 【问题描述】:

我的 Node.js API 中有一个端点,它返回由 Google-Search-scraper 库提供的 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 变量来检查我的结果数组来解决的。在下面标记为正确的答案中概述。

感谢大家的意见。


【问题讨论】:

How do I return the response from an asynchronous call?的可能重复 不是重复但相关的问题,它没有解释如何解决这个特定库的问题。 【参考方案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() 的位置的问题在于,它将使用异步回调的函数视为同步的。

【讨论】:

好的,如果我错了,请纠正我,但是每个结果都会调用传递给搜索函数的那个​​函数。那么如果有 10 个结果,我们会发回 10 个响应吗?这就是为什么我试图等到数组已满? 啊!是的,在这种情况下,回调中的代码将需要检查结果的数量或您希望用来指示结果已完成的任何内容。我将编辑我的答案。【参考方案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
            );
        
    )
)

【讨论】:

正确。谢谢。【参考方案3】:

res.send 放在回调之外将导致类似于this problem 的竞争条件。 google-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 可能在某些情况下不调用回调,这将不起作用。

【讨论】:

以上是关于Node.js 中的异步函数的主要内容,如果未能解决你的问题,请参考以下文章

node.js 中的异步函数完成后如何运行函数?

node.js 中的 foreach 异步函数

Node.js 文件系统

Node.js 文件系统

在 Node.js 的异步函数中填充数组

node.js中的forEach是同步还是异步