通话时间过长后,承诺链会自行重复
promise chain is repeating itself after the call takes too long
我在 $http.get 调用中有一个很长的承诺链,需要花费几分钟才能完成。耗时较长的部分是一个 for 循环,循环遍历 160 个数组元素和 运行 一系列长长的套接字连接测试。然而,在 for 循环的第 84 次迭代周围,整个承诺链(或者可能是 get 调用)重新开始。而另一个还在运行ning。然后,一旦第一个链完成,res.send 就永远不会通过,而新链 运行 则无限重复。
router.get('/', function(req, res) {
fs.readdir('C:\Temp\hostPorts', function(err, files) {
console.log('files', files);
chooseFile(files).then(response => {readTheFile(response).then(async (result) => {
splitText(result).then( async (final) => {
console.log('final version', final);
res.send({file: final});
})
// res.send({file: result});
}).catch(error => {
console.log(error);
}) //end catch
}); //end promise
}); //end read
}); //end get
这是我的 get 调用,splitText 函数卡住了。我将 post 下面的 splitText 函数的源代码,但我确信它以某种方式创建了两个实例,因为每次在第 84 次迭代时,我的终端控制台都会重新打印初始的 console.log('files',文件),然后 运行s 通过链中的其他承诺。
它最终完成了第一个,因为 console.log('final version', final) 确实打印出来了。但是 res.send 从未发生,第二个承诺链继续 运行。然后是第三个,以此类推
这是长循环中的代码
async function splitText(file){
let tableData = "<table border=1 cellspacing=0><tr>";
let splited = file.trim().split(/\s+/);
//vars for checking connectivity
for (let i = 0; i < splited.length; i++) {
console.log(splited[i] + " " + i);
if(i < 4 ) {
tableData += "<th>" + splited[i] + "</th>";
//if its less than 4 print out table headers
}
else if (i == 4){
tableData += "</tr><tr><td>" + splited[i] + "</td>";
//if its 4 create a new row for data
}
else if (i % 3 == 0){
//if modulo 3 is 0 then its on a port, checks connectivity and adds it to the row as data after port
//then starts a new row
let host = splited[(i - 1)]; //1 index ago was host
let port = parseInt(splited[(i)]); //current array index is port
console.log('host: ' + host );
console.log('port: ' + port );
await testPort(port, host).then(async (reachable) => {
console.log(reachable);
if (reachable) {
tableData += "<td>" + splited[i] + "</td><td>" + "<font color=\"GREEN\">UP</font>" + "</tr><tr>";
}
else {
tableData += "<td>" + splited[i] + "</td><td>" + "<font color=\"RED\">DOWN</font>" + "</tr><tr>";
}
});
} //end else if
else {
tableData += "<td>" + splited[i] + "</td>";
//otherwise adds tabledata
}
} //end for
return tableData;
} //end function
这是检查 host/ports 是否启动的异步函数。
async function testPort(port, host){
return new Promise(resolve => {
const socket = new net.Socket();
const onError = () => {
socket.destroy();
resolve(false);
};
socket.setTimeout(10000);
socket.on('error', onError);
socket.on('timeout', onError);
socket.connect(port, host, () => {
socket.end();
resolve(true);
}); //end promise
});
我不确定这是否是 HTTP 的问题。花费太长时间后重新启动,但是我将超时设置为 5 分钟。或者,如果这是在未收到响应后重新启动的承诺链。但是我真的很在意这个问题,因为无论哪种方式,我都永远不会将数据返回给我的客户,而且据我所知,我从来没有回忆起一个函数或创建一个无限循环。
你在异步语法上混合三种不同的风格并没有帮助自己。第一步真的应该是将代码简化为单一样式,这通常会揭示问题。
乍一看,我怀疑你的问题是你如何链接承诺。你的一些 then 语句正在执行新的承诺,但没有 returning 一个承诺,这意味着你创建了多个承诺链。您也会丢失错误,因为它们没有 catch 子句。
我会重构为
router.get('/', function(req, res) {
fs.readdir('C:\Temp\hostPorts', function(err, files) {
sendFile()
.then(result => res.send(result));
.catch(err => {
console.error(err);
res.sendError("Boom");
}
}
}
async function sendFile() {
const file= await chooseFile(files);
const contents = await readTheFile(file);
const splitContents = await splitText(contents);
return {file: splitContents};
}
这使用比标准承诺链更易于阅读的异步等待。您始终必须记住 return 使用经典承诺链的 then 子句中的承诺,否则您可能会遇到麻烦。
我不确定您使用的是什么框架,以及它是否有处理重试请求的内部超时。上述代码的问题之一是测试网络连接是否连续发生。当您有很多主机要检查时,它会绑定到 fail/timeout。您可以并行测试多个主机。为此,拆分、测试和构建输出的代码应该分开。这是一个基本版本。
function _splitText(file = '') {
let ret = {
header: [],
hosts: {}
};
if (!file.length) {
return ret;
}
//split the content
let splitted = file.trim().split(/\s+/);
if (splitted.length % 3 !== 1 && splitted.length < 4) {
console.log('Invalid data!');
return ret;
}
//get header
ret.header = splitted.splice(0, 4);
while (splitted.length) {
const [name, host, port, ...rest] = splitted;
ret.hosts[name] = {
host,
port,
isReachable: false
};
splitted = rest;
}
return ret;
}
async function testPort(name, port, host) {
return new Promise(resolve => {
const socket = new net.Socket();
const onError = () => {
socket.destroy();
resolve({
name,
isReachable: false
});
};
socket.setTimeout(10000);
socket.on('error', onError);
socket.on('timeout', onError);
socket.connect(port, host, () => {
socket.end();
resolve({
name,
isReachable: true
});
}); //end promise
});
}
async function testPortsParallel(o, nParallel = 5, timeout = 10000) {
const hostnames = Object.keys(o.hosts);
let temp;
while ((temp = hostnames.splice(0, nParallel))) {
//create async promise for all hosts and wait for them at one go.
await Promise.all(temp.map(v => testPort(v, o.hosts[v].host, o.hosts[v].port))).then(values => values.forEach(v => o.hosts[v.name].isReachable = v.isReachable));
}
}
function buildOutput(o) {
let ret = '<table border=1 cellspacing=0>';
//add header
ret += '<tr><th>' + o.header.join('</th><th>') + '</th></tr>';
//add hosts
ret += o.hosts.keys().map(v => '<tr><td>' + [v, o.hosts[v].host, o.hosts[v].port].join('</td><td>') + '</td></tr>').join('');
ret += '</table>'
}
async function splitText(s) {
let data = _splitText(s);
await testPortsParallel(data);
return buildOutput(data);
}
splitText('name host port IsReachable 1 a b 2 c d');
//console.log(JSON.stringify(output));
希望这可能有点helpful.You可以根据您的需要调整并行测试的服务器数量。
注意:您的 testPort fn 也有轻微的问题。
我在 $http.get 调用中有一个很长的承诺链,需要花费几分钟才能完成。耗时较长的部分是一个 for 循环,循环遍历 160 个数组元素和 运行 一系列长长的套接字连接测试。然而,在 for 循环的第 84 次迭代周围,整个承诺链(或者可能是 get 调用)重新开始。而另一个还在运行ning。然后,一旦第一个链完成,res.send 就永远不会通过,而新链 运行 则无限重复。
router.get('/', function(req, res) {
fs.readdir('C:\Temp\hostPorts', function(err, files) {
console.log('files', files);
chooseFile(files).then(response => {readTheFile(response).then(async (result) => {
splitText(result).then( async (final) => {
console.log('final version', final);
res.send({file: final});
})
// res.send({file: result});
}).catch(error => {
console.log(error);
}) //end catch
}); //end promise
}); //end read
}); //end get
这是我的 get 调用,splitText 函数卡住了。我将 post 下面的 splitText 函数的源代码,但我确信它以某种方式创建了两个实例,因为每次在第 84 次迭代时,我的终端控制台都会重新打印初始的 console.log('files',文件),然后 运行s 通过链中的其他承诺。
它最终完成了第一个,因为 console.log('final version', final) 确实打印出来了。但是 res.send 从未发生,第二个承诺链继续 运行。然后是第三个,以此类推
这是长循环中的代码
async function splitText(file){
let tableData = "<table border=1 cellspacing=0><tr>";
let splited = file.trim().split(/\s+/);
//vars for checking connectivity
for (let i = 0; i < splited.length; i++) {
console.log(splited[i] + " " + i);
if(i < 4 ) {
tableData += "<th>" + splited[i] + "</th>";
//if its less than 4 print out table headers
}
else if (i == 4){
tableData += "</tr><tr><td>" + splited[i] + "</td>";
//if its 4 create a new row for data
}
else if (i % 3 == 0){
//if modulo 3 is 0 then its on a port, checks connectivity and adds it to the row as data after port
//then starts a new row
let host = splited[(i - 1)]; //1 index ago was host
let port = parseInt(splited[(i)]); //current array index is port
console.log('host: ' + host );
console.log('port: ' + port );
await testPort(port, host).then(async (reachable) => {
console.log(reachable);
if (reachable) {
tableData += "<td>" + splited[i] + "</td><td>" + "<font color=\"GREEN\">UP</font>" + "</tr><tr>";
}
else {
tableData += "<td>" + splited[i] + "</td><td>" + "<font color=\"RED\">DOWN</font>" + "</tr><tr>";
}
});
} //end else if
else {
tableData += "<td>" + splited[i] + "</td>";
//otherwise adds tabledata
}
} //end for
return tableData;
} //end function
这是检查 host/ports 是否启动的异步函数。
async function testPort(port, host){
return new Promise(resolve => {
const socket = new net.Socket();
const onError = () => {
socket.destroy();
resolve(false);
};
socket.setTimeout(10000);
socket.on('error', onError);
socket.on('timeout', onError);
socket.connect(port, host, () => {
socket.end();
resolve(true);
}); //end promise
});
我不确定这是否是 HTTP 的问题。花费太长时间后重新启动,但是我将超时设置为 5 分钟。或者,如果这是在未收到响应后重新启动的承诺链。但是我真的很在意这个问题,因为无论哪种方式,我都永远不会将数据返回给我的客户,而且据我所知,我从来没有回忆起一个函数或创建一个无限循环。
你在异步语法上混合三种不同的风格并没有帮助自己。第一步真的应该是将代码简化为单一样式,这通常会揭示问题。
乍一看,我怀疑你的问题是你如何链接承诺。你的一些 then 语句正在执行新的承诺,但没有 returning 一个承诺,这意味着你创建了多个承诺链。您也会丢失错误,因为它们没有 catch 子句。 我会重构为
router.get('/', function(req, res) {
fs.readdir('C:\Temp\hostPorts', function(err, files) {
sendFile()
.then(result => res.send(result));
.catch(err => {
console.error(err);
res.sendError("Boom");
}
}
}
async function sendFile() {
const file= await chooseFile(files);
const contents = await readTheFile(file);
const splitContents = await splitText(contents);
return {file: splitContents};
}
这使用比标准承诺链更易于阅读的异步等待。您始终必须记住 return 使用经典承诺链的 then 子句中的承诺,否则您可能会遇到麻烦。
我不确定您使用的是什么框架,以及它是否有处理重试请求的内部超时。上述代码的问题之一是测试网络连接是否连续发生。当您有很多主机要检查时,它会绑定到 fail/timeout。您可以并行测试多个主机。为此,拆分、测试和构建输出的代码应该分开。这是一个基本版本。
function _splitText(file = '') {
let ret = {
header: [],
hosts: {}
};
if (!file.length) {
return ret;
}
//split the content
let splitted = file.trim().split(/\s+/);
if (splitted.length % 3 !== 1 && splitted.length < 4) {
console.log('Invalid data!');
return ret;
}
//get header
ret.header = splitted.splice(0, 4);
while (splitted.length) {
const [name, host, port, ...rest] = splitted;
ret.hosts[name] = {
host,
port,
isReachable: false
};
splitted = rest;
}
return ret;
}
async function testPort(name, port, host) {
return new Promise(resolve => {
const socket = new net.Socket();
const onError = () => {
socket.destroy();
resolve({
name,
isReachable: false
});
};
socket.setTimeout(10000);
socket.on('error', onError);
socket.on('timeout', onError);
socket.connect(port, host, () => {
socket.end();
resolve({
name,
isReachable: true
});
}); //end promise
});
}
async function testPortsParallel(o, nParallel = 5, timeout = 10000) {
const hostnames = Object.keys(o.hosts);
let temp;
while ((temp = hostnames.splice(0, nParallel))) {
//create async promise for all hosts and wait for them at one go.
await Promise.all(temp.map(v => testPort(v, o.hosts[v].host, o.hosts[v].port))).then(values => values.forEach(v => o.hosts[v.name].isReachable = v.isReachable));
}
}
function buildOutput(o) {
let ret = '<table border=1 cellspacing=0>';
//add header
ret += '<tr><th>' + o.header.join('</th><th>') + '</th></tr>';
//add hosts
ret += o.hosts.keys().map(v => '<tr><td>' + [v, o.hosts[v].host, o.hosts[v].port].join('</td><td>') + '</td></tr>').join('');
ret += '</table>'
}
async function splitText(s) {
let data = _splitText(s);
await testPortsParallel(data);
return buildOutput(data);
}
splitText('name host port IsReachable 1 a b 2 c d');
//console.log(JSON.stringify(output));
希望这可能有点helpful.You可以根据您的需要调整并行测试的服务器数量。
注意:您的 testPort fn 也有轻微的问题。