提问者:小点点

Async/Await隐式返回promise?


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

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

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

假设返回一个promise,并且await关键字将返回promise中的值,而不是promise itsef,那么我的getVal函数应该返回该值,而不是隐式的promise。

那么到底是什么情况呢?由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

在我的概要中,该行为确实与传统的返回语句不一致。当您从函数显式返回一个非promise值时,它会强制将其包装在promise中。我对它没有太大的问题,但它确实违抗了正常的JS。


共3个答案

匿名用户

返回值永远是一个承诺。如果您没有显式地返回一个承诺,那么您返回的值将自动包装在一个承诺中。

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

即使没有回报也一样!(返回CodePromise{undefined/code>)

async function increment(num) {}

即使有,也是一样。

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

承诺自动解包,因此如果您确实从函数中返回一个值的承诺,您将收到一个值的承诺(而不是一个对值的承诺的承诺)。

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的函数返回的值与不完全相同。这些函数称为生成器。

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

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

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

匿名用户

我看了一下规范,发现了以下信息。简短的版本是向生成器解糖,生成器生成

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

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

除糖至:

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

其中“是对以下算法的调用”:

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

匿名用户

您的问题是:如果我创建一个函数,它是否应该返回一个承诺?答:只要做你想做的任何事情,Javascript就会为你修复它。

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

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

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

你可能在想:“怎么会这样呢?”而且你是对的。如果需要,将神奇地用一个Promise包装一个值。

更奇怪的是,可以被编写为有时返回承诺,有时不返回承诺。但是这两个函数完全相同,因为也是魔术。如果有必要,它会拆开一个承诺,但它不会对那些不是承诺的东西产生任何影响。