То, что вы видите здесь, на самом деле является эффектом двух закруглений. Числа в ECMAScript представляют собой внутренне представленную точку с плавающей запятой с двойной точностью. Если для параметра id
установлено значение 714341252076979033
(0x9e9d9958274c359
в шестнадцатеричном формате), ему фактически присваивается ближайшее представимое значение двойной точности, которое равно 714341252076979072
(0x9e9d9958274c380
). Когда вы распечатываете значение, оно округляется до 15 значащих десятичных цифр, что дает 14341252076979100
.
Возвращаемое значение всегда будет обещанием. Если вы явно не вернете обещание, возвращаемое вами значение автоматически будет завернуто в обещание.
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));
Обещает автоматическое разворачивание, поэтому, если вы вернете обещание для значения из функции 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. Похоже, что когда вы явно возвращаете значение non-prom из функции async, оно принудительно завершает его в обещание. У меня нет большой проблемы с этим, но он бросает вызов нормальному JS.
blockquote>ES6 имеет функции, которые не возвращают точно то же значение, что и
return
. Эти функции называются генераторами.function* foo() { return 'test'; } // Logs an object. console.log(foo()); // Logs 'test'. console.log(foo().next().value);
async не возвращает обещание, ключевое слово await ожидает разрешения обещания. async - это расширенная функция генератора, и ожидание работает немного подобно 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);
});
});
}
Я просмотрел спецификацию и нашел следующую информацию. Краткая версия - это async function
desugars к генератору, который дает Promise
s. Итак, да, асинхронные функции возвращают обещания.
Согласно tc39 spec , верно следующее:
async function <name>?<argumentlist><body>
Desugars to:
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); });
});
}