async/await 隐式返回Promise?

IT技术 javascript node.js async-await ecmascript-next
2021-02-06 06:20:23

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

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

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

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

那么具体是怎么回事呢?由 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函数中显式返回一个非Promise值时,它会强制将其包装在一个Promise中。我对它没有什么大问题,但它确实无视普通的 JS。

5个回答

返回值将始终是一个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));

即使没有回报也一样!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));

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

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

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

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

// Logs 'test'.
console.log(foo().next().value);
仅返回自动创建的Promise而不是自己明确创建它被认为是不好的做法吗?不知何故,在许多情况下,我喜欢干净的方法。
2021-04-04 06:20:23
不,我不认为依赖自动创建的Promise是不好的做法。我认为异步函数的预期结果是允许您通过管道传输到其他返回Promise的函数,而不必在代码中出现“Promise”。例如 function async myFunc() { const val1 = await otherAsyncFunc1(); const val2 = 等待 otherAsyncFunc1(); 返回值 1 + 值 2;} function async main() { const result = await myFunc(): console.log("The result is " + result"); }
2021-04-06 06:20:23
静态方法Promise.resolve“你返回的值会自动包装在一个promise中”,即如果异步函数的return语句是-return x;它隐含地变成 - return Promise.resolve(x);
2021-04-08 06:20:23

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

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

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); });
    });
}
这个答案主要是对规范的参考,经过审查,我认为没有任何混淆。确实,异步函数会返回Promise,但为了做到这一点,它们对产生Promise的生成器进行了脱糖。
2021-03-27 06:20:23
“简短的版本是一个异步函数对生成 Promise 的生成器进行脱糖。” 我想你可能会产生混淆async functionasync function*前者只是返回一个Promise。后者返回一个产生Promise的生成器。
2021-04-05 06:20:23

你的问题是:如果我创建一个async函数,它是否应该返回一个Promise?回答:做任何你想做的事,Javascript 会为你修复它。

假设doSomethingAsync是一个返回Promise的函数。然后

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

完全一样

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

你可能在想“ WTF,这些怎么可能一样? ”你是对的。async神奇地包裹并Promise值,如果必要的

更奇怪的是,doSomethingAsync可以写成有时返回Promise,有时返回Promise。仍然两个功能完全相同,因为await也是magic如有必要,它会解开一个 Promise 但它不会影响非 Promise 的东西。

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

var ret = await  getVal();
console.log(ret);
await 仅在异步函数中有效
2021-04-09 06:20:23

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);
    });
  });
}
@bergi,实际上,它是一个增强的生成器功能。一个生成器函数,它总是返回一个 promise .. 或其他东西。
2021-03-11 06:20:23
async 是一个增强的生成器功能” - 不,它真的不是。
2021-03-21 06:20:23
如上所述 - “异步函数”确实会返回一个 Promise。至少从概念上讲,'async' 语句的要点是将该函数的返回值包装在一个 Promise 中。您甚至可以在返回 Promise 的普通旧函数上“等待”,并且一切正常,因为 'async function' === 'function returns Promise'。
2021-04-07 06:20:23