javascript node.js async-await ecmascript-next

javascript - async/wait implícitamente devuelve promesa?



node.js async-await (3)

Leí que las funciones asíncronas marcadas por la palabra clave async implícitamente devuelven una promesa:

async function getVal(){ return await doSomethingAync(); } var ret = getVal(); console.log(ret);

pero eso no es coherente ... suponiendo que doSomethingAsync() devuelve una promesa, y la palabra clave wait devolverá el valor de la promesa, no la promesa en sí misma, entonces mi función getVal debería devolver ese valor, no una promesa implícita.

Entonces, ¿cuál es exactamente el caso? ¿Las funciones marcadas por la palabra clave asíncrona devuelven implícitamente promesas o controlamos lo que devuelven?

¿Quizás si no devolvemos algo explícitamente, entonces implícitamente devuelven una promesa ...?

Para ser más claro, hay una diferencia entre lo anterior y

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

En mi sinopsis, el comportamiento es de hecho inconsistente con las declaraciones de retorno tradicionales. Parece que cuando devuelve explícitamente un valor no prometido de una función async , forzará a envolverlo en una promesa. No tengo un gran problema con él, pero desafía el JS normal.


Eché un vistazo a las especificaciones y encontré la siguiente información. La versión corta es que una async function desugará a un generador que produce Promise s. Entonces, sí, las funciones asíncronas devuelven promesas .

De acuerdo con la especificación tc39 , lo siguiente es cierto:

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

Desugar a:

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

Donde spawn "es una llamada al siguiente algoritmo":

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


El valor de retorno siempre será una promesa. Si no devuelve una promesa explícitamente, el valor que devuelva se incluirá automáticamente en una promesa.

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

Lo mismo, incluso si hay una 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));

Promesas de desempaquetado automático, por lo que si devuelve una promesa por un valor desde una función async , recibirá una promesa por el valor (no una promesa por una promesa por el valor).

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

En mi sinopsis, el comportamiento es de hecho inconsistente con las declaraciones de retorno tradicionales. Parece que cuando devuelve explícitamente un valor no prometido de una función asíncrona, forzará a envolverlo en una promesa. No tengo un gran problema con él, pero desafía el JS normal.

ES6 tiene funciones que no devuelven exactamente el mismo valor que el return . Estas funciones se llaman generadores.

function* foo() { return ''test''; } // Logs an object. console.log(foo()); // Logs ''test''. console.log(foo().next().value);


async no devuelve la promesa, la palabra clave esperar aguarda la resolución de la promesa. async es una función de generador mejorada y espera funciona un poco como el rendimiento

Creo que la sintaxis (no estoy 100% seguro) es

async function* getVal() {...}

Las funciones del generador ES2016 funcionan un poco así. He hecho un manejador de base de datos basado en tedioso que programa como este

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

Observe cómo lo programo como síncrono normal, particularmente en

yield connection.execSql y en yield connection.callProcedure

La función db.exec es un generador bastante típico basado en 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); }); }); }