230208 JavaScript AJAX 1

kangjuju·2023년 2월 7일
0

Acorn

목록 보기
13/15

동기/비동기

  • 동기방식은 설계가 매우 간단하고 직관적이지만 결과가 주어질 때까지 아무것도 못하고 대기해야 하는 단점이 있고,

  • 비동기방식은 동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있다

웹개발은 비동기처리로 하는것이 적합하다. 동기처리로 하면 순차적으로 처리하기때문에 하나의 요청이 끝나기 전까지 나머지 요청은 대기를 해야하기때문.

Promise

비동기 처리를 위한 객체. AJAX 구현을 위해 사용된다.
자바스크립트의 비동기 처리란 ‘특정 코드의 실행이 완료될 때까지 대기하지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’을 의미한다.

Promise는 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다.

프로미스를 사용할 때 알아야 하는 가장 기본적인 개념이 바로 프로미스의 상태(states)입니다. 여기서 말하는 상태란 프로미스의 처리 과정을 의미합니다. new Promise()로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖습니다.

  • Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태

  • Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

  • Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

    https://cafe.daum.net/flowlife/HqLj/56

Promise 기본 객체 사용

        let promise = new Promise(function(resolve,reject){ 
            setTimeout(()=>resolve(console.log("완료")),2000);
        });
        promise;  

객체 생성과 동시에 executor가 자동 실행되며, setTimeout을 이용하여 약간의 지연시간을 주고 Promise가 적용이 되었는지 확인했다.

클라이언트가 new Promise로 서버에게 요청. Pending상태가 된다.
서버, 서버내 DB를 로딩하는 시간이 걸리는데 8초의 시간이 소요되었다면 Pending은 8초가 걸린것이고,
모두 완료되었을때 Fulfilled 상태로 처리가 끝난다.
실패했을땐 Rejected.

loadScript 연습용 스크립트 로드

        function loadScript(arg) {
            let script = document.createElement('script');
            script.src = arg;
            console.log(script);
            document.head.append(script);
        }
        loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js");
 

createElement로 script 태그를 감싸는 역할을 하는 loadScript 메소드를 만들고,
생성한 script 객체의 src에 매개변수를 넣었다.

최종적으로 head.append로 element부분의 head태그에 붙혔다.

해당 주소에 있는 연습용 스크립트를 로드했다.

callbackfunction 사용 - promise 를 사용하지 않고 로드

        function loadScript(src,callback){
            let script = document.createElement('script');
            script.src = src; //script를 감싸서 넣고, 
            //script가 onload시 콜백함수에 script이 들어가서 수행. 
            script.onload=()=>callback(script); 
            //실패시 Error객체 수행
            script.onerror=()=>callback(new Error(`${src}를 불러오는 도중에 에러 발생`));

            document.head.append(script);
        }
        loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js",
        script => {
            alert(`${script.src}가 로드됨`);
        });
 

비동기프로그래밍은 promise를 사용하지 않고 콜백함수를 사용하여 만들 수 있다.
사용하지는 않겠지만 promise를 이해하기 위해 알아두는 것이 좋을 것 같다.

이제 이 작업을 promise을 사용하여 구현해보자

Promise 사용하여 로드

        function loadScript(src) {
            return new Promise(function (resolve, reject) {
                let script = document.createElement('script');
                script.src = src;
                console.log("script src : " + script.src);
                
                script.onload = () => callback(script);
                script.onerror = () => callback(new Error(`${src}를 불러오는 도중에 에러 발생`));
                
                document.head.append(script);
            });
        } 

Promise의 Consumer함수 : then,catch~finally

여기에 이어서 then을 활용한 여러 핸들러를 처리해보자.

        let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js");
        promise.then(
            script => alert(`${script.src}`),
            error => alert(`Error : ${error.message}`)
        );

        promise.then(script=>alert('또 다른 핸들러 처리...'));
 

then() 메서드는 Promise를 리턴하고 두 개의 콜백 함수를 인수로 받는다. 하나는 Promise가 이행했을 때, 다른 하나는 거부했을 때를 위한 콜백 함수이다.

Promise 연습

.then 응용1

        function abc() {
            return new Promise(function (resolve, reject) {
                let data = 10;
                resolve(data); 
            });
        }
        abc().then(function (resolveData) { 
            console.log(resolveData);
            document.write(resolveData);
        }); 
  • abc() : 콜백함수 resolve에 매개변수에 들어가면서 resolve는 이행(fulfilled) 상태가 됨.

+abc().then.. : abc promise객체가 실행시 then이 작동된다.
이행상태가 된 promise-resolve의 리턴값을 resolveData로 정의했고
then은 정의한 함수를 실행시킨다.

.then 응용2 중첩

        function def() {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    resolve(1);
                }, 1000);
            }).then(function (result) {
                console.log(result);
                document.getElementById("disp").append(result + " ");
                return result + 10;
            }).then(function (result) {
                console.log(result);
                document.getElementById("disp").append(result + " ");
                return result + 20;
            }).then(function (result) {
                console.log(result);
                document.getElementById("disp").append(result + " ");
            })
        } 

promise객체를 만들고 resolve를 1초의 지연시간을 두고 이행상태를 만들었다.
따로 불러내지 않고 바로 이어서 then을 사용했는데, 해당 형태로 중첩하여 사용도 가능하다.

async & await

자바스크립트의 비동기 처리 패턴 중 최근에 나온 문법으로 기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.

자세한 내용

기본형태

async function 함수명() {
  await 비동기_처리_메서드_명();
}
        function fetchDatas() {
            return new Promise(function (resolve, reject) {
                const items = [1,2,3];
                resolve(items);
            })
        }
        async function ghi() { //비동기 처리용 함수 : await 필요
            try{
                const resultDatas = await fetchDatas(); //처리상태가 될때까지 대기상태. await
                document.getElementById('show').append(resultDatas);
            }catch(error){
                console.log(error);
            }
        } 

비동기 처리 코드 앞에 await를 붙인다. 여기서 주의 할 점은 비동기 처리 메서드가 꼭 프로미스 객체를 반환해야 await가 의도한 대로 동작한다.

async키워드로 비동기 처리용 함수를 선언하고, try문 안에 await Promise객체명(); 형태로 작성한다.

Promise객체는 await 키워드로 인해 resolve가 처리될때까지 대기상태가 되고, 처리되면 resultDatas에 값을 저장하게 된다.

await를 사용하지 않았다면 데이터를 받아온 시점에 콘솔을 출력할 수 있게 콜백 함수나 .then()등을 사용해야 했을것. 하지만 async await 문법 덕택에 비동기에 대한 사고를 하지 않아도 되는 것이다.

JS module

자세한 내용

모듈은 기본적으로 JavaScript 코드를 담고 있는 파일이다. 다만 일반적인 JavaScript 파일과는 다른 여러가지 차이점을 갖고 있다.

  • import 혹은 export 구문을 사용할 수 있다.
  • 별다른 처리를 해주지 않아도 엄격 모드(strict mode)로 동작한다.
  • 모듈의 가장 바깥쪽에서 선언된 이름은 전역 스코프가 아니라 모듈 스코프에서 선언된다.
  • export & import : js파일에서 선언된 객체의 일부를 모듈 스코프로 정의해 이름을 부여한다.
  • JS파일에서 또다른 js파일을 사용하고 싶을때 일부만 가져오고 싶을때 사용한다.

js - export

export let user = "홍길동";
const name = "자바책";
const price = "25000";
export let msg = {name,price}

export function sayHi(user){
    return `Hi, ${user}`;
}
export let func = function add(x,y){
    return x + y;
}

function f1(user){
    return `hello,${user}`
}
function f2(user){
    return `Bye,${user}`
}
export{f1,f2};

//default export
export default '하나의 값을 다른 js에서 임의의 변수명으로 받을 수 있다.';

//클래스 export
export class Animal{
    constructor(name){
        this.name;
    }
} 

export 지시어를 통해 현재 파일의 일부 멤버를 외부로 출력.
객체 하나에 지정할 수도 있고, 중괄호{}로 묶어서 보낼수도 있다.

html - import

    <script type="module">
    
        //default
        import imsi from './JS/jsex29.js';
        console.log(imsi);
        
        //일반멤버
        import { f1, f2 } from './JS/jsex29.js';
        console.log(f1('tom'));
        console.log(f2('Kim'));
        import { user } from './JS/jsex29.js';
        console.log(user);
        import { msg } from './JS/jsex29.js';
        console.log(msg['name'] + " " + msg['price']);
        
        //함수
        import { sayHi } from './JS/jsex29.js';
        console.log(sayHi("박준규"));
        import { func } from './JS/jsex29.js';
        console.log('두수의 합은', func(10, 20));
        
        //클래스
        import {Animal} from './JS/jsex29.js';
        let dog = new Animal("강아지");
    </script>
  • import {export멤버명} from 'module파일경로';

형태로 사용한다. 해당 스크립트에 존재하는 멤버처럼 사용할 수 있다.

async 응용 동적 export

js - export

export function hi(){
    alert("안녕");
}
export function bye(){
    alert("잘가");
}
 

html - import

		async function dyFunc() {
            let say = await import ('./JS/jsex29.js');
            say.hi();
            say.bye();
        }

0개의 댓글