Node.js Call a method after another method is completed

限于喜欢 提交于 2019-12-25 03:28:19

问题


I would like to call my "app.get('/news/news-desc', (req, res)" method after "app.get('/news/api/:newsName', function(req, res)" is completed.

Here is my code:

let articleUrlArray = [];

app.get('/news/api/:newsName', function(req, res) {
  const API_KEY = 'example';

  let data = '';

  const techCrunchURL = `https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${API_KEY}`

  switch(req.params.newsName) {
    case 'tech-crunch':
      request(techCrunchURL, function(err, response, html) {
    
        let formattedData = JSON.parse(response.body);

        for(let i = 0; i < formattedData.articles.length; i++) {
          articleUrlArray.push(formattedData.articles[i].url);
        }

        data = response.body;
        res.setHeader('Content-Type', 'application/json');
        res.send(data);
      });

      break;

    default:
      data = 'Please type in correct news source';
      break;
  }
})

const checkBody = res => (err, response, html) => {
    const $ = cheerio.load(html);
    const articleContent = $('.article-content').children('p')
    const bodyOne = articleContent.eq(0).text()
    const bodyTwo = articleContent.eq(1).text()
    const isExtensive = bodyOne.split(' ').length > 50
    res(isExtensive ? { bodyOne } : { bodyOne, bodyTwo })
}

const getArticle = article => new Promise(res => request(article, checkBody(res)))

app.get('/news/news-desc', (req, res) => {
    Promise.all(articleUrlArray.map(getArticle)).then(data => res.send(JSON.stringify(data)))
})

As you can see, the first method calls the "newsapi.org" and gets 10 articles. Then it would only extract the urls of those articles and push them into articleUrlArray.

After the urls have been pushed into the articleUrlArray, it would look like this:

let articleUrlArray = [ 'https://techcrunch.com/2018/05/19/shared-housing-startups-are-taking-off/',
  'https://techcrunch.com/2018/05/19/shared-housing-startups-are-taking-off/',
  'https://techcrunch.com/2018/05/19/my-data-request-lists-guides-to-get-data-about-you/',
  'https://techcrunch.com/2018/05/19/siempos-new-app-will-break-your-smartphone-addiction/',
  'https://techcrunch.com/2018/05/19/la-belle-vie-wants-to-compete-with-amazon-prime-now-in-paris/',
  'https://techcrunch.com/2018/05/19/apple-started-paying-15-billion-european-tax-fine/',
  'https://techcrunch.com/2018/05/19/original-content-dear-white-people/',
  'https://techcrunch.com/2018/05/19/meet-the-judges-for-the-tc-startup-battlefield-europe-at-vivatech/',
  'https://techcrunch.com/2018/05/18/nasas-newest-planet-hunting-satellite-takes-a-stellar-first-test-image/',
  'https://techcrunch.com/video-article/turning-your-toys-into-robots-with-circuit-cubes/',
  'https://techcrunch.com/2018/05/18/does-googles-duplex-violate-two-party-consent-laws/' ];

It would just be filled up with urls.

Then the second method, would use the filled up articleUrlArray to do its own thing.

However, currently for my code, the second method runs first before the articleUrlArray has been filled up.

I would like to run the second method after the first method completes and the articleUrlArray has been filled up with urls.

Could you please help me with this?


回答1:


let articleUrlArray = [];
const addArticleUrl = url => articleUrlArray.push(url)

const checkBody = res => (err, response, html) => {
  const $ = cheerio.load(html);
  const articleContent = $('.article-content').children('p')
  const bodyOne = articleContent.eq(0).text()
  const bodyTwo = articleContent.eq(1).text()
  const isExtensive = bodyOne.split(' ').length > 50
  res(isExtensive ? { bodyOne } : { bodyOne, bodyTwo })
}

const getArticle = article => new Promise(res => request(article, checkBody(res)))

const newsDescMiddleware = app.get('/news/news-desc', (req, res) => {
  Promise.all(articleUrlArray.map(getArticle)).then(data => res.send(JSON.stringify(data)))
})

const techCrunch = res => url => request(url, (err, response, html) => {
  let formattedData = JSON.parse(response.body);
  formattedData.articles.forEach(article => addArticleUrl(article.url))
  res(response.body)
})

const getNewsByName = (newsName, url) => new Promise((res, reject) => ({
  'tech-crunch': techCrunch(res)(url)
}[newsName])) || reject()

const getNewsByNameMiddleware = (req, res) => {
  const API_KEY = 'example';
  const techCrunchURL = `https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${API_KEY}`

  getNewsByName(req.params.newsName, url)
    .then(body => {
      res.setHeader('Content-Type', 'application/json');
      res.send(body)
    })
    .catch(() => res.send('Please type in correct news source'))
}

app.get('/news/api/:newsName', getNewsByNameMiddleware, newsDescMiddleware)

Here, I made you some middlewares.

I am assuming that you don't need the response of the previous middleware.

I like to split the code by its responsibilities and write it functionally.




回答2:


You can separate the core logic of the first route to a function and re-use it in both places, if you please. however you still need to provide newsName parameter to GET '/news/news-desc' endpoint.

Example for your code.

    let articleUrlArray = [];

    function getNewsNames(newsName, callback) {
        const API_KEY = 'example';
        let data = '';
        const techCrunchURL = `https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${API_KEY}`

        switch (newsName) {
            case 'tech-crunch':
                request(techCrunchURL, function (err, response, html) {

                    let formattedData = JSON.parse(response.body);

                    for (let i = 0; i < formattedData.articles.length; i++) {
                        articleUrlArray.push(formattedData.articles[i].url);
                    }

                    data = response.body;
                    callback(null, data);
                });

                break;

            default:
                data = 'Please type in correct news source';
                callback('Error', data);
                break;
        }
    }

    app.get('/news/api/:newsName', function (req, res) {

        getNewsNames(req,params.newsName, (err, data) => {
            if (!err) {
                res.setHeader('Content-Type', 'application/json');
            }

            return res.send(data);
        })
    })

    const checkBody = res => (err, response, html) => {
        const $ = cheerio.load(html);
        const articleContent = $('.article-content').children('p')
        const bodyOne = articleContent.eq(0).text()
        const bodyTwo = articleContent.eq(1).text()
        const isExtensive = bodyOne.split(' ').length > 50
        res(isExtensive ? { bodyOne } : { bodyOne, bodyTwo })
    }

    const getArticle = article => new Promise(res => request(article, checkBody(res)))

    app.get('/news/news-desc/:newsName', (req, res) => {
        getNewsNames(req.params.newsName, (err, data) => {
            // by now, the articleUrlArray array will be filled
            Promise.all(articleUrlArray.map(getArticle)).then(data => res.send(JSON.stringify(data)))
        })
    })


来源:https://stackoverflow.com/questions/50441359/node-js-call-a-method-after-another-method-is-completed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!