Я изучаю Node.js и пытаюсь правильно использовать модуль mysql2. Из-за этого я недавно начал исследовать промисы.
Я пишу что-то вроде «библиотеки», поэтому я могу практиковаться во всех этих темах, и при этом я столкнулся с проблемой с цепочкой обещаний, которую я не могу понять. Любая помощь приветствуется!
Проблема в следующем:
Допустим, у меня есть функция query, которая извлекает базу данных, обрабатывает данные и возвращает обещание, поэтому я могу получить эти данные и работать с ними в каком-то другом файле.
Теперь, если я напишу свою функцию query следующим образом:
query(){
let p = new Promise((resolve, reject) => {
resolve("Hello world")
});
p.then(data => {
console.info("Hello world a second time!");
}).then(data => {
console.info("Hello world a third time")
})
return p;
}
и я пытаюсь «использовать» это обещание из другого файла следующим образом:
DBObject.query().then((data) => {
console.info("Hello world from the other file!");
})
Тогда вывод в неправильном порядке, программа печатает это:
Hello world a second time!
Hello world from the other file!
Hello world a third time
С другой стороны, если я изменю код в первом файле и не попытаюсь разделить цепочку обещаний, например так:
query(){
let p = new Promise((resolve, reject) => {
resolve("Hello world")
}).then(data => {
console.info("Hello world a second time!");
}).then(data => {
console.info("Hello world a third time")
})
return p;
}
Он отлично работает и печатает:
Hello world a second time!
Hello world a third time
Hello world from the other file!
Я не понимаю такого поведения, я думал, что объявление блоков then отдельно от определения промиса будет таким же, как и создание цепочки промисов сразу после объявления промиса, а это явно не так!
Заранее спасибо за ответы, которые вы можете мне дать. Кроме того, было бы здорово, если бы вы могли дать мне несколько советов о том, как правильно писать такой код. Я имею в виду, если я пишу код, использующий промисы, что я должен вернуть пользователю? Еще одно обещание? Или просто данные для работы? Мне бы очень хотелось писать код, который следует «стандартному» способу ведения дел.
Приветствую вас всех! Еще раз спасибо.



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


Вместо возврата p в отдельной версии... верните цепочку p.then(). Последний будет добавлен в конец этой цепочки, а не создавать две разные цепочки.
then() возвращает новое обещание, разрешенное любым возвратом или undefined, если возврата нет
const query = () => {
let p = new Promise((resolve, reject) => {
resolve("Hello world")
});
return p.then(data => {
// from `resolve()`
console.info('Then 1: ', data)
// return to next then()
return ("Hello world a second time!");
}).then(data => {
// from previous then()
console.info('Then 2: ', data)
// return to next then()
return ("Hello world a third time")
});
}
query().then(res => console.info('Final: ', res))Как только вы поймете, что каждый then — это новое обещание, его будет легче визуализировать.
Когда у вас есть одно обещание, вы можете связать любой номер обещаний с его .then. Например
const p = Promise.resolve();
p.then(() => console.info('then 1');
p.then(() => console.info('then 2');
означает, что p имеет два Promises, которые от него ответвляются, когда он разрешается: 1 и 2 (в дополнение к самому обещанию p).
p
/ \
/ \
1 2
Что вы делаете в своем первом коде
let p = new Promise((resolve, reject) => {
resolve("Hello world")
});
p.then(data => {
console.info("second");
}).then(data => {
console.info("third")
})
return p;
как
"Hello world" = <Promise you return>
|
|
|
second
|
|
|
third = <unused Promise expression that the then chain resolves to>
У вас есть две ветви: обещание, которое вы возвращаете, разрешается, когда запускается Hello world, а не когда запускается third.
С другой стороны, когда вы вызываете .then несколько раз для обещания, все выражение оценивается как обещание, которое разрешает когда бежит финал .then:
let p = new Promise((resolve, reject) => {
resolve("Hello world")
}).then(data => {
console.info("Hello world a second time!");
}).then(data => {
console.info("Hello world a third time")
})
return p;
как
"Hello world"
|
|
'Hello second'
|
|
'Hello third' = <Promise you return>
где возвращенный промис — это тот, который разрешается сразу после запуска Hello third.
Спасибо за отличное и подробное объяснение, CertainPerformance! Теперь это имеет смысл, и это здорово, потому что я определенно был сбит с толку. :)
Верно ли также, что если вы возвращаете промис внутри onResolveCallback из .then(onResolveCallback), это промис не тот, который вы используете в цепочке. Обещание, возвращаемое .then(), является другим обещанием, которое разрешается только после выполнения onResolveCallback, и, если возвращаемое значение onResolveCallback также является обещанием, остается в состоянии ожидания до тех пор, пока обещание, возвращенное onResolveCallback, тоже не разрешается? Это правильно? Надеюсь, я был понятен.
Спасибо за ответ, chaflietfl! Я понятия не имел, что могу вернуть обещание, вернув p.then. Это, в сочетании с ответом CertainPerformance, действительно очень помогло! Я протестировал ваш код внутри своей функции, и он отлично сработал, мне понравился этот подход.