0

can u help me with a tip :D. Here is my code:

const request = require('request');
const cheerio = require('cheerio');

function getUrls(url) {
    const baseUrl = 'https://unsplash.com';
    let urls = [];
    request(url, (err, res, body) => {
        if (!err && res.statusCode === 200) {
            const $ = cheerio.load(body, { normalizeWhitespace: false, xmlMode: false, decodeEntities: true });
            $('.photo.qa-photo a').each((i, e) => {
                const lnk = $(e).attr('href');
                if (lnk.indexOf('@') === -1 && lnk.indexOf('download') === -1) {
                    urls.push(baseUrl + lnk);
                }
            });
        }
    });
    return urls;
}

function getImages(arr) {
    let images = [];
    for (const url of arr) {
        request(url, (err, res, body) => {
            if (!err && res.statusCode === 200) {
                const $ = cheerio.load(body, { normalizeWhitespace: false, xmlMode: false, decodeEntities: true });
                $('script').each((i, e) => {
                    if (i === 4) {
                        let img = $(e).text();
                        img = img.substring(img.indexOf('full') + 7, img.indexOf('regular') - 3);
                        images.push(img);
                    }
                });
            } else {
                console.log(err, res.statusCode);
            }
        });
    }
    return images;
}

console.log(getImages(getUrls('https://unsplash.com/search?utf8=%E2%9C%93&keyword=life&button=')));

Separately functions are working well, but if i want to combine both functions console.log show me an empty array first then functions finish work but i cant see the returned array, why? sorry for my english. With this little programm i want to get full urls of 20 images from unsplash.com Ty in advance.

Alexander Barac
  • 125
  • 1
  • 1
  • 5
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Ben Fortune Jun 16 '16 at 11:51

2 Answers2

0

Javascript is an asynchronoous language. What happens here is that your getImages function does not wait for your getUrls function to be finished.

You need to use a callback or a promise in your getImages function so it'll wait for getUrls.

Here's a little tutorials on callbacks

Callbacks are a really important concept in Javascript and I strongly suggest you learn how it works. It'll make your life easier. Same goes for promises.

Here's an example with your code

const request = require('request');
const cheerio = require('cheerio');

// callback is the function to be called when this one finishes
function getUrls(url, callback) {
    const baseUrl = 'https://unsplash.com';
    let urls = [];
    request(url, (err, res, body) => {
        if (!err && res.statusCode === 200) {
            const $ = cheerio.load(body, { normalizeWhitespace: false, xmlMode: false, decodeEntities: true });
            $('.photo.qa-photo a').each((i, e) => {
                const lnk = $(e).attr('href');
                if (lnk.indexOf('@') === -1 && lnk.indexOf('download') === -1) {
                    urls.push(baseUrl + lnk);
                }
            });
        }
    });
    //Notice the call to callback.
    callback(urls);
}
function getImages(arr) {
    let images = [];
    for (const url of arr) {
        request(url, (err, res, body) => {
            if (!err && res.statusCode === 200) {
                const $ = cheerio.load(body, { normalizeWhitespace: false, xmlMode: false, decodeEntities: true });
                $('script').each((i, e) => {
                    if (i === 4) {
                        let img = $(e).text();
                        img = img.substring(img.indexOf('full') + 7, img.indexOf('regular') - 3);
                        images.push(img);
                    }
                });
            } else {
                console.log(err, res.statusCode);
            }
        });
    }
    return images;
}

console.log(getUrls('https://unsplash.com/search?utf8=%E2%9C%93&keyword=life&button=', function(urls){getImages(urls)}));

I haven't tested it but it should work or be close enough.

0

Bacause request function invokes asynchrounously, so parent function (getUrls, getImages) returning before array filled. You have to use callbacks.

Constantine
  • 482
  • 3
  • 10