У меня проблема, когда я хочу дождаться асинхронного запроса к базе данных и его операций, прежде чем продолжить.
Я, конечно, мог бы поместить операции внутри пирамиды, но в долгосрочной перспективе это не будет круто, потому что мне иногда придется дублировать код.
Вот мой пример (который, конечно, сейчас не будет работать из-за асинхронности запросов к базе данных):
var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random()*(50+level)+1);
if (difficulty < randomDecider) {
var type;
var name;
var heroid = "";
dbconn.query("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login], function(err, result, fields) {
heroid = result[0].heroid;
});
if (randomDecider > 50) {
type = "skill";
var ownedSkills = [];
var skillsKeys = Object.keys(Skill);
dbconn.query("SELECT * FROM owned_skills WHERE user = ? AND heroid = ? AND equipped = 1", [req.session.login, heroid], function(err, result, fields) {
for (var i = 0; i < result.length; i++) {
ownedSkills.push(result[i].name);
}
});
//Here later I also want to remove ownedSkills from skillsKeys.
name = skillsKeys[Math.floor(Math.random()*skillsKeys.length)];
}
else {
type = "item";
var itemsKeys = Object.keys(Item);
var ownedItems = [];
dbconn.query("SELECT * FROM owned_items WHERE user = ? AND heroid = ? AND equipped = 1", [req.session.login, heroid], function(err, result, fields) {
for (var i = 0; i < result.length; i++) {
ownedItems.push(result[i].name);
}
});
//Here later I also want to remove ownedItems from itemsKeys.
name = itemsKeys[Math.floor(Math.random()*itemsKeys.length)];
}
//Some other code using the type and name variable.
Так может ли кто-нибудь на основе этого объяснить мне, как я могу преобразовать это во что-то работающее, например, дождаться завершения действий после запросов, прежде чем двигаться вперед. Я пробовал async / await, но пока не могу понять.
Также приветствуются любые другие предложения по коду. Спасибо.
@ionizer Не могли бы вы показать мне пример того, как бы вы обернули функции запроса? Всего лишь по одной функции запроса, и я буду очень признателен.
Вы можете попробовать такой код: function q(str, params) { return new Promise((resolve, reject) => {dbconn.query(str, params, (err, result, fields) => {if (err) reject(err); resolve(result)})})}. Я придумал ответ, используя это, если вы не против подождать еще немного.
@ionizer Да, конечно, если хочешь, я могу дождаться ответа, но я думаю, что знаю, что ты имеешь в виду, и смогу заставить его работать, но все же я буду ждать аккуратной версии. :)
Я опубликовал ответ, вы можете выбрать любой подход. Кстати, какую версию Node вы используете?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я объяснил в комментариях об использовании Promise. И я предполагаю, что вы используете библиотеку mysql для своей программы NodeJS.
Итак, во-первых, чтобы избежать пирамиды (или ада обратных вызовов, как мы ее обычно называем), мы можем попробовать обернуть функцию async в Promise следующим образом:
function queryPromise(str, params) {
return new Promise((resolve, reject) => {
dbconn.query(str, params, (err, result, fields) => {
if (err) reject(err);
resolve(result);
})
})
}
Тогда я обещал только важную часть:
var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random() * (50 + level) + 1);
if (difficulty < randomDecider) {
var type;
var name;
var heroid = "";
queryPromise("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login]).then(result => {
heroid = result[0].heroid;
if (randomDecider > 50) {
........
Вы можете использовать эту функцию и для других ваших запросов. Но ждать! Разве это не то же самое, что положить его в пирамиду? Что ж, это то же самое более или менее, и обычно это способ сделать это так, чтобы ваш код выполнялся так, как мы хотим. Но теперь мы можем связать Promise .then() с другими запросами внутри и избежать еще большего отступа вашего кода, что приведет к созданию ада обратных вызовов. Хотя это не то, что мне нравится делать, поскольку цепочка обещаний также приносит ад, когда мы не будем осторожны с этим.
Если вы используете Node 8 или выше, использование async await - лучшее решение. Учитывая, что async await также использует обещания, мы можем сделать это так:
var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random() * (50 + level) + 1);
if (difficulty < randomDecider) {
var type;
var name;
var heroid = "";
let heroidQuery = await queryPromise("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login]);
heroid = heroidQuery[0].heroid;
if (randomDecider > 50) {
........
Теперь выглядит намного лучше, не так ли? Как следует из ключевого слова, await заставляет ваш код ждать, пока результат будет получен из вашего запроса. Только не забудьте обернуть весь этот код в блок async function(), поскольку await не разрешен вне функций async.
async function myfunc() {
var level 5;
....
Я предлагаю изучить библиотеки, такие как mysql2/promise или даже sequelize, которые используют Promises, когда вам удобно с Promises (или даже лучше, вместе с async-await).
Надеюсь, это поможет. Удачи!
Один вопрос, если я поставлю, скажем, «myfunc ()» как async, тогда как мне дождаться его обратного вызова, потому что я делаю так: var squareweb = myfunc(); И позже, используя переменную squareweb, поэтому myfunc () не может быть асинхронным . Придется ли мне создавать еще одно обещание для myfunc () или?
Функции async возвращают обещание, и все, что вы return внутри них, совпадает с resolve()-обещанием с данными. Таким образом, вы можете использовать squareweb.then() или даже снова использовать await. Для чего нужен var squareweb и как он будет использоваться?
somefunc(req).then(function(gweb) { squareweb = gweb; /*Some other code*/ } Готово. Большое спасибо :)
Пойдите и прочтите
Promise. Это может позволить вам избежать ада пирамиды обратных вызовов при решении вашей проблемы. Вы можете попробовать обернуть функцию запроса в обещания.