为了账号安全,请及时绑定邮箱和手机立即绑定

异步/等待隐式返回诺言?

/ 猿问

异步/等待隐式返回诺言?

波斯汪 2019-10-16 14:32:40

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


async function getVal(){

 return await doSomethingAync();

}


var ret = getVal();

console.log(ret);

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


那到底是什么情况?用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函数显式返回非承诺值时,它将强制将其包装在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));

即使有,也是一样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函数中返回了对某个值的承诺,您将收到该值的承诺(而不是该值的承诺)。


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中。我没有什么大问题,但是它确实违背了普通的JS。


ES6的函数返回的值与并不完全相同return。这些功能称为生成器。


function* foo() {

  return 'test';

}


// Logs an object.

console.log(foo());


// Logs 'test'.

console.log(foo().next().value);


查看完整回答
反对 回复 2019-10-16
?
月关宝盒

我看了一看规格,发现以下信息。简短的版本是async function产生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); });

    });

}


查看完整回答
反对 回复 2019-10-16
?
慕的地8271018

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

    });

  });

}


查看完整回答
反对 回复 2019-10-16

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信