Асинхронная функция в Node.js - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть конечная точка в моем API Node.js, которая возвращает массив результатов JSON, предоставленный библиотекой Google-Search-Scrapper.

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 (результаты) иres.json ({результаты}) должен произойти после выполнения функции scraper.search.В настоящее время он всегда возвращает пустой массив.

Функция, переданная функции scraper.search (), вызывается для каждого результата.Поэтому, если есть 10 результатов, функция запускается 10 раз, поэтому я жду, пока массив не заполнится, чтобы отправить ответ.

Я пытался использовать семафоры и мьютексные блокировки в разных местах, но безуспешно.Любой совет приветствуется.


Эта проблема была решена с помощью переменной LIMIT для проверки моего массива результатов.Изложенное в ответе помечено правильно ниже.

Спасибо всем за вклад.


Ответы [ 3 ]

0 голосов
/ 10 февраля 2019

Ответ Тротта был на правильном пути, но как насчет наличия переменной, которую вы увеличиваете каждый раз, а затем, когда она равна 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
            });
        }
    })
})
0 голосов
/ 10 февраля 2019

Помещение res.send за пределы обратного вызова приведет к состоянию гонки, аналогичному этой проблеме .Недостатком библиотеки 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не вызывать обратный вызов при некоторых условиях.

0 голосов
/ 10 февраля 2019

Мне нужно, чтобы console.log (результаты) и res.json ({результаты}) появлялись после выполнения функции 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(), заключается в том, что этообработка асинхронной функции, использующей обратный вызов, как если бы она была синхронной.

...