#node.js #spotify #synchronous
#node.js #spotify #синхронный
Вопрос:
Я работаю над ботом, используемым для запросов песен Twitch. Бот прочитает чат Twitch, выполнит поиск по команде !sr и получит название песни. Затем он выполнит поиск песни в Spotify, получит URI песни и добавит ее в список воспроизведения стримера.
РЕДАКТИРОВАТЬ: извините, если есть какие-либо «тупые» проблемы с кодом (например, уведомление об обратном вызове @ ippi), я действительно новичок в программировании и особенно в Node JS.
Теперь у меня есть две функции: одна, которая ищет песню и записывает полученный URI в текстовый файл, и одна, получающая URI из файла. Вот код:
основной код (вызов двух функций):
testSong(commandName, accessToken);
let uri = getUri();
console.log(uri);
поиск песни:
function testSong(song, accessToken) {
let song1;
let song2;
song1 = song.replace("!sr", "");
song2 = song1.trim();
var uri = "";
axios.get('https://api.spotify.com/v1/search?q=' encodeURIComponent(song2) 'amp;type=trackamp;market=CHamp;limit=1', {
headers: {
Authorization: 'Bearer ' accessToken
}
})
// handle success
.then(function (response) {
uri = response.data.tracks.items[0].uri;
console.log("yeet")
fs.writeFileSync('conf/uri.txt');
logger.log('info', 'Successfully obtained URI for track ' song2);
})
// handle error
.catch(function (error) {
logger.log('error', 'Error while accessing Spotify.');
return error;
});
}
получить URI:
function getUri() {
try {
return fs.readFileSync('conf/uri.txt', 'utf-8');
} catch (e) {
logger.log('error', 'Error while reading the URI text file: ' e.stack);
}
}
У меня проблема во время чтения. При первом запуске бота uri.txt файл пуст.
Когда я отправляю первый !sr в Twitch-чате, песня не добавляется в список воспроизведения Spotify, потому что кажется, что команда testSong записывает в текстовый файл ПОСЛЕ того, как функция getUri прочитала файл.
Даже после этого мне приходится отправлять новый !sr для добавления первой песни, поэтому каждый запрос сдвигается.
Есть идеи, почему это происходит?
Я читал об асинхронных функциях, но, насколько я понял, это не то, что я хочу, потому что я хочу, чтобы выполнение программы блокировалось при записи в текстовый файл, таким образом, функция getUri может считывать текущий запрошенный URI песни и не сдвигаться.
РЕДАКТИРОВАТЬ 2: как сказал Феликс, я изменил код следующим образом:
testSong(commandName, accessToken).then(() => console.log(getUri()));
function testSong(song, accessToken) {
let song1;
let song2;
song1 = song.replace("!sr", "");
song2 = song1.trim();
var uri = "";
return axios.get('https://api.spotify.com/v1/search?q=' encodeURIComponent(song2) 'amp;type=trackamp;market=CHamp;limit=1', {
headers: {
Authorization: 'Bearer ' accessToken
}
})
// handle success
.then(function (response) {
uri = response.data.tracks.items[0].uri;
console.log("yeet")
fs.writeFileSync('conf/uri.txt', uri, function (err) {
if (err) {
return console.log(err);
} else {
response = true;
}
});
logger.log('info', 'Successfully obtained URI for track ' song2);
})
// handle error
.catch(function (error) {
logger.log('error', 'Error while accessing Spotify.');
return error;
});
}
Это правильно?
Комментарии:
1. Перво-наперво,
fs.writeFileSync(file, data[, options])
не принимает обратный вызов, толькоwriteFile
принимает. Обратный вызов должен быть запущен когда-нибудь в будущем, когда WriteFile завершится.2. Вы записываете это синхронно, но запись происходит внутри функции, которая вызывается асинхронно. Функция «обработать успех» не будет вызвана, пока не будет выполнен ваш текущий сценарий (включая
let uri = getUri()
).3. @FelixKling хорошо, но почему? Я не указал, что моя функция testSong должна быть асинхронной. Все ли функции асинхронны по умолчанию?
4. «Я не указал, что моя функция testSong должна быть асинхронной» Вы используете promises. Функция, которую вы передали,
.then
будет вызвана через некоторое время в будущем , когда обещание будет выполнено. И это гарантированно займет как минимум одну итерацию цикла событий. «Все ли функции асинхронны по умолчанию?» Нет.5. Ах!!! Итак, мне нужно изменить его, используя другой API, кроме Axios? Не могли бы вы сказать мне, что использовать, если да?
Ответ №1:
Как я уже упоминал в своих комментариях, у вас возникла эта проблема, потому что вы используете promises, то есть файл будет записан через некоторое время в будущем, после того, как вы попытаетесь прочитать.
И, как мы уже обсуждали, нет никакой необходимости использовать файл для «передачи» значения вообще. Вы можете просто вернуть значение из testSong
(завернутое в обещание):
function testSong(song, accessToken) {
song = song.replace("!sr", "").trim();
return axios.get('https://api.spotify.com/v1/search?q=' encodeURIComponent(song2) 'amp;type=trackamp;market=CHamp;limit=1', {
headers: {
Authorization: 'Bearer ' accessToken
}
})
// handle success
.then(function (response) {
return response.data.tracks.items[0].uri;
});
// errors should probably be handled by the caller
}
и затем:
testSong(commandName, accessToken)
.then(function(uri) {
console.log(uri);
})
.catch(function(error) {
// handle error
});
async
Функция немного упрощает работу с promises. Таким образом, вы могли бы реализовать testSong
также как
async function testSong(song, accessToken) {
song = song.replace("!sr", "").trim();
const response = await axios.get('https://api.spotify.com/v1/search?q=' encodeURIComponent(song2) 'amp;type=trackamp;market=CHamp;limit=1', {
// ^^^^^
headers: {
Authorization: 'Bearer ' accessToken
}
});
return response.data.tracks.items[0].uri.
}