async/await implicitly returns promise?

前端 未结 5 1982
离开以前
离开以前 2020-11-22 12:06

I read that async functions marked by the async keyword implicitly return a promise:

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


        
相关标签:
5条回答
  • 2020-11-22 12:27

    The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a 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));
    

    Same thing even if there's an 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));
    

    Promises auto-unwrap, so if you do return a promise for a value from within an async function, you will receive a promise for the value (not a promise for a promise for the value).

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

    In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise. I don't have a big problem with it, but it does defy normal JS.

    ES6 has functions which don't return exactly the same value as the return. These functions are called generators.

    function* foo() {
      return 'test';
    }
    
    // Logs an object.
    console.log(foo());
    
    // Logs 'test'.
    console.log(foo().next().value);
    
    0 讨论(0)
  • 2020-11-22 12:37

    Just add await before your function when you call it :

    var ret = await  getVal();
    console.log(ret);
    
    0 讨论(0)
  • 2020-11-22 12:37

    async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield

    I think the syntax (I am not 100% sure) is

    async function* getVal() {...}

    ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this

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

    Notice how I just program it like normal synchronous particularly at

    yield connection.execSql and at yield connection.callProcedure

    The db.exec function is a fairly typical Promise based generator

    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);
        });
      });
    }
    
    0 讨论(0)
  • 2020-11-22 12:46

    Your question is: If I create an async function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.

    Suppose doSomethingAsync is a function that returns a promise. Then

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

    is exactly the same as

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

    You probably are thinking "WTF, how can these be the same?" and you are right. The async will magically wrap a value with a Promise if necessary.

    Even stranger, the doSomethingAsync can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.

    0 讨论(0)
  • 2020-11-22 12:50

    I took a look at the spec and found the following information. The short version is that an async function desugars to a generator which yields Promises. So, yes, async functions return promises.

    According to the tc39 spec, the following is true:

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

    Desugars to:

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

    Where spawn "is a call to the following algorithm":

    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); });
        });
    }
    
    0 讨论(0)
提交回复
热议问题