ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [멋쟁이사자처럼] json-server 이용한 JS비동기 통신 특강
    Front-end 개발 2023. 9. 27. 22:04

    목차

    1. 비동기

    2. json-server 만들기

    3. Fetch API 를 이용해 서버와 데이터 통신하기


    오늘은 비동기 개념을 보충해주는 특강이 있다.

    즐거운 한가위를 맞이하기 전 마지막 수업으로 찝찝했던 부분을 일부 해소할 수 있었다.

    이전까지는 간단한 database 없이, html 에 바로 생성하거나 브라우저 로컬스토리지를 이용 todo 리스트를 만들어 보았다. 이번 수업에서는 간단한 json 서버를 만들고 데이터를 생성하고, 읽어오고, 제거해 본다.

    추석 연휴 전날까지 고생해주신 강사님께 감사할 따름이다.

    1. 비동기


    1-1. 동기적인 처리

    - 비동기 처리는 동기적으로 처리되지 않는 것을 이야기한다.

    -하나의 흐름에서 순차적

    - 출력1 > 출력2 > 출력3

    - 각각의 함수는 완전히 종료되며 이어진다.

    const 출력1 = ()=>console.log(1)
    const 출력2 = ()=>console.log(2)
    const 출력3 = ()=>console.log(3)
    
    출력1()
    출력2()
    출력3()
    
    // 출력
    // 1
    // 2
    // 3

    - 하지만 비동기는 그렇지 않다.

     

    1-2. 비동기적인 처리

    const 출력1 = ()=>console.log(1)
    const 출력2 = ()=>console.log(2)
    const 출력3 = ()=>console.log(3)
    
    // 비동기
    const 비동기출력1 = ()=>{
            console.log("비동기함수1실행")
        setTimeout(출력1,1000);
    }
    const 비동기출력2 = ()=>{
      console.log("비동기함수2실행")
        setTimeout(출력2,1500);
    }
    const 비동기출력3 = ()=>{
      console.log("비동기함수3실행")
        setTimeout(출력3,500);
    }
    
    비동기출력1()
    비동기출력2()
    비동기출력3()
    
    // 출력
    // 비동기함수1실행
    // 비동기함수2실행
    // 비동기함수3실행
    // undefined
    // 3
    // 1
    // 2

    - 실행이 하나의 흐름에 존재하지 않기 때문에 위와 같은 현상이 일어난다.

    - 출력3 > 출력1 > 출력2

    - 실행은 순차적으로 진행되지만 각각의 함수 실행은 개별적으로 진행된다.

    - 다른 작업의 종료와 상관없이 영향을 받지 않고 실행된다.

    - JS 는 동기적으로 동작하지만, 비동기를 지원한다.

     

    1-3. 비동기 통신

    - 왜 통신을 하는데 비동기라는 용어를 붙여 놓았을까?

    - 각 작업은 별도로 행동하는 주체이며 비동기적으로 행동한다고 본다.

    - 구글 맵이 페이지 이동할 때 멈추거나, 인스타그램이 댓글을 써서 멈춘다면 정말 불편할 것이다.

    - AJAX 라는 기법은 비동기 자바스크립트 그리고 XML 의 줄임말이다.

     

    1-4. Fetch API 기초 사용법

    - 총 2가지 방법을 이용해 본다.

    - fetch는 HTTP 통신을 이용한다.

    - fetch(<url>) : fetch를 이용해 get 요청을 보내게 된다.

    - fetch(url, [option] : fetch에 URI 뿐만 아닌 다른 속성을 객체형태로 념겨주어 요청을 보낸다.

    - get 은 데이터를 받아오는 것이다.

    - post 는 데이터를 보내는 것이다.

    - fetch 에서는 HTTP는  body에 들어가 있다.

    //fetch로 get요청 보내기, 옵션을 넣지 않으면 get요청이다.
    fetch("요청할주소")
    
    //fetch에 옵션을 넣어 POST요청 보내기
    fetch("요청할 주소",{
    	method: "POST",
    	header: {
    		"Content-Type":"application/json"
    	},
    	body: "{text:'안녕하세요'}"
    })

    - 책추천: HTTP 완벽 가이드

    - 최소한 1 ~ 3장까지 읽을 것

    2. json-server 만들기


    2-1. json-server 를 이용해 간단한 서버 만들어보기

    - 서버를 만들기 위해 json-server 를 npm 으로 설치해보자

    npm install -g json-server

    - fetch 폴더 > db 폴더 > db.json 파일 생성

    fetch > db > db.json 생성

    {
        "todos":[]
    }

    - json-server 실행

    json-server --watch db.json
    
    // 실행 후 브라우저 접속 http://localhost:3000/todos

    vscode 터미널에서 json-server 실행
    브라우저를 통해 json-server 링크 접속

    - URI 를 통해 들어간 형태가 get 요청이다.

    3. fetch 를 이용해 서버와 서버와 통신하기


    - 브라우저 about:blank 에 접속해서 개발자 도구를 열어보자

    - 개발자 도구 콘솔에서 fetch 를 이용해 get 요청을 해본다.

    fetch('http://localhost:3000/todos').then(res=>res.json()).then(json=>console.log(json))

    fetch 로 get 요청

    - db.json 파일의 데이터를 바꿔본다.

    {
        "todos":[{
                "id":1,
                "todo":"밥먹기"
            }]
    }

    - 갱신된 데이터를 fetch 로 불러와 확인해보자

    바뀐 데이터를 받아서 확인

     

    2-3. html 파일에서 fetch 이용해서 서버와 통신하기

    - json-server 를 켜둔 상태로 vscode 에서 파일을 생성한다.

    - db.json 파일과 다른 폴더 경로에 새로운 폴더와 index.html 파일을 생성한다.

    - 그 이유는 json-server 에 데이터 요청으로 변경이 되면 새로고침을 수행한다.
      이때  index.html 이 같은 경로에 있다면, fetch 를 실행하는 index.html도 재실행되기 때문이다.

    - fetch 폴더 > HTML 폴더 > index.html 경로에 생성한다.

    fetch 폴더 > HTML 폴더 >index.html 생성

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script>
            fetch("http://localhost:3000/todos")
                        .then(data=>data.json())
                        .then(json=>console.log(json))
        </script>
    </body>
    </html>

    - 현재 vscode live 서버는 5500 port로 열려있고, json-server 는 3000 port에 열려 있는 상황이다.

    - live 서버에서는 데이터를 json-server 에서 데이터를 가져가고 있다.

     

    2-4. fetch 에서 Post 를 이용하기 

    - 데이터를 보내거나, 로그인을 할 때 post 를 사용한다.

    - post 요청을 하면서 필요한 명세를 적어서 보낸다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script>
              fetch("http://localhost:3000/todos",{
              method: "POST",
              headers: {
                    "Content-type": "application/json"
              },
              body: JSON.stringify({
                    todo:"밥안먹기"
               }),
          })
          .then(data=>data.json())
                .then(json=>console.log(json))
        </script>
    </body>
    </html>

    - post 요청을 보내서 json-server 데이터가 추가되었다.

    post 요청으로 db.json 데이터가 추가됨

     

    2-4. button 으로 데이터 추가하기

    - createTodo 와 getTodoList 를 정의하여 데이터를 추가하고 읽어온다.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <button>todo 추가</button>
        <div id="todo"></div>
        <script>
            const $button = document.querySelector("button");
    
            const createTodo = () => {
                fetch("http://localhost:3000/todos", {
                    method: "POST",
                    headers: {
                        "Content-type": "application/json"
                    },
                    body: JSON.stringify({
                        todo: "밥안먹기"
                    }),
                })
                    .then(data => data.json())
                    .then(json => {
                        console.log(json)
                        getTodoList()
                    })
            }
    
            const getTodoList = () => {
                fetch("http://localhost:3000/todos")
                    .then(data => data.json())
                    .then(json => {
                        document.querySelector("#todo").innerHTML = ""
                        json.forEach(todo => {
                            document.querySelector("#todo")
                                .innerHTML += `<li>${JSON.stringify(todo)}</li>`
                        })
                    })
            }
            $button.addEventListener("click", createTodo)
    
            getTodoList();
        </script>
    </body>
    
    </html>

     

    2-5. input 요소로 text 를 받아 서버로 데이터 보내기

    - input 요소의 value 를 가져와 event 핸들러에 적용시키기

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <input />
        <button>todo추가</button>
        <div id="todo"></div>
        <script>
            const $button = document.querySelector("button");
            // 텍스트를 입력받아서 서버로 요청을보내는 함수!
            const createTodo = (todoText) => {
                fetch("http://localhost:3000/todos", {
                    method: "POST",
                    headers: {
                        "Content-type": "application/json"
                    },
                    body: JSON.stringify({
                        todo: todoText
                    }),
                })
                    .then(data => data.json())
                    .then(json => {
                        console.log(json)
                        getTodoList()
                    })
            }
            const getTodoList = () => {
                fetch("http://localhost:3000/todos")
                    .then(data => data.json())
                    .then(json => {
                        document.querySelector("#todo").innerHTML = ""
                        json.forEach(todo => {
                            document.querySelector("#todo")
                                .innerHTML += `<li>${JSON.stringify(todo)}</li>`
                        });
                    })
            }
            const inputTodo = () => {
                // 인풋요소에서 값을 가져온다.
                const todoText = document.querySelector("input").value
                // 가져온 값을 createTodo에 넘겨준다!
                createTodo(todoText)
                document.querySelector("#todo").innerHTML = ""
    
            }
            $button.addEventListener("click", inputTodo);
    
            getTodoList();
        </script>
    </body>
    
    </html>

     

    2-6. delete 로 db 데이터 제거하기

    - HTTP 메소드 delete 를 활용하기

    - id 는 getTodoList 의 todo 에 들어 있다.

    - innerHTML 로 요소를 붙이면 event 가 지워진다.

    - li 요소를 append 로 붙인다.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <input />
        <button>todo추가</button>
        <div id="todo"></div>
        <script>
            const $button = document.querySelector("button");
            // 텍스트를 입력받아서 서버로 요청을보내는 함수!
            const createTodo = (todoText) => {
                fetch("http://localhost:3000/todos", {
                    method: "POST",
                    headers: {
                        "Content-type": "application/json"
                    },
                    body: JSON.stringify({
                        todo: todoText
                    }),
                })
                    .then(data => data.json())
                    .then(json => {
                        console.log(json)
                        getTodoList()
                    })
            }
            const getTodoList = () => {
                fetch("http://localhost:3000/todos")
                    .then(data => data.json())
                    .then(json => {
                        document.querySelector("#todo").innerHTML = ""
                        json.forEach(todo => {
                            const $li = document.createElement("li")
                            $li.innerHTML = todo.todo;
    
                            const $deleteButton = document.createElement("button");
                            $deleteButton.addEventListener("click", () => deleteTodo(todo.id));
                            $deleteButton.innerText = todo.id + "삭제";
                            document.querySelector("#todo").append($li, $deleteButton)
                        });
                    })
            }
            const inputTodo = () => {
                // 인풋요소에서 값을 가져온다.
                const todoText = document.querySelector("input").value
                // 가져온 값을 createTodo에 넘겨준다!
                createTodo(todoText)
                document.querySelector("#todo").innerHTML = ""
    
            }
            const deleteTodo = (id) => {
                fetch("http://localhost:3000/todos/" + id, {
                    method: "DELETE"
                })
                    .then(data => data.json())
                    .then(json => {
                        getTodoList()
                    })
            }
    
            $button.addEventListener("click", inputTodo);
    
            getTodoList();
        </script>
    </body>
    
    </html>

    최종 실행 결과

     

Designed by Tistory.