수색…


소개

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 . 각자 PromisePromise , 그래서 우리는 사슬이 아닌 약속의 모음을 가지고있었습니다.

사실 우리는 그것을 생각할 수있는 function* 각으로, 발전기 await 있는 Being yield new Promise . 그러나 다음 약속을 지키기 위해서는 각 약속의 결과가 필요합니다. 이것은 자바 스크립트가이 반복에 대한 관찰자를 자동으로 생성하도록 알려주기 때문에 함수에 추가 키워드 async 가 필요하기 때문입니다 (약속을 호출 할 때 await 키워드가 필요합니다). async function newUnicorn() 의해 반환 된 Promise 는이 반복이 완료되면 해결됩니다.

실제로, 당신은 그것을 고려할 필요가 없습니다; await 약속을 숨기고 async 발전기 반복을 숨 깁니다.

async 함수를 약속처럼 호출하고 약속 또는 async 함수를 awaitawait . .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);
 });
})();

이것은 실수로 화살표 기능을 블록으로 보았 기 때문입니다. awaitasync 가 아닌 콜백 함수의 컨텍스트에서 수행됩니다.
인터프리터는 위의 오류를 방지하지만 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.allawait 합니다.

(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 은 이들을 하나의 약속으로 결합하지만 동시에 수행됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow