ChatGPT解决这个技术问题 Extra ChatGPT

async/await 隐式返回承诺?

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

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

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

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

那么究竟是什么情况呢?由 async 关键字标记的函数是隐式返回承诺还是我们控制它们返回的内容?

也许如果我们没有明确地返回一些东西,那么他们就会隐含地返回一个承诺......?

更清楚地说,上面和上面有区别

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

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

console.log 显示什么?
它是 promise resolve 函数传递的值,而不是 promise 本身
或许 await 会解开 promise 的结果。
JavaScript 的承诺试图模仿 c# 的异步等待行为。然而,历史上有很多结构可以用 c# 来支持它,而在 JavaScript 中则没有。因此,虽然在许多用例中它可能看起来非常相似,但它有点用词不当。
是的,这是正确的,只是有点令人困惑,因为它是隐含的……也就是说,即使没有 return 语句,它仍然会返回一个 promise……看到了吗?

m
mPrinC

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

静态方法 Promise.resolve 的“你返回的值将自动包装在一个 Promise 中”,即如果异步函数的返回语句是 - return x;它隐式变为 - return Promise.resolve(x);
只返回自动创建的承诺而不是自己显式创建它被认为是不好的做法吗?不知何故,在许多情况下,我喜欢干净的方法。
不,我不认为依赖自动创建的承诺是不好的做法。我认为异步函数的预期结果是允许您通过管道传递到其他返回承诺的函数,而不必在代码中出现“承诺”。例如 function async myFunc() { const val1 = await otherAsyncFunc1(); const val2 = 等待 otherAsyncFunc1();返回 val1 + val 2; } function async main() { const result = await myFunc(): console.log("The result is " + result"); }
J
Jon Surrell

我查看了规范并找到了以下信息。简短的版本是 async function 对生成 Promise 的生成器进行脱糖。所以,是的,异步函数返回承诺

根据 tc39 spec,以下情况属实:

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

“简短的版本是异步函数对生成 Promises 的生成器进行去糖。” 我认为您可能会将 async functionasync function* 混淆。前者只是返回一个承诺。后者返回一个产生承诺的生成器。
这个答案主要是对规范的参考,经过审查,我认为没有任何混淆。确实,异步函数返回 Promise,但为了做到这一点,它们对产生 Promise 的生成器脱糖。
J
John Henckel

您的问题是:如果我创建一个 async 函数,它是否应该返回一个承诺? 答案:随心所欲,Javascript 会为您解决问题。

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

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

完全一样

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

你可能在想“WTF,这些怎么可能是一样的?”,你是对的。 async神奇地用 Promise 必要时包装一个值。

更奇怪的是,doSomethingAsync 可以写成 sometimes 返回一个 Promise,有时 NOT 返回一个 Promise。这两个函数仍然完全相同,因为 await 也是 magic如有必要,它将打开一个 Promise,但它不会对不是 Promise 的东西产生影响。


m
mohsen gharivand

当你调用它时,只需在你的函数之前添加等待:

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

await 仅在 async 函数中有效
a
akc42

async 不返回承诺,await 关键字等待承诺的解决。 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.execSqlyield 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);
    });
  });
}

“异步是增强的生成器功能” - 不,它确实不是。
如上所述——“异步函数”确实返回了一个 Promise。至少从概念上讲,'async' 语句的要点是将函数的返回值包装在一个 Promise 中。您甚至可以在返回 Promise 的普通旧函数上“等待”,并且一切正常,因为 'async function' === 'function returned Promise'。
@bergi,实际上,它是一个增强的生成器功能。一个生成器函数,它总是返回一个 promise .. 或其他东西。