Javascript async/await 隐式返回承诺?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35302431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:33:09  来源:igfitidea点击:

async/await implicitly returns promise?

javascriptnode.jsasync-awaitecmascript-next

提问by Alexander Mills

I read that async functions marked by the asynckeyword implicitly return a promise:

我读到由async关键字标记的异步函数隐式返回一个承诺:

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

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

but that is not coherent...assuming doSomethingAsync()returns a promise, and the await keyword will return the value from the promise, not the promise itsef, then my getVal function shouldreturn that value, not an implicit promise.

但这并不连贯......假设doSomethingAsync()返回一个承诺,并且 await 关键字将从承诺中返回值,而不是承诺本身,那么我的 getVal 函数应该返回该值,而不是隐含的承诺。

So what exactly is the case? Do functions marked by the async keyword implicitly return promises or do we control what they return?

那么究竟是怎么回事呢?由 async 关键字标记的函数是隐式返回 promise 还是我们控制它们返回的内容?

Perhaps if we don't explicitly return something, then they implicitly return a promise...?

也许如果我们不明确返回某些东西,那么它们会隐含地返回一个承诺......?

To be more clear, there is a difference between the above and

为了更清楚,上面和

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

In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an asyncfunction, it will force wrap it in a promise. I don't have a big problem with it, but it does defy normal JS.

在我的概要中,这种行为确实与传统的 return 语句不一致。似乎当您从async函数中显式返回一个非承诺值时,它会强制将它包装在一个承诺中。我对它没有什么大问题,但它确实无视普通的 JS。

回答by Nathan Wall

The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.

返回值将始终是一个承诺。如果你没有明确返回一个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));

Same thing even if there's an await.

即使有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, so if you do return a promise for a value from within an asyncfunction, you will receive a promise for the value (not a promise for a promise for the value).

Promise 会自动解包,因此如果您确实从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));


In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise. I don't have a big problem with it, but it does defy normal JS.

在我的概要中,这种行为确实与传统的 return 语句不一致。看来,当您从异步函数中显式返回一个非承诺值时,它会强制将其包装在承诺中。我对它没有什么大问题,但它确实无视普通的 JS。

ES6 has functions which don't return exactly the same value as the return. These functions are called generators.

ES6 的函数返回的值与return. 这些函数称为生成器。

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

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

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

回答by Jon Surrell

I took a look at the spec and found the following information. The short version is that an async functiondesugars to a generator which yields Promises. So, yes, async functions return promises.

我查看了规范并找到了以下信息。简短的版本是一个async functiondesugars 到一个产生Promises的生成器。所以,是的,异步函数返回 promises

According to the tc39 spec, the following is true:

根据tc39 规范,以下是正确的:

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

Desugars to:

脱糖:

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

Where spawn"is a call to the following algorithm":

其中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); });
    });
}

回答by mohsen gharivand

Just add await before your function when you call it :

调用函数时,只需在函数前添加 await :

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

回答by akc42

async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield

async 不返回承诺, await 关键字等待承诺的解决。async 是一个增强的生成器函数,await 有点像 yield

I think the syntax (I am not 100% sure) is

我认为语法(我不是 100% 确定)是

async function* getVal() {...}

async function* getVal() {...}

ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this

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}));
});

Notice how I just program it like normal synchronous particularly at

请注意我是如何像正常同步一样对其进行编程的,特别是在

yield connection.execSqland at yield connection.callProcedure

yield connection.execSql并在 yield connection.callProcedure

The db.exec function is a fairly typical Promise based generator

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);
    });
  });
}