자바스크립트

[JavaScript] async, await 테스트

h__hj 2022. 9. 10. 20:56

# async, await 테스트 

 async 함수와 await 설정 확인 하기.

 

 해당 예제 코드는 모던 스크립트의 async await test code를 참조했습니다.

async
 function 앞에 async 키워드를 추가하면 두 가지 효과가 있습니다.
1. 함수는 언제나 프라미스를 반환합니다.
2. 함수 안에서 await를 사용할 수 있습니다.

await
 프라미스 앞에 await 키워드를 붙이면 자바스크립트는 프라미스가 처리될 때까지 대기합니다.
처리가 완료되면 조건에 따라 아래와 같은 동작이 이어집니다.
에러 발생 – 예외가 생성됨(에러가 발생한 장소에서 throw error를 호출한 것과 동일함)
에러 미발생 – 프라미스 객체의 result 값을 반환
 - await는 최상위 레벨 코드에서 작동하지 않습니다.

async/await
 함께 사용하면 읽고, 쓰기 쉬운 비동기 코드를 작성할 수 있습니다.
async/await를 사용하면 promise.then/catch가 거의 필요 없습니다.
하지만 가끔 가장 바깥 스코프에서 비동기 처리가 필요할 때같이 promise.then/catch를 써야만 하는 경우가 생기기 때문에 async/await가 프라미스를 기반으로 한다는 사실을 알고 계셔야 합니다.
여러 작업이 있고, 이 작업들이 모두 완료될 때까지 기다리려면 Promise.all을 활용할 수 있다는 점도 알고 계시기 바랍니다.

- async/await: Javascript Info
- async/await, ajax: 보러가기

# 환경

/**
 * tool: STS 4.13.0
 * version: 2.7.3-SNAPSHOT
 * java: 1.8
 * type: MAVEN
 * view: THYMELEAF
 * jQuery: 3.6.0
 */

 

# 페이지

# HTML

<h1>동기/비동기 테스트 페이지 입니다.</h1>

<div>
    <input id="toggle" type="button" onclick="toggle()" value="START" style="display: inline;"/>
    <br>
    <h3>SAMPLE CODE</h3>
    <input type="button" onclick="console.log(type1())" value="TYPE1" style="display: inline;"/>
    <input type="button" onclick="console.log(type2())" value="TYPE2" style="display: inline;"/>
    <input type="button" onclick="console.log(type3())" value="TYPE3" style="display: inline;"/>
    <input type="button" onclick="console.log(type4())" value="TYPE4" style="display: inline;"/>
</div>

# 4초 딜레이 함수, 2초 딜레이 함수, 발진기 함수(1초마다 타임스탬프로그.)

/** 4초 지연함수 */
function resolveAfter2Seconds() {
    console.log(timestamp(), ':', "starting 4초 함수");
    return new Promise(resolve => {
        setTimeout(function() {
            resolve(4000);
            console.log(timestamp(), ':', "4초 함수 is done");
        }, 4000);
    });
}
/** 2초 지연함수 */
function resolveAfter1Second() {
    console.log(timestamp(), ':', "starting 2초 함수");
    return new Promise(resolve => {
        setTimeout(function() {
            resolve(2000);
            console.log(timestamp(), ':', "2초 함수 is done");
        }, 2000);
    });
}
let isRun = false;
let interval = null;
function toggle() {
    if(isRun) {
        isRun = false;
        clearInterval(interval);
        $('#toggle').val('START');
    } else {
        isRun = true;
        interval = setInterval(function() {
            console.log('ING:', timestamp());
        }, 1000);
        $('#toggle').val('STOP');
    }
}
/** 1초 마다 시간 로그! */
function timestamp() {
    const date = new Date();
    const hh = String(date.getHours()).padStart(2, '0');
    const mi = String(date.getMinutes()).padStart(2, '0');
    const ss = String(date.getSeconds()).padStart(2, '0');
    return `${hh}:${mi}:${ss}`;
}

1. resolveAfter2Seconds (함수이름은 2초지만 4초로 변경함.)

  • 시작로그: starting 4초 함수
  • 종료로그: 4초 함수 is done
  • 응답로그: 4000

2. resolveAfter1Second (함수이름은 1초지만 2초로 변경함.)

  • 시작로그: starting 2초 함수
  • 종료로그: 2초 함수 is done
  • 응답로그: 2000

3. toggle

  • on 일 경우, 1초마다 현재 시간 log를 남김. >> 비동기 여부 확인을 위해
  • 로그패턴: ING: 23:59:59

# TYPE 1 (sequential)

function type1() {
    sequentialStart(); 	// 2초 후 로그 "느림" 후 1초 후 "빠름"	
    return timestamp() + " : " + '==SEQUENTIAL END==';
}
async function sequentialStart() {
    console.log(timestamp(), ':', '==SEQUENTIAL START==');

    // 대기 연산자 뒤에 오는 식의 값이 약속이 아닌 경우 확인된 약속으로 변환됩니다.
    const slow = await resolveAfter2Seconds();
    console.log(timestamp(), ':', slow);

    const fast = await resolveAfter1Second();
    console.log(timestamp(), ':', fast);
}
/*  LOG
    ING: 21:23:22
    ING: 21:23:23
21:23:23 : ==SEQUENTIAL START==
    21:23:23 : starting 4초 함수
21:23:23 : ==SEQUENTIAL END==
    ING: 21:23:24
    ING: 21:23:25
    ING: 21:23:26
    ING: 21:23:27
    21:23:27 : 4초 함수 is done
    21:23:27 : 4000
    21:23:27 : starting 2초 함수
    ING: 21:23:28
    ING: 21:23:29
    21:23:29 : 2초 함수 is done
    21:23:29 : 2000
    ING: 21:23:30
    ING: 21:23:31
*/
  • 호출된 함수는 바로끝나지만, 비동기로 함수가 진행.
  • 4초 함수가 다 끝난 이후, 2초 함수가 시작된다.
  • 함수명 그대로 순차적을 진행된다!

# TYPE 2 (concurrent)

function type2() {
    concurrentStart();  // 2초 후 로그 "느림" 후 "빠름"
    return timestamp() + " : " + '==CONCURRENT END with await==';
}
async function concurrentStart() {
    console.log(timestamp(), ':', '==CONCURRENT START with await==');
    const slow = resolveAfter2Seconds(); // 타이머를 즉시 시작합니다.
    const fast = resolveAfter1Second();

    console.log(timestamp(), ':', await slow);
    console.log(timestamp(), ':', await fast); // 이미 빠르게 완료되었음에도 불구하고, 천천히 끝날 때까지 기다립니다.
}
/*
    ING: 21:24:28
    ING: 21:24:29
21:24:30 : ==CONCURRENT START with await==
    21:24:30 : starting 4초 함수
    21:24:30 : starting 2초 함수
21:24:30 : ==CONCURRENT END with await==
    ING: 21:24:30
    ING: 21:24:31
    21:24:32 : 2초 함수 is done
    ING: 21:24:32
    ING: 21:24:33
    21:24:34 : 4초 함수 is done
    21:24:30 : 4000
    21:24:34 : 2000
    ING: 21:24:34
    ING: 21:24:35
*/
  • 호출된 함수는 4초함수, 2초함수가 비동기로 실행되고 바로 종료된다. 
  • 동시에 시작되어 2초 함수가 먼저 종료되고, 4초 함수가 종료된다.
  • 2초함수가 먼저 끝났지만, await slow 에서 4초 함수가 끝나길 기다린다.
  • 함수명 그대로 동시에 진행된다!

# TYPE 3 (stillConcurrent)

function type3() {
    stillConcurrent(); 	// concurrentStart와 동일
    return timestamp() + " : " + '==CONCURRENT END with Promise.all==';
}
function stillConcurrent() {
    console.log(timestamp(), ':', '==CONCURRENT START with Promise.all==');
    Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
        console.log(timestamp(), ':', messages[0]); // slow
        console.log(timestamp(), ':', messages[1]); // fast
    });
}
/*
    ING: 21:25:12
    ING: 21:25:13
21:25:14 : ==CONCURRENT START with Promise.all==
    21:25:14 : starting 4초 함수
    21:25:14 : starting 2초 함수
21:25:14 : ==CONCURRENT END with Promise.all==
    ING: 21:25:14
    ING: 21:25:15
    21:25:16 : 2초 함수 is done
    ING: 21:25:16
    ING: 21:25:17
    21:25:18 : 4초 함수 is done
    21:25:18 : 4000
    21:25:18 : 2000
    ING: 21:25:18
    ING: 21:25:19
*/
  • 함수명 그대로 TYPE2와 실행결과는 동일하다. 
  • 다만 함수에 async가 붙지않고, 변수의 await을 사용하지 않는다.
  • 대신 Promiss.all과 then() 함수를 이용.

# TYPE 4 (parallel)

function type4() {
    parallel(); // 진정한 병렬: 1초 후, 로그 "빠름" 후, 1초 후, "느림"
    return timestamp() + " : " + '==PARALLEL with Promise.then END==';
}
function parallel() {
    console.log(timestamp(), ':', '==PARALLEL with Promise.then==');
    resolveAfter2Seconds().then((message)=>console.log(timestamp(), ':', message));
    resolveAfter1Second().then((message)=>console.log(timestamp(), ':', message));
}
/*
    ING: 21:26:57
    ING: 21:26:58
21:26:58 : ==PARALLEL with Promise.then==
    21:26:58 : starting 4초 함수
    21:26:58 : starting 2초 함수
21:26:58 : ==PARALLEL with Promise.then END==
    ING: 21:26:59
    ING: 21:27:00
    21:27:00 : 2초 함수 is done
    21:27:00 : 2000
    ING: 21:27:01
    ING: 21:27:02
    21:27:02 : 4초 함수 is done
    21:27:02 : 4000
    ING: 21:27:03
    ING: 21:27:04
*/
  • TYPE2 와 TYPE3 과 흡사하다.
  • 호출된 함수는 4초함수, 2초함수가 비동기로 실행되고 바로 종료된다. 
  • 동시에 시작되어 2초 함수가 먼저 종료되고, 4초 함수가 종료된다.
  • 다른 점은 4초 함수가 끝나길 기다리지 않고 바로 실행한다.
  • 일반 ajax {async: ture} 와 비슷. (=또는 fetch)

# 내용 

jQuery ajax를 사용하면서 비동기로 처리되는 ajax를 동기적으로 움직이게 만드려면 해당 스킬이 사용되면 좋을 거 같다.

# JavaScript 시리즈

https://hjho95.tistory.com/21 async, await
https://hjho95.tistory.com/22 async, await를 이용한 ajax

# JavaScript 시리즈의 참조 페이지

async/await: https://ko.javascript.info/async-await