当脚本执行完成后允许点击链接

4
我正在寻找一种方法,允许用户在特定功能完成运行后才能点击链接。在我的情况下,我有一个ejs模板,其中包含两个链接。点击第一个链接(“运行python”)会激活一个需要一些时间才能完成的脚本。只有在它完成后(所以控制台上会显示"finished",来自于这行代码:console.log('finished'),下一个链接(“查看表格”)才会可点击(或取消隐藏等)。
<h1>Search for a movie</h1>

<form action="results" method="GET">
    <input type="text" placeholder="search term" name="search">
    <input type="submit">
</form>

<p><a href="/run"> Run python </a></p>
<p><a href="/data"> See the table </a></p>

这里是app.js代码

var express = require("express")
var app = express()
var request = require("request")
var PythonShell = require('python-shell');
app.set("view engine", "ejs")
app.engine('html', require('ejs').renderFile);

var thelist =[]

app.get("/", function(req, res){
    res.render("search")
})

var jsondata = ""


app.get("/results", function(req, res){
    var query = req.query.search
    var url = "http://www.omdbapi.com/?s=" + query + "&type=series&apikey=thewdb"

    request(url, function(error, response, body){
        if(!error && response.statusCode == 200){
            var data = JSON.parse(body)
            res.render("results", {data: data})
        }    
    })
})

app.get('/data', function(req, res) {
    //viewname can include or omit the filename extension
    res.render(__dirname + '/well.html'); 
});


app.get("/show/:id", function (req, res) {
    var id = req.params.id;
    thelist.push(id)
    console.log(thelist);
    res.redirect('/')
});

app.get("/run", function(req, res) {
            var pyshell = new PythonShell('script2.py');
            pyshell.send(JSON.stringify(thelist))
            pyshell.on('message', function (message) {
    // received a message sent from the Python script (a simple "print" statement)
            jsondata += message
            });

// end the input stream and allow the process to exit
            pyshell.end(function (err) {
             if (err){
               throw err;
                };

            console.log('finished');
            });
            res.redirect('/')
            thelist = []
});

app.listen(process.env.PORT, process.env.IP, function(){
    console.log("Movie App has started!!!");
})

假设您最初将该链接(“查看表格”)保持隐藏(或禁用),然后在pyshell.end函数完成后为其添加内联样式,这样可以吗?例如:var linkToEnable = document.querySelector(".link-to-enable); linkToEnable.style.display = "block";(这只是一个例子 - 关键在于确定是否可以在预期的时刻添加内联样式:在所讨论的函数完成后)。 - UncaughtTypeError
嗯,我不确定我是否做得正确,但是我收到了一个错误,指出文档未定义。这是服务器端的node.js代码,似乎不允许DOM操作。 - Alex T
5个回答

3
您可以使用Ajax完成此操作,正如Emil在他的答案中建议的那样,但由于您正在使用ejs模板引擎,为什么不直接使用它呢?(您只需要将.html模板文件扩展名更改为.ejs)。
此外,在这里我认为您最好不要使用res.redirect。最好使用res.render并将参数传递给视图,默认设置为false。
一个基本示例:
server.js
// ...
app.get("/", function (req, res) {
  res.render("search", { active: false });
})

// ...
app.get("/run", function (req, res) {
  // ...
  pyshell.end(function (err) {
    if (err) throw err;
    console.log('finished');
    res.render("search", { active: true });
  });
});

search.ejs

<p><a href="/run">Run python</a></p>
<p>
  <%if (active) { %>
    <a href="/data">See the table</a>
  <% } else { %>
    See the table
  <% } %>
</p>

现在,只有在Python脚本完成后,才能单击"查看表格"链接。


3

摘要

应该使用AJAX调用来完成。在/run中不要使用重定向,而是可以返回一些JSON数据,指示作业的成功/错误状态。

点击运行Python时,将运行AJAX调用,而不是将页面重定向到/

在AJAX调用的OnSuccess中,您可以启用查看表格。

代码

HTML

<p><a id="run" href="/run"> Run python </a></p>
<p><a id="show-data" href="/data" style="pointer-events:none;"> See the table </a></p>

前端JavaScript

$(function() {
  $('#run').click(function(event) {
     event.preventDefault();
     $.get('/run', function() {
       $('#show-data').css('pointer-events', 'all');
     });
  });
});

NodeJs

app.get("/run", function(req, res) {
  ...
  // res.redirect('/');
  res.json({ success: true });
});

我按照您发布的方式尝试了一下,当我点击运行Python后,“查看表格”已经可以点击了,但是脚本还没有完成。为什么会这样? - Alex T
换句话说,在 app.get 中的整个代码运行完毕后,它应该发送 res.json({success: true}),以便 console.log 被执行。 - Alex T
你在 run 函数中移除了 res.redirect('/') 吗? - emil
是的,我已经这样做了:目前它看起来像这样:app.get("/run", function(req, res) { var pyshell = new PythonShell('script2.py'); pyshell.send(JSON.stringify(thelist)) pyshell.on('message', function (message) { jsondata += message }); pyshell.end(function (err) { if (err){ throw err; }; console.log(jsondata); res.json({ success: true }); }); }); - Alex T
我不确定这是否是您要求的内容: jquery.min.js:4 XHR完成加载:GET“https://python-node-projct-atpim.c9users.io/run?onSuccess=undefined”。 send @ jquery.min.js:4 ajax @ jquery.min.js:4 n.(匿名函数)@ jquery.min.js:4 (匿名)@(索引):94 dispatch @ jquery.min.js:3 r.handle @ jquery.min.js:3 在实际的console.log语句运行后,我得到了这个结果-所以它打印了我想要的。但是,在接收到并打印console.log之前,“运行表格”链接是可点击的。 - Alex T
显示剩余3条评论

1

您可以使用Jquery的prevent函数来防止链接。

 $("a").click(function() {
        if (status == "1") {
           return true;

        } else {
           return false;
           e.preventDefault();
        }
     });

这是一个函数,我用它来阻止用户在运行函数之前导航到其他页面。
我初始化了一个名为status的变量,并将其值设置为0。
然后,在函数成功运行后,我递增了该变量。
因此,如果状态为0,则URL将无法使用。完成函数后,状态将递增为1,因此如果条件为真,则会返回true语句。如果不是,则会返回false语句,并使用e.preventDefault()进行防止。

这是问题中比较简单的部分。但另一部分是如何设置状态呢? ;) - Mouneer
在您的函数成功完成后,您必须增加状态值。 - pradeep kumar
你介意将这部分代码添加到你的解决方案吗? - Alex T

-1

为什么不尝试使用socket.io呢?这里有简化的代码,但是完全可用...

(注意:“msg”对象仅用于示例,以供进一步使用)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Title</title>
</head>

<body>
  <h1>Search for a movie</h1>
  <p><a href="#" onclick="runPython()"> Run python </a></p>
  <p><a id="table-data"> See the table </a></p>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    var msg = {
      msg: "TestMsgSend",
      iParam: 100,
      sParam: "Test Param 1",
      aParam: [1, 2, 3]
    }
    var socket = io();

    socket.on("server:finished", function (msg) {
      // msg = "TestMsgReceived", for further usage
      console.log("\nId: " + socket.id + "\nmsg: " + msg.msg + "\niParam: " + msg.iParam + "\nsParam: " + msg.sParam + "\naParam: " + msg.aParam);

      document.getElementById("table-data").setAttribute("href", "/data");
    });

    function runPython() {
      socket.emit("client:run", msg);
    }
  </script>
</body>
</html>

app.js

var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);

app.use("/", express.static(__dirname + "/"));

// ***************************************************************************
// ***************************************************************************
// ***** Your code
// ***************************************************************************
// ***************************************************************************

io.on("connection", function (socket) {
  console.log("New connection with id: " + socket.id);

  socket.on("client:run", function (msg) {
    // msg = "TestMsgSend", for further usage
    console.log("\nId: " + socket.id + "\nmsg: " + msg.msg + "\niParam: " + msg.iParam + "\nsParam: " + msg.sParam + "\naParam: " + msg.aParam);

    // ***************************************************************************
    // ***************************************************************************
    // ***** Your code
    // ***************************************************************************
    // ***************************************************************************

    msg.msg = "TestMsgReceived";
    msg.iParam++;
    msg.sParam = "Test Param 2";
    msg.aParam.push(4, 5, 6)
    io.emit("server:finished", msg);
  });
});

// ***************************************************************************
// ***************************************************************************
// ***** Your code
// ***************************************************************************
// ***************************************************************************

http.listen(80, function () {
  console.log("listening on *:80");
});

package.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.2",
    "socket.io": "^2.0.4"
  }
}

node app.js 开始,尽情享受吧


实现套接字对于这种情况来说有些过度了。你并没有在制作实时应用程序,只是禁用了一个链接! - Mouneer

-1

为什么不使用一个简单的守卫变量呢?在你的代码中:

var ready = false; // 1) the guard

app.get('/data', function(req, res) {
    if (ready) { // 2) view execution blocked until guard is ready
        res.render(__dirname + '/well.html');
    }
});

app.get("/run", function(req, res) {
    var pyshell = new PythonShell('script2.py');
    pyshell.send(JSON.stringify(thelist))
    pyshell.on('message', function (message) {
        // received a message sent from the Python script (a simple "print" statement)
        jsondata += message
    });

    // end the input stream and allow the process to exit
    pyshell.end(function (err) {
        if (err) {
            throw err;
        };
        ready = true; // 3) if evetything is OK the guard is now ready
        console.log('finished');
    });
    res.redirect('/')
    thelist = []
});

1- 在单线程服务器中使用全局变量将无法正确处理多个用户。 2- 这并没有回答禁用链接的问题。 - Mouneer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接