iyOmSd/Title: Swift

[Swift] WWDC21 Meet async/await in Swift

냄수 2021. 11. 17. 17:23
반응형

String을 통해서 이미지를 가져오기 까지의 과정이다

이 과정들은 이전 작업에 따라 달라질 수 있다 즉, 순서대로 실행되야 합니다

 

URLRequest를 호출하는 부분과 Data로 이미지를 구성하는 것같이 빠르게 값이 반환되는 함수들은 함수가 실행되는 스레드에서 실행하여 동기호출이 되도록 하는 것이 좋습니다.

 

하지만 일부는 시간이 걸립니다

데이터를 다운로드하는 데 시간이걸리고

썸네일을 만들기위해 비싼 작업을 할 수 있는 장치가 필요하다

이러한 이유로 SDK는 이러한 작업을 완료하기위해 비동기 기능을 제공합니다

이러한 호출은 비동기식이어야 합니다

 

async/await 를 사용하기전 우리는 completion handler를 사용했다

fetchThumbnail이 호출되면 thumbnailURLRequest를 호출

이 함수는 동기적이라서 completion handler는 필요하지않습니다.

다음으로 URLRequest와 completion handler를 전달해서 dataTask를 호출하고 

resume을 통해 비동기 작업을 시작합니다

그런다음 fetchThumbnail이 반환되고 스레드는 자유롭게 다른 작업을 할 수 있습니다.

이미지 다운로드 하는데 시간이 걸리고 데이터 스트리밍 되는 것을 기다리는 스레드를 차단하지 않으려 하기 때문에 이는 매우 중요합니다.

결국 이미지 다운로드가 완료되거나 오류가 발생합니다.

어느쪽이든 요청이 완료되고 dataTask에 전달된 completion handler는 데이터, 응답 및 오류 같은 몇가지 선택적 값으로 호출됩니다.

 

데이터를 잘 받았다면

이미지를 데이터로 부터 생성하고

생성에 실패했다면 return합니다

 

이미지가 잘 생성 됬다면

completion handler를 전달해서 prepareThumbnail 함수를 호출하고

작업이 완료되는동안 스레드는 차단 해제되고 다른작업을 수행 할 수 있습니다.

작업이 성공하면 completion handler를 통해 이미지를 전달합니다.

 

여기서문제가있습니다

fetchThumbnail함수가 실패하더라도 작업이 완료되면 알림을 받을 것으로 예상하지만

현재 우리는

guard else return을 쓰는데 익숙해서

완료핸들러를 두번 호출하는 것을 잊었습니다.

따라서 UIImage를 만들거나 썸네일을 준비하는데 실패한다면 알림이 전송되지않고 업데이트 되지않아서 영원히 스피너를 보여주게 될것입니다.

 

일반함수는 호출자에게 오류를 던져서 오류를 받게 합니다.

스위프트는 실행이 어떻게 되든 값이 반환되지 않으면 오류가 발생하도록 보장합니다.

하지만 여기서 스위프트의 일반적인 에러처리 메커니즘을 사용할 수 없습니다.

문제가 발생하면 completion handler내에서 오류를 발생 시킬 수 없습니다.

스위프트가 우리작업을 확인 할 수 없다는 뜻이다.

스위프트에게 fetchThumbnail와 같은 completion handler는 단지 클로져일 뿐이다

 

completion handler가 호출되는지 확인하는 것은 사용자에게 달려 있습니다.

우리는 약 20줄의 코드에 미묘한 버그가 침투할 수 있는 5가지 기회를 포함하게 되었습니다.

우리가 원하는 것은 네가지 작업을 순서대로 수행하는 것이었습니다.

하지만 우리가 얻은 것은 따라가기 어렵고, 제대로 하기 어렵고, 우리의 의도를 흐리게 합니다

 

이것을 좀더 안전하게 만들 수 있었던 방법들이 있습니다.

표준 라이브러리의 Result 타입을 사용하는 것입니다.

조금 더 안전하긴 하지만 코드를 보기싫도록하고 약간 더 길게 만들수 있습니다.

 

이제 async/await를 사용하므로써 더 나은 작업을 수행 할 수 있습니다.

위의 4스텝의 함수를 수정해 볼 것이다.

 

함수를 async로 표시할 때 반환형 선언전에 throws를 선언해야합니다.

비동기 함수를 표시하면 함수 및 해당 서명이 더 단순해 질 수 있습니다.

 

thumbnailed가 성공하면 섬네일이 단순하게 반환됩니다.

에러가 발생한다면 그냥 던져집니다.

thumbnailURLRequest는 동기이므로 스레드가 차단되어 작업을 수행합니다.

 

그런다음 URLSession의 data함수를 통해서 데이터를 다운로드합니다.

Foundation에서 제공하는 비동기식입니다.

이 함수는 dataTask와 달리 awaitable합니다.

그래서 그것이 불려진후 스레드는 다른작업을 자유롭게 할 수 있습니다.

 

try await URLSession.shared.data(...)

try는 데이터방법이 throws로 표기되기 때문에 여기에 표시됩니다.

이전 버전에서 completion handler로 호출하는 방식을 기억하시나요?

awaitable한 버전에서는 모든 코드가 try키워드로 요약됩니다.

throws로 표기된 함수를 호출하려면 try가 필요한 것처럼 async로 표시된 함수를 호출하려면 await가 필요합니다

식에 여러 비동기 함수 호출이 있는 경우 여러개의 throwing함수 호출식에 대해 try가 하나만 필요한 것처럼

await도 한번만 쓰면됩니다.

모두 합치면 함수호출은 try await로 표시됩니다.

비동기식을 처리할 때 await전에 try를 써야합니다.

 

데이터 다운로드가 완료되면 data함수가 재개되고 fetchThumbnail로 돌아갑니다.

이 때 data함수가 반환하는 값 또는 오류가 유입됩니다.

오류가 발생하면 fetchThumbnail이 해당 오류를 차례로 발생시킵니다.

그렇지 않으면 데이터 및 응답 변수가 정의됩니다.

 

이전버전과 이번버전 두 버전 모두 URLSession의 비동기 방식으로 생성됬습니다.

하지만 awaitable 버전이 훨씬 더 간단합니다.

우리가 의미하는 바를 정확히 말해줍니다.

요청을 하고 변수를 사용할 수 있도록 값을 다시 변수에 할당하고 문제에 부딪히면 오류를 던집니다.

 

그런다음 다운로드한 데이터에서 UIImage를 만드려고 시도합니다.

성공하면 썸네일 이미지속성에 접근하여 해당이미지에 대한 축소 이미지가 렌더링됩니다.

썸네일이 형성되는 동안 스레드에서는 썸네일 속성이 재개되어 fetchThumbnail로 돌아올때까지 자유롭게 일을 할 수 있습니다.

썸네일이 렌더되면 fetchThumbnail로 돌아오고 그렇지 않다면 오류를 던집니다.

 

completion handler와 달리 썸네일 렌더가 되지않은경우 스위프트는 에러 또는 값을 반환하도록 보장합니다.

silently fail(조용한 실패)는 할 수 없다. 이게전부다.

이 함수는 completion handler버전이 수행한 것과 동일한 작업을 수행합니다.

하지만 20줄의 코드 대신 6줄만 있습니다.

그리고 모두 직선 코드이다(인덴트가 같다)

 

순서대로 수행해야하는 네가지 작업이 하나씩 나열됬고

Swift는 문제가 발생할 경우 오류를 던지거나, 함수가 항상 발신자에게 알리도록 합니다.

이것은 async/await 코드를 사용하여 비동기식 Swift 코드를

안전하고 짧게 변환하고 사용자의 의도를 보다 잘 반영 할 수 있는 방법의 한가지 예시입니다.

 

 

fetchThumbnail구현을 자세히 살펴보겠습니다.

마지막줄에 이부분에서 await가 사용됩니다.

썸네일 프로퍼티가 비동기이기 때문입니다.

함수뿐만아니라 프로퍼티, 생성자도 비동기가 될 수 있습니다.

SDK에 있는 프로퍼티가 아니라 Robert가 추가한 것입니다. 한번 보겠습니다.

여기서 주목할 점으로

첫째 명확한 getter가 있습니다.

이것은 프로퍼티 비동기 표시를 위해 필요합니다.

Swift5.5부터 프로퍼티 getter들 또한 throws 할 수 있습니다.

그리고 async함수 처럼 프로퍼티가 비동기식인 경우 async키워드는 throws 키워드 전에 위치합니다.

 

둘쨰, 프로퍼티에는 setter가 없습니다.

읽기전용 프로퍼티만 비동기일 수 있습니다.

 

함수, 속성, 생성자식에 await를 사용하여 함수가 스레드의 차단을 해제 할 수 있는 위치를 나타 낼 수 잇습니다.

async sequence를 반복하는 루프를 사용할 수 있습니다.

이 함수는 비동기 시퀀스에서 반복되면서 다음요소를 기다리는동안

스레드를 차단해제한 다음 루프 본문에

다음 요소를 삽입하거나 루프 이후에 요소가 남아있지 않는경우 다시 시작 할 수 있습니다.

자세한 내용은 Meet AsyncSequence 세션을 참조하세요

 

await를 이용 할 수 있는 곳이 많이있습니다.

비동기 기능이 여기서 일시중단 될 수있음을 나타냅니다.

비동기 일시중단된다는 것은 무엇을 의미하나요?

이 질문에 답하기위해 함수호출시 어떤 일이 일어나는지 생각해 봅시다.

 

함수를 호출하면 함수가 실행되는 스레드의 제어권한을 해당 함수로 넘깁니다.

thumbnailURLRequest같이 일반적인 함수일 경우 스레드는 끝날 때 까지 해당기능 대신 작업을 수행하느라 완전히 바쁩니다.

그 작업은 값을 반환하거나 오류를 발생시킴으로써 끝납니다.

그러면 제어 권한을 다시 사용자의 함수에 넘겨줍니다.

그것이 정상적인 함수가 스레드 제어를 포기할 수 있는 유일한 방법입니다. 마무리를 통해서요

그리고 당신의 함수는 그것이 통제할 수 있는 유일한 것입니다.

호출하는 비동기 함수라면 상황이 달라집니다.

일반적인 함수과 마찬가지로 작업이 완료되면 제어가 완료되고 다시 함수로 돌아갑니다.

하지만 일반적인 함수과 달리 그것은 완전히 다른 방식으로 스레드의 제어를 포기할 수 있습니다. 중단을 통해서요

 

일반적인 함수처럼 비동기함수를 호출하면 스레드 제어권한을 부여합니다.

일단 실행되면 비동기함수를 일시중단 할 수 있습니다.

그렇게 되면 스레드에 대한 제어권한을 포기합니다.

그러나 사용자의 함수에 다시 제어권한을 부여하는 대신 시스템에 스레드에 대한 제어권한을 부여합니다.

그렇게 되면 당신의 함수도 정지됩니다.

 

일시중단은 시스템에 말한다. "해야할 일이 많다는 것을 알고있습니다. 무엇이 가장 중요한지는 당신이 결정하세요"

얼마나 협조적인가?

따라서 일단 함수가 중단되면 시스템은 스레드를 자유롭게 사용하여 다른 작업을 수행 할 수 있습니다.

 

어느시점에서는 시스템이 수행해야할 가장 중요한 작업이 이전에 일시중단된 비동기기능을 계속하는 것이라고 결정합니다.

그러면 시스템이 다시 시작됩니다.

그러면 비동기기능이 다시 스레드를 제어하게되고 계속 작업할 수 있습니다.

 

그리고 원한다면 다시 중단할 수 있습니다.

그것은 스스로 필요한 만큼 일시중단 할 수 있습니다.

반면에, 그것은 스스로 중단될 필요가 없을지도 모른다.

비동기 함수가 일시중단될 수 있지만 비동기 함수로 표시된다고 해서 반드시 일시중단 되는것은 아닙니다.

같은이유로 await가 나타난다고해서 기능이 거기서 확실히 정지되는 것은 아닙니다.

결국 중단없이 또는 마지막으로 재개된 후에 함수는 종료되며 값이나 오류와 함께 스레드에 대한 제어권한을 다시 함수에 넘깁니다.

 

fetchThumbnail이 일시중단 되면 어떤일이 발생 할 수 있는지 살펴보겠습니다

URLSession의 비동기 함수를 호출할때 data함수는 비동기 함수만의 할 수 있는 특별한 방법으로 스레드에서의 실행을 중지시킵니다.

일시중단했고

시스템에 스레드 제어권한을 부여하고 URLSession의 data함수에 대한 작업스케줄을 시스템에 요청합니다.

 

이 시점에서는 시스템에 제어되고 있으며 해당 작업이 즉시 시작되지 않을 수 있습니다.

그 스레드는 다른 용도로 사용될 수 있습니다.

fetchThumbnail이 호출된 후 사용자가 어떤데이터 업로드할 버튼을 탭한다고 가정했을때

예를들어 그들이 post에 반응한다고 하면

이전에 대기중인 작업전에 사용자의 반응을 post하는 작업을 자유롭게 실행 할 수 있습니다.

 

Late-breaking(임시)작업이 완료되면 URLSession의 data함수를 재개할 수 있습니다. 또는 시스템이 다른 작업을 실행할 수 있습니다.

마지막으로 data함수가 완료되면 fetchThumbnail로 돌아갑니다

스위프트는 함수가 일시중단된 동안 다른작업을 수행 할 수 있기 때문에 비동기 호출을 await 키워드로 표시해야한다고 주장합니다.

함수가 정지될 때 앱의 상태가 급격하게 변할 수 있다는 것을 알아야합니다.

 

completion handler일 때도 마찬가지입니다.

그러나 async/await 코드에 수반되는 ceremony(의식) 과 들여쓰기가 없기 떄문에

await키워드는 코드블록이 하나의 트랜잭션으로 실행되지 않는다는 것을 어떻게 알아채는가입니다

함수가 정지될 수 있고, 함수의 라인 사이에 정지되는 동안 다른 일들이 발생 할 수 있습니다.

 

async/await에대해 기억해야할 중요한 사항입니다.

첫째, async로 함수를 표시하면 해당 함수가 일시 중단 될 수 있습니다.

그리고 함수가 스스로 정지되면 호출자도 정지됩니다. 따라서 호출자도 비동기여야 합니다.

둘째, 비동기 함수에서 일시 중단이 한번 이상 발생할 수 있는 위치를 지적하기위해 await키워드가 사용됩니다.

셋째, 비동기 함수가 일시중단되는 동안 스레드는 차단되지 않습니다.

시스템은 다른일을 자유롭게 스케줄링할 수 있습니다.

나중에 시작하는 작업도 먼저 실행 할 수 있습니다.

그것은 함수가 정지된 동안 당신의 앱의 상태가 크게 바뀔 수 있다는 것을 의미합니다.

(Finally, when an async function resumes, the results returned from the async function it called flow back into the original function, and execution continues right where it left off.)

마지막으로, 비동기함수가 재개되면, 원래 함수로 돌아가서 비동기 함수로부터 결과를 반환받고, 실행은 중단되었던 바로 그자리에서 계속됩니다.

 

스위프트에서 async/await가 어떻게 작동하는지 봤을것입니다.

이제부턴 로버트가 프로젝트에서 어떻게 그것을 사용하는지 보여줄 것입니다.

현대 소프트웨어 개발에 중요한 테스트부터 시작하겠습니다

우리는 비동기 코드를 테스트하는 것이 동기 코드를 테스트하는 것만큼 쉽기를 원했습니다

 

XCTest는 비동기 기능을 지원합니다

expectation, fulfillment, 명시적인 wait를 제거하고 대신 위에서 설명한 비동기 fetchThumbnail함수를 호출하는 결과를 기다립니다.

 

테스트는 끝났으니 애플리케이션 코드 자체를 확대해보자.

각 행의 리스트에 thumbnailView가 있다

 

이미지셀은 Post와 함게 생성되며 각 Post는 id를 가지고 뷰모델에 전달하여 썸네일을 비동기식으로 검색합니다.

테스트 코드에서 이호출을 변환하는 방법을 살펴봤으므로 한번 시도해보겠습니다.

 

completion handler를 제거하고

try를 추가합니다. 그리고 비동기함수에대한 호출을 완료하기위해 await를 추가합니다.

하지만 우리가 이코드를 만들려할때 에러가뜹니다.

스위프트 컴파일러는 그 자체가 비동기적이지 않은 컨텍스트에서는 비동기함수를 호출 할 수 없다고 말합니다.

여기서 onAppear수식어는 일반적이고 비동기가 아닌 클로저이므로 동기식과 비동기식 사이의 격차를 메울 방법이 필요합니다.

 

해결책은 비동기 Task 함수를 사용하는것입니다.

클로저의 작업을 패키징해서 global dispatch queue의 비동기 함수와 같이 사용 가능한 다음 스레드에서 즉시 실행할 수 있도록 시스템으로 보냅니다.

가장 큰 장점은 비동기 코드를 동기 컨텍스트 내부에서 호출할 수 있다는 것입니다.

다시 빌드하면 컴파일러가 만족합니다.

비동기 task는 친숙하고 자연스럽게 구조화된 스타일로 풍부한 동시성 스위프트 코드를 작성할 수 있는 API의 일부입니다.

 

앱에서 async/await방식을 채택할 수 있는 기회가 많다

빠르게 시작하고 실행하려면 기존 API에 대한 비동기식 대안으로 작게 시작하는 것이 좋습니다.

스위프트 동시성이 점진적으로 채택되어야합니다.

completion handler api에 대한 대체 비동기 API제공

xcode의 비동기 리팩터링 작업이 도움이 될 수 있음

 

SDK는 비동기 방식으로 사용자를 대신하여 작업하기때문에 completion handler를 사용하는 수백개의 API를 제공합니다.

이 API들이 나란히 정렬되면 패턴이 나타나기 시작합니다.

이러한 콜밸 블록을 비동기 함수로 전환하면 멋지지않을까요?

swift5.5에서는 이렇게됩니다!

스위프트 컴파일러는 자동으로 Objective-C에서 가져온 completion handler코드를 살펴보고 비동기식 대안을 제공합니다.

 

여기서 멈추지않고

또한 많은 delegate API에 completion handler를 전달하는 함수가 포함되어있습니다.

비동기 작업이 완료되면 핸들러를 호출하여 프레임워크에 알립니다.

 

이전과 마찬가지로 모든 경로에서 completion handler를 불러줘야합니다.

async await에서는 더이상 그럴 필요가 없습니다.

이 delegate 함수대신 사용할 수 있는 비동기식 대안이 있습니다.

먼저 선행 "get"을 삭제하는 비동기 대안 이름이 사용됩니다.

비동기 함수는 호출결과가 직접 반환되지 않을때 통신하는 "get"과 같은 선행 단어를 생략하는 것이 좋습니다.

결국 이것은 비동기 대체 함수이기 때문에 타임라인 항목을 직접 반환합니다.

비동기 컨텍스트가 설정되었으므로 fetchThumbnail의 비동기 버전을 호출합니다.

마지막으로, 지금 삭제된 완료 블록을 호출하는 대신 이 함수에서 타임라인 항목을 반환합니다.

 

이 모든상황은 Swift가 당신을 대신하여 비동기식 대안을 만드는 상황의 예입니다

하지만 불가피하게 코드에 비동기식 대안을 직접 만들어야 하는 곳이 있을것입니다.

 

코어데이터 저장소에 있는 저장된 모든 게시물을 검색하는 기능을 가진 함수입니다.

이 기능은 앱에서 비동기 썸네일 보다 더 많은 곳에서 호출되므로 비동기 함수를 사용한는 것은 매우 큰 변화가 될것입니다.

이함수는 비동기 대안으로 완벽한 후보인 것 같습니다.

 

먼저 비동기 함수로 만들고 반환값을 변환 합니다.

이 함수는 오류를 발생 시킬 수 있기 때문에 throws 표시도 해야합니다.

 

다음으로 우리는 completion handler버전의 getPersistentPosts를 호출합니다.

그리고 이제 우리는 아무것도 할 수 없습니다.

 

우리는 콜백에서 비동기 persistentPosts함수를 호출한 대기 중인 장소로 리턴해야합니다.

그것뿐만아니라 호출자들은 일시중단 상태에 있습니다.

그들이 나머지 작업을 계속 할 수 있도록 적절한 시점에 적절한 데이터로 재개해야합니다.

 

앞서 스위프트 시스템이 우리를 위해 비동기 코드를 재개하기 위해 어떻게 협력하는지 보여줬습니다.

이 일시중단/재개 프로세스가 어떻게 작동하는지 더 자세히 살펴보고 우리의 문제에 대해 해결책을 제시할 수 있는지 알아보겠습니다.

 

비동기버전의 persistentPosts가 호출되면 Core Data를 호출합니다.

나중에 Core Data는 completion handler를 호출하고 요청 결과를 전달합니다.

이상황은 앞서 비동기 fetchThumbnail 함수가 일시중단된 비동기 함수를 재개하도록 코어데이터가 아닌 시스템에게 요청했을때와 동일하다.

(All that’s missing is a bridge to await the completion handler and resume with the fetch request’s results.)
빠진 것은 completion handler를 await하고 요청의 결과로 재개하는 bridge이다.

(아래그림의 await, resume브릿지가 빠졌다고 설명함)

 

이 패턴은 계속 나타날 것이며 그것의 이름은 continuation 라고할 것이다.

함수의 호출자는 함수의 결과를 (await)기다리고 다음에 수행할 작업을 지정할 수 있는 클로저를 제공합니다.

 

(getPersistentPosts -> await -> Core Data 과정)

 

함수 호출이 완료되면 completion handler를 호출하여 호출자가 원하는 결과를 다시 시작합니다.

(Core Data -> resume -> getPersistentPost 과정)

 

이러한 종류의 협동 실행은 스위프트 비동기 함수가 작동하는 방식입니다.

 

이를 명확하게 하기위해 Swift는 사용자가 high level 수준의 안전한 방법으로 continuation을 계속 생성, 관리, 재개할 수 있는 기능을 제공합니다.

다시 예시로 돌아가서 continuation이 비동기식 대안 작성을 완료하는데 어떤 도움이 되는지 알아보겠습니다.

 

withCheckedThrowingContinuation함수는 completion블럭과 함께 에러를 던질수 있는 비동기 함수를 입니다.

함수가 절대 오류를 발생시키지 않는 상황을 위해 CheckedContinuation타입과 함께 호출됩니다.

이러한 함수는 중단된 비동기 함수를 재개하는데 사용할 수 있는 continuation값에 접근할 수 있는 방법입니다.

이것은 또한 우리가 getPersistentPosts에 대한 호출을 기다릴 수 있게 함으로써 브릿지의 첫번째 부분을 구축합니다.

 

브릿지 건설을 끝냅니다.

continuation값은 completion handler의 결과를 저장할 수 있는 resume함수를 제공합니다.

그뿐만아니라, resume은 persistentPosts함수의 결과를 기다리는 모든 호출을 중단시키는데 필요한 누락된 링크를 제공합니다

그리고 completion handler에서 비동기 함수에 이르기까지 완성된 브릿지가 한 패키지 안에 있습니다.

 

continuation은 비동기함수를 수동으로 제어할 수 있는 강력한 방법을 제공하지만

몇가지 유의사항이 있습니다.

resume은 모든 경로에서 정확히 한번씩 호출 되어야합니다.

걱정마세요 Swift가 뒤를 봐줄 것입니다.

만약 continuation이 resume 호출없이 제거되면 스위프트 런타임이 비동기 호출시 결코 일시중단되지 않는다고 경고를 할것입니다.  

 

같은 함수에서 continuation resume이 여러번 있으면 프로그램 데이터가 손상될 수 있어서 더 심각한 오류가 발생합니다.

이 문제를 해결하기위해서 스위프트 런타임은 여러번 resume호출하려는 시도를 감지하고 두번째 resume시점에 fatal error가 발생하도록 보장합니다.

 

이런한 점을 염두해두고 checkedContinuation을 사용할 수 있는 중요한 위치를 하나 더 강조해보겠습니다.

 

많은 API들이 이벤트 중심입니다.

그것들은 특정 중요 지점에 우리의 애플리케이션에 알림을 주고 적절하게 응답할 수 있도록 delegate 콜백을 제공합니다.

async/await 방식을 올바르게 채택하려면 continuation을 저장하고 나중에 resume해야 합니다.

이전과같이 checked continuation을 만듭니다.

 

그리고 나서 우리는 그것을 저장하고 일을 시작합니다.

 

check continuation이 API를 준수하기위해 active continuation을 resume하고

마지막으로 nil을 넣어줘서 한번 이상 호출하지 않도록 합니다.

 

요약: continuation을 따로 변수로 저장 하고 delegate API시점에 맞게 resume해주고 nil처리해줘서 중복사용못하도록 막음

 

delegate API가 여러번 호출되거나 특정 상황에서 전혀 호출되지 않는경우 active continuation을 정확히 한번 resume하는 것이 중요합니다.

 

지금까지 async await 키워드가 어떻게 작동하는지, 애플리케이션 및 프레임워크에서 어떻게 채택할 수 있는지 보여드렸습니다.

시작을 위해 SDK에서 사용 할 수 있는 비동기 API의 샘플링을 제공하고 기존코드를 동기 세계에서 비동기 세계로 브릿지하는 방법을 보여드렸습니다.

 

 

 

 

 

 

 

반응형