수색…
소개
async
이며 비동기식 동작을 인라인으로 표현하기 위해 약속과 생성기를 기반으로 빌드를 await
립니다. 따라서 비동기 또는 콜백 코드를 훨씬 쉽게 유지 관리 할 수 있습니다.
async
키워드를 사용하는 함수는 Promise
반환하고 해당 구문으로 호출 할 수 있습니다.
async function
에서 await
키워드는 모든 Promise
적용될 수 있으며, 약속이 해결 된 후에 await
수있는 모든 함수 본문이 실행됩니다.
통사론
- 비동기 함수 foo () {
...
asyncCall ()을 기다린다.
} - 비동기 함수 () {...}
- async () => {...}
- (async () => {
const 데이터 = asyncCall () 대기
console.log (data)}) ()
비고
비동기 함수는 약속 및 생성기에 대한 통사론입니다. 코드를보다 읽기 쉽고, 관리하기 쉬우 며, 오류를 쉽게 잡을 수있게하고, 들여 쓰기 수준을 낮추는 데 도움이됩니다.
소개
async
로 정의 된 함수는 비동기 작업을 수행 할 수 있지만 여전히 동기식으로 볼 수있는 함수입니다. 그것이 완료되면 await
키워드를 사용하여 Promise 가 해결하거나 거부하기를 기다리는 동안 함수를 연기합니다.
참고 : 비동기 함수는 ECMAScript 2017 표준에 포함될 트랙 4 단계 ( "완료") 제안 입니다.
예를 들어, 약속 기반 Fetch API 사용 :
async function getJSON(url) {
try {
const response = await fetch(url);
return await response.json();
}
catch (err) {
// Rejections in the promise will get thrown here
console.error(err.message);
}
}
비동기 함수는 항상 Promise 자체를 반환하므로 다른 비동기 함수에서도 사용할 수 있습니다.
화살표 기능 스타일
const getJSON = async url => {
const response = await fetch(url);
return await response.json();
}
덜 들여 쓰기
약속 있음 :
function doTheThing() {
return doOneThing()
.then(doAnother)
.then(doSomeMore)
.catch(handleErrors)
}
비동기 함수 사용 :
async function doTheThing() {
try {
const one = await doOneThing();
const another = await doAnother(one);
return await doSomeMore(another);
} catch (err) {
handleErrors(err);
}
}
반환 값이 맨 아래가 아닌 상단에 있는지, 그리고 언어의 원시 오류 처리 메커니즘 ( try/catch
)을 사용하는지 확인하십시오.
기다리고 연산자 우선 순위
await
키워드를 사용할 때는 연산자 우선 순위를 염두에 두어야합니다.
다른 비동기 함수 인 getUnicorn()
을 호출하는 비동기 함수가 있다고 가정하고 Unicorn
클래스의 인스턴스로 확인되는 Promise를 반환합니다. 이제는 해당 클래스의 getSize()
메서드를 사용하여 유니콘의 크기를 가져 getSize()
.
다음 코드를 살펴보십시오.
async function myAsyncFunction() {
await getUnicorn().getSize();
}
첫눈에 그것은 유효하지만 보이지 않습니다. 연산자 우선 순위 때문에 다음과 같습니다.
async function myAsyncFunction() {
await (getUnicorn().getSize());
}
여기서 Promise 객체의 getSize()
메서드를 호출하려고합니다.이 메서드는 우리가 원하는 것이 아닙니다.
대신 우리는 괄호를 사용하여 먼저 유니콘을 기다리고 그 결과에 대한 getSize()
메서드를 호출해야 함을 나타냅니다.
async function asyncFunction() {
(await getUnicorn()).getSize();
}
당연하지. 예를 들어 getUnicorn()
함수가 동기식 이었지만 getSize()
메소드가 비동기 인 경우와 같이 이전 버전이 유효 할 수 있습니다.
약속과 비교되는 비동기 함수
async
함수는 Promise
형식을 대체하지 않습니다. 약속을 쉽게하기 위해 언어 키워드를 추가합니다. 그들은 상호 교환 가능하다 :
async function doAsyncThing() { ... }
function doPromiseThing(input) { return new Promise((r, x) => ...); }
// Call with promise syntax
doAsyncThing()
.then(a => doPromiseThing(a))
.then(b => ...)
.catch(ex => ...);
// Call with await syntax
try {
const a = await doAsyncThing();
const b = await doPromiseThing(a);
...
}
catch(ex) { ... }
약속의 사슬을 사용하는 함수는 다음과 같이 await
사용하여 다시 작성할 수 await
.
function newUnicorn() {
return fetch('unicorn.json') // fetch unicorn.json from server
.then(responseCurrent => responseCurrent.json()) // parse the response as JSON
.then(unicorn =>
fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
})
)
.then(responseNew => responseNew.json())
.then(json => json.success) // return success property of response
.catch(err => console.log('Error creating unicorn:', err));
}
이 함수는 다음과 같이 async
/ await
을 사용하여 다시 작성할 수 있습니다.
async function newUnicorn() {
try {
const responseCurrent = await fetch('unicorn.json'); // fetch unicorn.json from server
const unicorn = await responseCurrent.json(); // parse the response as JSON
const responseNew = await fetch('new/unicorn', { // send a request to 'new/unicorn'
method: 'post', // using the POST method
body: JSON.stringify({unicorn}) // pass the unicorn to the request body
});
const json = await responseNew.json();
return json.success // return success property of response
} catch (err) {
console.log('Error creating unicorn:', err);
}
}
newUnicorn()
의이 async
변형은 Promise
를 반환하지만 실제로는 여러 개의 키워드를 await
. 각자 Promise
되 Promise
, 그래서 우리는 사슬이 아닌 약속의 모음을 가지고있었습니다.
사실 우리는 그것을 생각할 수있는 function*
각으로, 발전기 await
있는 Being yield new Promise
. 그러나 다음 약속을 지키기 위해서는 각 약속의 결과가 필요합니다. 이것은 자바 스크립트가이 반복에 대한 관찰자를 자동으로 생성하도록 알려주기 때문에 함수에 추가 키워드 async
가 필요하기 때문입니다 (약속을 호출 할 때 await
키워드가 필요합니다). async function newUnicorn()
의해 반환 된 Promise
는이 반복이 완료되면 해결됩니다.
실제로, 당신은 그것을 고려할 필요가 없습니다; await
약속을 숨기고 async
발전기 반복을 숨 깁니다.
async
함수를 약속처럼 호출하고 약속 또는 async
함수를 await
수 await
. .then()
없이 약속을 실행할 수있는 것처럼 비동기 함수를 await
필요가 없습니다.
해당 코드를 즉시 실행하려면 async
IIFE를 사용할 수도 있습니다.
(async () => {
await makeCoffee()
console.log('coffee is ready!')
})()
비동기 루프가 기다리고 있습니다.
async in loops를 사용할 때 이러한 문제가 발생할 수 있습니다.
forEach
내부에서 기다리려고하면 Unexpected token
오류가 발생합니다.
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(e => {
const i = await somePromiseFn(e);
console.log(i);
});
})();
이것은 실수로 화살표 기능을 블록으로 보았 기 때문입니다. await
는 async
가 아닌 콜백 함수의 컨텍스트에서 수행됩니다.
인터프리터는 위의 오류를 방지하지만 forEach
콜백에 async
를 추가하면 오류가 발생하지 않습니다. 문제가 해결되었다고 생각할 수도 있지만 예상대로 작동하지 않습니다.
예:
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(async(e) => {
const i = await somePromiseFn(e);
console.log(i);
});
console.log('this will print first');
})();
콜백 비동기 함수는 부모 비동기 함수가 아니라 자체를 일시 중지 할 수 있기 때문에 발생합니다.
약속을 반환하는 asyncForEach 함수를 작성하면 asyncForEach
await asyncForEach(async (e) => await somePromiseFn(e), data )
와 같은 것이 될 수await asyncForEach(async (e) => await somePromiseFn(e), data )
기본적으로 모든 콜백이 기다리고 완료 될 때 해결되는 약속을 반환합니다. 그러나 이것을 수행하는 더 좋은 방법이 있으며, 그것은 단지 루프를 사용하는 것입니다.
for-of
루프 또는 for/while
루프 for/while
사용할 수 있습니다. 어떤 루프를 선택하든 상관 없습니다.
(async() => {
data = [1, 2, 3, 4, 5];
for (let e of data) {
const i = await somePromiseFn(e);
console.log(i);
}
console.log('this will print last');
})();
그러나 또 다른 포획이있다. 이 솔루션은 somePromiseFn
에 대한 각 호출이 완료 될 때까지 기다렸다가 다음 호출을 반복합니다.
somePromiseFn
호출을 순서대로 실행하려면이 기능이 유용하지만 동시에 실행하려면 Promise.all
을 await
합니다.
(async() => {
data = [1, 2, 3, 4, 5];
const p = await Promise.all(data.map(async(e) => await somePromiseFn(e)));
console.log(...p);
})();
Promise.all
은 유일한 매개 변수로 약속 배열을 받고 약속을 반환합니다. 배열의 모든 약속이 해결되면 반환 된 약속도 해결됩니다. 우리는 그 약속을 await
있으며, 해결 될 때 우리의 모든 가치가 유효합니다.
위의 예제는 완전히 실행 가능합니다. somePromiseFn
함수는 시간 초과가있는 비동기 반향 함수로 만들 수 있습니다. 적어도 stage-3
사전 설정으로 babel-repl 의 예제를 시험해보고 출력을 살펴볼 수 있습니다.
function somePromiseFn(n) {
return new Promise((res, rej) => {
setTimeout(() => res(n), 250);
});
}
동시 비동기 (병렬) 작업
종종 비동기 작업을 병렬로 수행하고자 할 것입니다. async
/ await
제안서에서 이것을 지원하는 직접 구문이 있지만 약속을 await
있기 때문에 Promise.all
에서 여러 약속을 묶어서 기다릴 수 있습니다.
// Not in parallel
async function getFriendPosts(user) {
friendIds = await db.get("friends", {user}, {id: 1});
friendPosts = [];
for (let id in friendIds) {
friendPosts = friendPosts.concat( await db.get("posts", {user: id}) );
}
// etc.
}
각 친구의 게시물을 순차적으로 가져 오기 위해 각 쿼리를 수행하지만 동시에 완료 할 수 있습니다.
// In parallel
async function getFriendPosts(user) {
friendIds = await.db.get("friends", {user}, {id: 1});
friendPosts = await Promise.all( friendIds.map(id =>
db.get("posts", {user: id})
);
// etc.
}
이것은 일련의 약속을 만들기 위해 ID 목록을 반복합니다. 모든 약속이 끝날 때까지 await
것입니다. Promise.all
은 이들을 하나의 약속으로 결합하지만 동시에 수행됩니다.