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

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

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


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

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

到底是什么案子?用异步关键字标记的函数是隐式返回承诺,还是由我们控制它们返回什么?

也许如果我们不明确地返回一些东西,那么他们就暗示地返回一个承诺... ?

更明确地说,上述两者之间有一个区别

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。

115145 次浏览

返回值将永远是一个承诺。如果不显式返回承诺,则返回的值将自动包装在承诺中。

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

承诺自动展开,所以如果返回 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));

在我的大纲中,这种行为确实与传统不一致 返回语句。当显式返回一个 非承诺值,它将强制将该值包装到 我保证,我对此没什么意见,但这确实有违常理 JS.

ES6中的函数返回的值与 return不完全一样,这些函数被称为生成器。

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


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


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

异步不返回承诺,等待关键字等待承诺的解决。异步是一个增强的生成器函数,等待工作有点像产量

我认为语法(我不是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

Exec 函数是一个相当典型的基于誓言的生成器

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

是的,异步函数总是返回承诺。

根据 Tc39规格,一个 async function脱糖到发电机产生 Promise

具体来说:

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

在调用函数时,只需在函数之前添加 wait:

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

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

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

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

完全一样

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

你可能在想“ 卧槽,这些怎么可能是一样的?”,你是对的。 async神奇地包装一个承诺 如果有必要的话的值。

更奇怪的是,doSomethingAsync可以写给 有时候回一个承诺,有时候 没有回一个承诺。但是这两个函数完全相同,因为 await也是 魔法。它将打开一个承诺 如果有必要的话,但它将没有影响的东西不是承诺。