async / await는 암시 적으로 promise를 반환합니까?


111

async키워드 로 표시된 비동기 함수가 암시 적으로 약속을 반환 한다는 것을 읽었습니다 .

async function getVal(){
 return await doSomethingAync();
}

var ret = getVal();
console.log(ret);

그러나 그것은 일관 적이 지 않습니다 ... doSomethingAsync()약속을 반환하고 await 키워드가 promise itsef가 아닌 promise에서 값을 반환 한다고 가정하면 getVal 함수 암시 적 약속이 아닌 해당 값을 반환해야합니다.

그렇다면 정확히 어떤 경우입니까? async 키워드로 표시된 함수는 암시 적으로 promise를 반환합니까? 아니면 반환하는 것을 제어합니까?

아마도 우리가 명시 적으로 무언가를 반환하지 않으면 암시 적으로 promise를 반환합니다 ...?

더 명확하게 말하면 위와

function doSomethingAync(charlie) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(charlie || 'yikes');
        }, 100);
    })
}

async function getVal(){
   var val = await doSomethingAync();  // val is not a promise
   console.log(val); // logs 'yikes' or whatever
   return val;  // but this returns a promise
}

var ret = getVal();
console.log(ret);  //logs a promise

내 시놉시스에서 동작은 실제로 전통적인 return 문과 일치하지 않습니다. async함수 에서 약속이 아닌 값을 명시 적으로 반환하면 약속에 강제로 래핑하는 것처럼 보입니다 . 나는 그것에 큰 문제가 없지만 정상적인 JS를 무시합니다.


1
무엇을 console.log보여 주나요?
Barmar

그것은 약속 해결 기능에 의해 전달 된 값의 아닌 자체를 약속
알렉산더 밀스

아마도 기다림은 약속의 결과를 풉니 다.
Hamlet Hakobyan

사실, 제가 틀렸어요. 약속을 기록했습니다
Alexander Mills

2
JavaScript의 약속은 C #의 비동기 대기 동작을 모방하려고합니다. 그러나 역사적으로 C #에서는이를 지원하기위한 많은 구조가 있었고 JavaScript에서는 지원하지 않았습니다. 따라서 많은 사용 사례에서 매우 유사 해 보일 수 있지만 다소 잘못된 이름입니다.
Travis J

답변:


138

반환 값은 항상 약속입니다. 명시 적으로 promise를 반환하지 않으면 반환하는 값이 자동으로 promise에 래핑됩니다.

async function increment(num) {
  return num + 1;
}

// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));

이 생길 경우에도 마찬가지입니다 await.

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function incrementTwice(num) {
  const numPlus1 = await defer(() => num + 1);
  return numPlus1 + 1;
}

// Logs: 5
incrementTwice(3).then(num => console.log(num));

Promises auto-unwrap, 따라서 async함수 내에서 값에 대한 약속을 반환하면 값에 대한 약속을 받게됩니다 (값에 대한 약속에 대한 약속이 아님).

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function increment(num) {
  // It doesn't matter whether you put an `await` here.
  return defer(() => num + 1);
}

// Logs: 4
increment(3).then(num => console.log(num));

내 시놉시스에서 동작은 실제로 전통적인 return 문과 일치하지 않습니다. 비동기 함수에서 약속이 아닌 값을 명시 적으로 반환하면 약속에 강제로 래핑합니다. 나는 그것에 큰 문제가 없지만 정상적인 JS를 무시합니다.

ES6에는 .NET Framework와 정확히 동일한 값을 반환하지 않는 함수가 있습니다 return. 이러한 함수를 생성기라고합니다.

function* foo() {
  return 'test';
}

// Logs an object.
console.log(foo());

// Logs 'test'.
console.log(foo().next().value);

3
정적 메소드 Promise.resolve에 의해 "반환하는 값은 자동으로 promise에 래핑됩니다."즉, 비동기 함수의 return 문이 다음과 같은 경우-return x; 암시 적으로 다음과 같이됩니다. return Promise.resolve (x);
adnan2nd

명시 적으로 직접 생성하는 대신 자동으로 생성 된 promise를 반환하는 것이 나쁜 습관으로 간주됩니까? 어쨌든 나는 많은 경우 깨끗한 접근 방식을 좋아합니다.
marlar

24

사양을보고 다음 정보를 찾았습니다. 짧은 버전은 s async function를 생성하는 발전기 로 desugars Promise입니다. 그래서, 예, 비동기 함수는 약속을 반환합니다 .

tc39 사양 에 따르면 다음 사항이 적용됩니다.

async function <name>?<argumentlist><body>

Desugars to :

function <name>?<argumentlist>{ return spawn(function*() <body>, this); }

어디 spawn"다음의 알고리즘에 대한 호출입니다"

function spawn(genF, self) {
    return new Promise(function(resolve, reject) {
        var gen = genF.call(self);
        function step(nextF) {
            var next;
            try {
                next = nextF();
            } catch(e) {
                // finished with failure, reject the promise
                reject(e);
                return;
            }
            if(next.done) {
                // finished with success, resolve the promise
                resolve(next.value);
                return;
            }
            // not finished, chain off the yielded promise and `step` again
            Promise.resolve(next.value).then(function(v) {
                step(function() { return gen.next(v); });
            }, function(e) {
                step(function() { return gen.throw(e); });
            });
        }
        step(function() { return gen.next(undefined); });
    });
}

"짧은 버전은 비동기 함수가 약속을 생성하는 생성기로 탈당한다는 것입니다." 난 당신이 혼동 될 수 있습니다 생각 async function으로 async function*. 전자는 단순히 약속을 반환합니다. 후자는 약속을 생성하는 생성기를 반환합니다.
cdhowie

이 답변은 주로 사양에 대한 참조이며 검토 후 혼란이 없다고 생각합니다. 사실, 비동기 함수는 promise를 반환하지만이를 수행하기 위해 promise를 생성하는 생성자에게 desugar합니다.
Jon Surrell


-3

async는 promise를 반환하지 않으며 await 키워드는 promise의 해결을 기다립니다. async는 향상된 생성기 함수이며 await는 yield와 비슷하게 작동합니다.

구문은 (100 % 확실하지 않습니다)

async function* getVal() {...}

ES2016 생성기 함수는 이와 비슷하게 작동합니다. 나는 당신이 이와 같이 프로그래밍하는 지루한 기반으로 데이터베이스 핸들러를 만들었습니다.

db.exec(function*(connection) {
  if (params.passwd1 === '') {
    let sql = 'UPDATE People SET UserName = @username WHERE ClinicianID = @clinicianid';
    let request = connection.request(sql);
    request.addParameter('username',db.TYPES.VarChar,params.username);
    request.addParameter('clinicianid',db.TYPES.Int,uid);
    yield connection.execSql();
  } else {
    if (!/^\S{4,}$/.test(params.passwd1)) {
      response.end(JSON.stringify(
        {status: false, passwd1: false,passwd2: true}
      ));
      return;
    }
    let request = connection.request('SetPassword');
    request.addParameter('userID',db.TYPES.Int,uid);
    request.addParameter('username',db.TYPES.NVarChar,params.username);
    request.addParameter('password',db.TYPES.VarChar,params.passwd1);
    yield connection.callProcedure();
  }
  response.end(JSON.stringify({status: true}));

}).catch(err => {
  logger('database',err.message);
  response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});

특히 일반적인 동기처럼 프로그래밍하는 방법에 주목하십시오.

yield connection.execSql 그리고 yield connection.callProcedure

db.exec 함수는 상당히 일반적인 Promise 기반 생성기입니다.

exec(generator) {
  var self = this;
  var it;
  return new Promise((accept,reject) => {
    var myConnection;
    var onResult = lastPromiseResult => {
      var obj = it.next(lastPromiseResult);
      if (!obj.done) {
        obj.value.then(onResult,reject);
      } else {
       if (myConnection) {
          myConnection.release();
        }
        accept(obj.value);
      }
    };
    self._connection().then(connection => {
      myConnection = connection;
      it = generator(connection); //This passes it into the generator
      onResult();  //starts the generator
    }).catch(error => {
      reject(error);
    });
  });
}

4
" 비동기는 향상된 생성기 기능입니다 "-아니요, 실제로는 그렇지 않습니다.
Bergi

위에서 언급했듯이- '비동기 함수'는 실제로 Promise를 반환합니다. 적어도 개념적으로 'async'문의 요점은 해당 함수의 반환 값을 promise에 래핑하는 것입니다. 'async function'=== 'function returning Promise'이기 때문에 Promise를 반환하는 평범한 이전 함수에서 '대기'할 수도 있습니다.
스펙터

2
@bergi는 실제로 향상된 생성기 함수입니다. 항상 promise .. 또는 무언가를 반환하는 생성기 함수.
Alexander Mills
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.