我正在编写一个基于浏览器的Cmus Remote,并在后端使用Nodejs。该应用程序的一部分涉及获取当前正在播放的歌曲并将其显示给用户。
目前它成功运行该命令正确地将输出存储到变量中,但客户端请求在服务器端函数的回调之前运行,因此它为该歌曲重新打开一个空字符串。
以下是更好地说明我的意思的代码:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cmus Remote</title>
<script src="client.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body id="body">
</body>
</html>
client.js
"use strict";
window.onload = function () {
$.get("/songInfo", function(string){
alert(string);
});
};
server.js
var express = require('express');
var app = express();
var path = require('path');
var exec = require('child_process').exec;
var fs = require('fs');
var child;
var getSongCommand = "cmus-remote -Q | sed -n -e 's/^.*tag title //p'";
var getAlbumCommand = "cmus-remote -Q | sed -n -e 's/^.*tag album //p'";
var getArtistCommand = "cmus-remote -Q | sed -n -e 's/^.*tag artist //p'";
var song ="";
var album= "";
var artist = "";
app.use(express.static(__dirname + '/public'));
app.get('/', function (req, res){
res.sendFile(path.join(__dirname + '/index.html'));
});
app.get('/songInfo', function(req, res){
updateSongInfo(getSongCommand);
updateSongInfo(getAlbumCommand);
updateSongInfo(getArtistCommand);
var strings = [song, artist, album];
res.send(strings);
});
var server = app.listen(8080, function () {
console.log("Server online");
});
function updateSongInfo(command){
var exec = require('child_process').exec;
exec(command, function(error, stdout, stderr){
callback(command, stdout);
});
}
function callback(commandRan, output){
console.log("Commandran = " + commandRan);
console.log("Command output = " + output);
if(commandRan.includes("title")){
console.log("Updating song to " + output);
song = output;
}
if(commandRan.includes("album")){
album = output;
}
if(commandRan.includes("artist")){
artist = output;
}
// console.log("In callback");
// console.log(output);
return output;
}
总结一下,ajax响应工作正常,命令运行正常,值保存到我拥有的3个全局变量中,但是我不知道如何设置变量具有的ajax请求返回的时间值。
答案 0 :(得分:2)
问题是因为exec是异步的,所以exec将被调用,程序将继续并将仍然为空的数据返回给调用者,然后它将以现在收到的执行数据结束。
要解决此问题,您可以使用Promise和async / await。
app.get('/songInfo', async function(req, res){
await updateSongInfo(getSongCommand);
await updateSongInfo(getAlbumCommand);
await updateSongInfo(getArtistCommand);
var strings = [song, artist, album];
res.send(strings);
});
...
function updateSongInfo(command){
return new Promise((resolve, reject) => {
var exec = require('child_process').exec;
exec(command, function(error, stdout, stderr){
callback(command, stdout);
return resolve();
});
});
}
在Promise中调用resolve()将完成它,而调用reject()将抛出错误。你也可以给这些函数参数。
答案 1 :(得分:0)
您的updateSongInfo
函数异步运行,因此服务器在更新完成之前发回响应。您需要做的是实现Promises或在这些函数完成后运行的回调。我可能会建议你不要在这里使用全局变量,而是每次返回结果。这是一个例子:
app.get('/songInfo', function(req, res) {
var song, artist, album;
updateSongInfo(getSongCommand, function(err, result) {
if (err) return res.send(err);
song = result;
updateSongInfo(getAlbumCommand, function(err, result) {
if (err) return res.send(err);
album = result;
updateSongInfo(getArtistCommand, function(err, result) {
if (err) return res.send(err);
artist = result
// Now your globals will be fulfilled
return res.send([song, artist, album]);
});
});
});
});
function updateSongInfo(command, cb){
var exec = require('child_process').exec;
exec(command, function(error, stdout, stderr){
callback(command, stdout, cb);
});
}
function callback(commandRan, output, cbFunction){
console.log("Commandran = " + commandRan);
console.log("Command output = " + output);
if(commandRan.includes("title")){
console.log("Updating song to " + output);
song = output;
}
if(commandRan.includes("album")){
album = output;
}
if(commandRan.includes("artist")){
artist = output;
}
// console.log("In callback");
// console.log(output);
return cbFunction(null, output);
}