rkdghgyun
42
2020-11-11 21:40:14
7
393

node.js에서 map 관련 질문입니다.


안녕하세요 javascript 관련 질문입니다!

다름이 아니라 프론트에서 노드 서버로 url 10개를 보내면 노드 서버에서 url 각각을 크롤링해서 원하는 태그 내용을 얻어서 다시 프론트로 보내주는겁니다.

제가 생각하기에는 node서버에서 받은 url 리스트를 map으로 하나씩 크롤링을 해서 데이터를 얻고 이전에 만들어 두었던 리스트(test)에 하나씩 저장을 해서 map이 끝나면 데이터가 저장 된 리스트(test)를 보내주려고 하는데 이게 잘 안 됩니다..ㅠㅠㅠ

각각의 url마다 크롤링은 제대로 되어 console.log(newData)와 console.log(test)를 map 안에서 찍어보면 잘 나오는데 map 밖에서 console.log(test)를 하면 빈 리스트가 출력됩니다.. 아무리 해도 해결이 되지 않아 이렇게 글 올립니다. 답변 부탁드립니다. 감사합니다!

해당 코드입니다.


router.post("/ingredients/url", (req, res) => {
  console.log("asd");
  const getHtml = async (url) => {
    try {
      return await Axios.get(url);
    } catch (error{
      console.error(error);
    }
  };
  let urlList = [];
  urlList = req.body;

  var test = [];
  let testIndex = 0;

  urlList.map((idx) =>{
      getHtml(idx.url).then((html) => {
        const newData = {
          title: null,
          image: null,
        };
        const $ = cheerio.load(html.data);
        const $metaList = $("meta");
        for (let index = 0; index < $metaList.length; index += 1{
          const element = cheerio($metaList[index]);

          // meta 태그의 content 속성 값 추출
          let content = element.attr("content");

          if (!content || !content.trim()) {
            continue;
          }
          content = content.trim();

          // meta 태그의  property 속성 값 추출
          let propertyAttr = element.attr("property");
          if (propertyAttr{
            propertyAttr = propertyAttr.toLocaleLowerCase();
          }

          // 추출할 property 에 따라 newsData에 할당
          switch (propertyAttr{
            case "og:title":
              newData.title = content;
              break;
            case "og:image":
              newData.image = content;
              break;
            default:
              break;
          }
        }
        test[testIndex= newData;
        testIndex = testIndex + 1;
        console.log(test)
        console.log(newData)
      })
    })
   
  console.log(test);
  res.status(200).json({ success: true, test });
});
0
  • 답변 7

  • Dierslair
    5k
    2020-11-11 21:45:52

    getHtml이 async이니깐요

  • rkdghgyun
    42
    2020-11-11 21:48:33

    답글을 어떻게 남기는지 몰라 이렇게 글 남겨요 ㅠㅠ

    John Suhr님 답변 감사합니다!

    그럼 혹시 어떻게 해야할까요?? 감이 안잡히네요..ㅠㅠ

  • 1005hoon
    785
    2020-11-11 22:03:10

    john suhr님 답변에 조금 추가드리자면 


    일단 getHTML이 async 함수이고, 해당 함수 안에서 await axios ...로 프로미스를 리턴하잖아요


    그럼 해당 프로미스를 사용하는 코드들은 일단 promise가 fulfill이 되기 전까지는 대기를 타고 있어요.


    map 함수 안에서 test에다가 gethtml을 사용해 나온 결과물을 다 집어넣으셨고, 

    map 함수 안에서 test를 console.log를 찍으셨잖아요.

    그러면 해당 console.log는 프로미스가 fulfill 될떄까지 기다렸다가 다 되면 출력을 해주고요


    map 함수 밖에 있는 친구는 promise가 fullfill 되지 않아도, 지금 해당 console.log 코드를 읽는 순간 실행을 시켜버려요. 


    그래서 밖에 있는애는 빈 array를 출력하는거구요. 



  • rkdghgyun
    42
    2020-11-11 22:12:09

    hoonnote님 답변 감사드립니다!

    이해가 잘 됐습니다 ㅎㅎ

    좀 더 공부해서 fulfill이 다 되면 프론트로 보내주는 코드를 짜야겠군요

    답변 너무 감사드립니다!!

  • 1005hoon
    785
    2020-11-11 22:12:13
    router.post("/someURL"(reqres) => {
      const getHTML = async (url) => {    // 얘는 fullfill된 프로미스값을 
        return await axios.get(url); 리턴해주는 함수에요
      };

      const urlList = [...req.body.url];

      const test = [];

      urlList.map((urlindex) => {  // 이 map은, urlList를 도는동안 
        const page = await getHTML(url);비동기적으로 동작하는게 아니고 
        const newData = { ...page } 해당 코드실행이 끝나면 바로 다음줄로
        /**  넘어갑니다
    *
         * 그러고 뭔가 많은 함수들을 실행하구요
         */

         test[index] = newData await에 걸린 데이터를 활용하기 때문에
    얘도 기다리고있죠

         console.log(test)   // 이 친구는 await이 끝나고 fulfill 된 프로미스값을 
      }); 받아오기전까지 실행되지 않아요


      console.log(test)  // 근대 이 친구는 map이 비동기처리를 하고있지 않기 때문에, 
    await getHTML이 다 끝나지 않았는데도 map만 다 
    돌아가면 바로 실행이 되고 있죠.

    });

  • 1005hoon
    785
    2020-11-11 22:15:01

    루프를 비동기로 사용하게 될때에는 

    for in이나 for of 사용하셔도 좋구요,


    map을 사용하신다면, promise들을 잔뜩 리턴하게 한 뒤 Promise.all() 로 감싸줘도 유용하게 사용이 가능해요


    뭐 이런 식으루요!

    Promise.all(
      urlLists.map(url => {
        return new Promise(resolve => {
          someRequest(url(errresbody) => {
            resolve(JSON.parse(body))
          })
        })
      })
    )
  • rkdghgyun
    42
    2020-11-11 22:19:23

    와 진짜 hoonnote님 ㅠㅠㅠㅠ

    너무 감동입니다.... 진짜 너무 감사합니다 ㅠㅠㅠㅠㅠㅠ

    말로 표현 못 할 만큼 너무 감사드립니다.

    감사합니다!!!!

  • 로그인을 하시면 답변을 등록할 수 있습니다.