최상위 레벨에서 async / await를 어떻게 사용합니까?


182

나는 이상 진행되고있다 async/ await여러 기사를 통해 진행 한 후, 나는 나 자신을 시험 일에 결정했다. 그러나 왜 이것이 효과가 없는지 머리를 감쌀 수없는 것 같습니다.

async function main() {  
    var value = await Promise.resolve('Hey there');
    console.log('inside: ' + value);
    return value;
}

var text = main();  
console.log('outside: ' + text);

콘솔은 다음을 출력합니다 (노드 v8.6.0).

> 외부 : [개체 약속]

> 내부 : 이봐

함수 내부의 로그 메시지가 나중에 실행되는 이유는 무엇입니까? async/ await생성 된 이유 는 비동기 작업을 사용하여 동기 실행을 수행하기위한 것이라고 생각했습니다 .

.then()after 를 사용하지 않고 함수 내에서 반환 된 값을 사용할 수있는 방법이 main()있습니까?


4
아니요, 타임머신 만이 비동기 코드를 동기식으로 만들 수 있습니다. await약속 then구문의 설탕 일뿐입니다.
Bergi

main은 왜 값을 반환합니까? 필요한 경우 진입 점이 아니고 다른 함수 (예 : 비동기 IIFE)로 호출해야합니다.
Estus Flask

@estus 프로그램을 대표 할 필요는 없지만 노드에서 테스트하는 동안 빠른 함수 이름이었습니다.main
Felipe

2
참고로 async/awaitES7이 아닌 ES2017의 일부입니다 (ES2016)
Felix Kling 17 년

답변:


267

왜 이것이 효과가 없는지 머리를 감쌀 수 없습니다.

main약속을 돌려주기 때문에 ; 모든 async기능을 수행합니다.

최상위 레벨에서 다음 중 하나를 수행해야합니다.

  1. async"처리되지 않은 거부"오류를 원하지 않는 한 거부하지 않는 최상위 함수를 사용 하거나

  2. 사용 thencatch, 또는

  3. (출시 예정!) 를 사용하여 최고 수준await 의에서 3 단계에 도달 한 제안 과정 의 최상위 사용할 수 있습니다 await모듈에 있습니다.

# 1- async거부하지 않는 최상위 기능

(async () => {
    try {
        var text = await main();
        console.log(text);
    } catch (e) {
        // Deal with the fact the chain failed
    }
})();

를 주목 catch; 당신은 있어야합니다 에 가고 아무것도 때문에, 약속의 거부 / 비동기 예외를 처리; 당신은 그들에게 전달할 발신자가 없습니다. 원하는 catch경우 try/ catch구문 대신 함수 를 통해 호출 한 결과에서 그렇게 할 수 있습니다 .

(async () => {
    var text = await main();
    console.log(text);
})().catch(e => {
    // Deal with the fact the chain failed
});

... 그것은 조금 더 간결합니다 (그 이유 때문에 그것을 좋아합니다).

또는 물론 오류를 처리하지 않고 "처리되지 않은 거부"오류 만 허용하십시오.

# 2- then그리고catch

main()
    .then(text => {
        console.log(text);
    })
    .catch(err => {
        // Deal with the fact the chain failed
    });

catch오류가 체인 또는에서 발생하는 경우 처리기가 호출됩니다 then핸들러입니다. ( catch처리기가 아무것도 처리하도록 등록되어 있지 않으므로 처리기가 오류를 발생시키지 않아야합니다.)

또는 두 가지 주장 모두 then:

main().then(
    text => {
        console.log(text);
    },
    err => {
        // Deal with the fact the chain failed
    }
);

다시 거부 핸들러를 등록하고 있음을 다시 한 번 확인하십시오. 그러나이 형식에서는 then어떤 콜백도 오류를 발생시키지 않으며 오류를 처리하기 위해 등록 된 것이 없습니다.

await모듈에서 3 위

await비 모듈 스크립트의 최상위 수준 에서는 사용할 수 없지만 최상위 await제안 ( 3 단계 )을 사용하면 모듈의 최상위 수준에서 사용할 수 있습니다. async처리되지 않은 거부 오류가 발생하기 때문에 최상위 코드에서 거부 (오류 발생)를 원하지 않는다는 점에서 최상위 함수 래퍼 (위의 # 1) 를 사용하는 것과 비슷합니다 . 따라서 # 1과 같이 문제가 발생했을 때 처리되지 않은 거부를 원치 않는 한 오류 처리기에 코드를 래핑하고 싶습니다.

// In a module, once the top-level `await` proposal lands
try {
    var text = await main();
    console.log(text);
} catch (e) {
    // Deal with the fact the chain failed
}

이 작업을 수행하면 모듈에서 가져 오는 모든 모듈이 약속 await이 확정 될 때까지 기다립니다 . 최상위 레벨을 사용하는 모듈 await이 평가되면 기본적으로 모듈 로더에 약속을 반환합니다 ( async함수 처럼 ).이 약속은 모듈에 의존하는 모든 모듈의 본문을 평가하기 전에 해당 약속이 완료 될 때까지 기다립니다.


그것을 약속으로 생각하면 함수가 즉시 반환되는 이유를 설명합니다. 나는 최상위 익명 비동기 함수를 만드는 실험을했고 지금 이해가되는 결과를 얻습니다
Felipe

2
@Felipe : 예, async/ await문법 약속 주위 설탕 (설탕의 좋은 종류 :-))이 있습니다. 단지 약속을 돌려주는 것으로 생각 하는 것이 아닙니다 . 실제로 그렇습니다. ( 세부 사항 .)
TJ 크라우

1
@LukeMcGregor-위의 모든 async옵션을 먼저 보여주었습니다 . 최상위 기능의 경우 어느 쪽이든 볼 수 있습니다 (주로 async버전 의 두 가지 들여 쓰기 수준으로 인해 ).
TJ Crowder 2018

3
@Felipe-최상위 await제안서가 3 단계에 도달 했으므로 답변을 업데이트 했습니다. :-)
TJ Crowder

1
@SurajShrestha-아니요. 그러나 문제가되지는 않습니다. :-)
TJ Crowder

7

최상위 레벨await 이 3 단계로 이동 했으므로 질문에 대한 답변 최상위 레벨에서 async / await를 어떻게 사용합니까? await에 전화를 추가 하는 것입니다 main().

async function main() {  
    var value = await Promise.resolve('Hey there');
    console.log('inside: ' + value);
    return value;
}

var text = await main();  
console.log('outside: ' + text)

아니면 그냥 :

const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)

여전히 Webpack@v5.0.0-alpha.15 에서만 사용할 수 있습니다 .

당신이 경우 타이프 라이터를 사용하여 , 그것은 3.8에 도착했다 .

v8은 모듈에서 지원추가 했습니다.

Deno 도 지원합니다 (곤잘로 바하 몬데 즈의 논평).


정말 멋진. 노드 구현을위한 로드맵이
Felipe

모릅니다. 그러나 곧 TypeScript 및 Babel 구현을 보게 될 것입니다. TypeScript 팀에는 3 단계 언어 기능을 구현하는 정책이 있으며 Babel 플러그인은 일반적으로 제안을 테스트하기위한 TC39 프로세스의 일부로 빌드됩니다. github.com/Microsoft/TypeScript/issues/…
Taro

그것은 너무 deno에서 사용할 수 (단지 JS는, 타이프 라이터는 아직 지원하지 않습니다 github.com/microsoft/TypeScript/issues/25988 ) deno.land 참조 deno.news/issues/... .
Gonzalo Bahamondez

SyntaxError : await는 비동기 함수에서만 유효합니다
Sudipta Dhara

4

이 문제에 대한 실제 해결책은 다르게 접근하는 것입니다.

아마도 목표는 일반적으로 응용 프로그램의 최상위 수준에서 발생하는 일종의 초기화입니다.

해결책은 응용 프로그램의 최상위 레벨에 단 하나의 JavaScript 명령문 만 있도록하는 것입니다. 응용 프로그램 상단에 하나의 문장 만있는 경우 다른 곳에서 비동기 / 대기를 자유롭게 사용할 수 있습니다 (물론 일반 구문 규칙에 따라 다름)

달리 말하면 전체 최상위 레벨을 함수로 감싸서 더 이상 최상위 레벨이 아니며 애플리케이션의 최상위 레벨에서 비동기 / 대기 실행 방법에 대한 질문을 해결합니다.

응용 프로그램의 최상위 수준은 다음과 같습니다.

import {application} from './server'

application();

1
내 목표는 초기화라는 것이 맞습니다. 데이터베이스 연결, 데이터 가져 오기 등과 같은 사항. 경우에 따라 나머지 응용 프로그램을 진행하기 전에 사용자의 데이터를 가져와야했습니다. 본질적으로 당신은 application()비동기식을 제안하고 있습니까?
Felipe

1
아니요, 응용 프로그램의 루트에 JavaScript 문이 하나만 있으면 문제가 사라집니다. 표시 된 최상위 문은 비동기가 아닙니다. 문제는 최상위 수준에서 비동기를 사용할 수 없다는 것입니다. 실제로 해당 수준에서 기다리기를 기다릴 수 없으므로 최상위 수준에 문이 하나만 있으면 해당 문제를 회피했습니다. 가져온 비동기 코드에서 초기화 비동기 코드가 다운되었으므로 비동기가 제대로 작동하므로 애플리케이션 시작시 모든 것을 초기화 할 수 있습니다.
Duke Dougal

1
수정-응용 프로그램은 비동기 기능입니다.
Duke Dougal

4
죄송하지만 명확하지 않습니다. 요점은 일반적으로 최상위 레벨에서 비동기 함수가 기다리지 않는다는 것입니다. JavaScript는 다음 명령문으로 바로 넘어가므로 초기화 코드가 완료되었다고 확신 할 수 없습니다. 응용 프로그램 상단에 단 하나의 진술 만 있으면 문제가되지 않습니다.
Duke Dougal

3

현재 답변 위에 추가 정보를 제공하려면 다음을 수행하십시오.

node.js파일 의 내용 은 현재 문자열과 같은 방식으로 연결되어 함수 본문을 형성합니다.

예를 들어 파일이있는 경우 test.js:

// Amazing test file!
console.log('Test!');

그런 다음 node.js다음과 같은 기능을 비밀리에 연결합니다.

function(require, __dirname, ... a bunch more top-level properties) {
  // Amazing test file!
  console.log('test!');
}

주목할 점은 결과 함수가 비동기 함수가 아니라는 것입니다. 따라서 그 용어를 await직접 사용할 수 없습니다 !

그러나이 파일에서 약속으로 작업해야한다고 가정하면 두 가지 방법이 있습니다.

  1. 함수 내에서 await 직접 사용하지 마십시오
  2. 사용하지 마십시오 await

옵션 1을 사용하려면 새 범위를 만들어야합니다 (이 범위를 async제어 할 수 있으므로이 범위는 가능할 수 있음 ).

// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
  await new Promise(...);
  console.log('Test!');
})();

옵션 2에서는 객체 지향의 promise API (약속이 있지만 기능을 수행하는 기능 패러다임)를 사용해야합니다.

// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);

// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));

개인적으로 node.js가 기본적으로 코드가 async함수 로 연결되기를 바랍니다 . 그것은이 두통을 제거 할 것입니다.


0

최상위 대기는 곧 나오는 EcmaScript 표준의 기능입니다. 현재 TypeScript 3.8 (현재 RC 버전)에서 사용할 수 있습니다.

TypeScript 3.8 설치 방법

다음 명령을 사용하여 npm에서 TypeScript 3.8을 설치 하여 TypeScript 3.8을 사용할 수 있습니다 .

$ npm install typescript@rc

이때 rc최신 typescript 3.8 버전을 설치하려면 태그를 추가해야합니다 .


하지만 어떻게 사용하는지 설명해야합니까?
raarts

-2

main()비동기 적으로 실행 되므로 약속을 반환합니다. then()방법으로 결과를 얻어야합니다 . then()반품 약속도 있기 때문에 process.exit()프로그램을 끝내 려면 전화 해야합니다.

main()
   .then(
      (text) => { console.log('outside: ' + text) },
      (err)  => { console.log(err) }
   )
   .then(() => { process.exit() } )

2
잘못된. 모든 약속이 수락되거나 거부되고 기본 스레드에서 더 이상 코드가 실행되지 않으면 프로세스가 자체적으로 종료됩니다.

@Dev : 일반적으로 다른 값을 전달 exit()하여 오류가 발생했는지 여부 를 알립니다 .
9000

@ 9000 네,하지만 여기서는 끝나지 않습니다. 종료 코드 0이 기본값이므로 포함 할 필요가 없습니다.

9000 @ 사실, 오류 핸들러는 아마도 사용되어야합니다process.exit(1)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.