异步函数隐式返回promise?

问题描述 投票:0回答:5

我读到由

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

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

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

但这并不连贯...假设

doSomethingAsync()
返回一个 Promise,并且 wait 关键字将返回 Promise 中的值,而不是 Promise 本身,那么我的 getVal 函数 should 返回该值,而不是隐式 Promise。

那么到底是什么情况呢?由 async 关键字标记的函数是否隐式返回 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。

javascript node.js async-await ecmascript-next
5个回答
239
投票

返回值永远是一个承诺。如果您没有显式返回 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));

即使没有回报也是一样! (

Promise { undefined }
已返回)

async function increment(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));

Promise 自动解包,因此,如果您确实从

async
函数中返回某个值的 Promise,您将收到该值的 Promise(而不是该值的 Promise)。

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

在我的概要中,这种行为确实与传统的不一致 返回语句。看来当你明确返回一个 来自异步函数的非承诺值,它将强制将其包装在 承诺。我没有什么大问题,但它确实违背了正常 JS.

ES6 的函数返回的值与

return
不完全相同。这些函数称为生成器。

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

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

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

39
投票

是的,异步函数总是会返回一个promise。

根据tc39规范

async function
脱糖到生成器,产生
Promise
s。

具体:

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

脱糖至:

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

27
投票

你的问题是:如果我创建一个

async
函数,它是否应该返回一个promise? 答案:只要做你想做的事,Javascript就会为你解决它。

假设

doSomethingAsync
是一个返回promise的函数。然后

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

完全相同
async function getVal(){
    return doSomethingAsync();
}

您可能在想“WTF,这些怎么会一样?”,您是对的。

async
神奇地用 Promise 包装一个值如果需要的话

更奇怪的是,

doSomethingAsync
可以写成有时返回承诺,有时返回承诺。但两个功能仍然完全相同,因为
await
也是 magic。它会解开 Promise 如果需要的话,但它不会对非 Promise 的东西产生影响。


-4
投票

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

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

-10
投票

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);
    });
  });
}
© www.soinside.com 2019 - 2024. All rights reserved.