如何在节点js应用程序中显示加载器

时间:2018-03-08 08:03:28

标签: node.js bash spinner

我正在开发一个节点js应用程序。在我的应用程序中,我从节点js app调用脚本文件。

在该脚本文件中,我正在用azure创建一个HDI集群。

我想显示一个微调器,直到脚本完成HDI集群的创建,并在脚本执行后隐藏微调器。

如何使用Node js应用程序显示?给我举个例子?

index.js

<div class="container">
  <fieldset>
    <form action="/" method="post">
      <h4>Create Cluster</h4><br><br>
      <label for="name"> Name:  </label>
      <input name="name" type="text" class="name" placeholder="Enter a name" required><br><br>          
      <input type="submit" class="button" value="Create">
    </form>
  </fieldset>
  <div id="load"></div>
</div>

server.js

app.post('/', function (req, res) {
  res.render('index');

    var child = exec('bash sample.sh');

  child.stdout.on('data', function(data) {
    logger.info(data)
  });

  child.stderr.on('data', function(data) {
    logger.error(data);
  });

  child.on('close', function(code) {
    logger.info('Script exit code: ' + code);
  });
})

sample.sh

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

# -e: immediately exit if any command has a non-zero exit status
# -o: prevents errors in a pipeline from being masked
# IFS new value is less likely to cause confusing bugs when looping arrays or arguments (e.g. $@)

usage() { echo "Usage: $0 -i <subscriptionId> -g <resourceGroupName> -n <deploymentName> -l <resourceGroupLocation>" 1>&2; exit 1; }

declare subscriptionId=""
declare resourceGroupName=""
declare deploymentName=""
declare resourceGroupLocation=""

# Initialize parameters specified from command line
while getopts ":i:g:n:l:" arg; do
    case "${arg}" in
        i)
            subscriptionId=${OPTARG}
            ;;
        g)
            resourceGroupName=${OPTARG}
            ;;
        n)
            deploymentName=${OPTARG}
            ;;
        l)
            resourceGroupLocation=${OPTARG}
            ;;
        h)
            echo "This message"
        esac
done
shift $((OPTIND-1))

#Prompt for parameters is some required parameters are missing
if [[ -z "$subscriptionId" ]]; then
    echo "Your subscription ID can be looked up with the CLI using: az account show --out json "
    echo "Enter your subscription ID:"
    read subscriptionId
    [[ "${subscriptionId:?}" ]]
fi

if [[ -z "$resourceGroupName" ]]; then
    echo "This script will look for an existing resource group, otherwise a new one will be created "
    echo "You can create new resource groups with the CLI using: az group create "
    echo "Enter a resource group name"
    read resourceGroupName
    [[ "${resourceGroupName:?}" ]]
fi

if [[ -z "$deploymentName" ]]; then
    echo "Enter a name for this deployment:"
    read deploymentName
fi

if [[ -z "$resourceGroupLocation" ]]; then
    echo "If creating a *new* resource group, you need to set a location "
    echo "You can lookup locations with the CLI using: az account list-locations "

    echo "Enter resource group location:"
    read resourceGroupLocation
fi

#templateFile Path - template file to be used
templateFilePath="template.json"

if [ ! -f "$templateFilePath" ]; then
    echo "$templateFilePath not found"
    exit 1
fi

#parameter file path
parametersFilePath="parameters.json"

if [ ! -f "$parametersFilePath" ]; then
    echo "$parametersFilePath not found"
    exit 1
fi

if [ -z "$subscriptionId" ] || [ -z "$resourceGroupName" ] || [ -z "$deploymentName" ]; then
    echo "Either one of subscriptionId, resourceGroupName, deploymentName is empty"
    usage
fi

#login to azure using your credentials
az account show 1> /dev/null

if [ $? != 0 ];
then
    az login
fi

#set the default subscription id
az account set --subscription $subscriptionId

set +e

#Check for existing RG
az group show $resourceGroupName 1> /dev/null

if [ $? != 0 ]; then
    echo "Resource group with name" $resourceGroupName "could not be found. Creating new resource group.."
    set -e
    (
        set -x
        az group create --name $resourceGroupName --location $resourceGroupLocation 1> /dev/null
    )
    else
    echo "Using existing resource group..."
fi

#Start deployment
echo "Starting deployment..."
(
    set -x
    az group deployment create --name "$deploymentName" --resource-group "$resourceGroupName" --template-file "$templateFilePath" --parameters "@${parametersFilePath}"
)

if [ $?  == 0 ];
 then
    echo "Template has been successfully deployed"
fi

1 个答案:

答案 0 :(得分:1)

您尝试实现的内容类似于将在服务器端运行的长异步处理任务。此过程将由您的用户或前端代码启动。

有几种方法可以根据完成任务所需的平均预期时间来处理此类方案。让我们将它们区分为:

<强> 1。操作时间少于3秒(&lt; = 3000ms)

在这种情况下,您可以了解操作所需的时间,例如读取文件或创建群集或设置mongo数据库等等。因此,您可以从前面进行简单的XHR或AJAX调用。结束代码到节点服务器。

//index.html

<fieldset>
    <form action="javascript:void(0);" onSubmit="makeRequest()" method="post">
        <h4>Create Cluster</h4><br><br>
        <label for="name"> Name:  </label>
        <input name="name" type="text" class="name" placeholder="Enter a name" required><br><br>
        <input type="submit" class="button" value="Create" onclick="makeRequest()">
        </form>
    </fieldset>
    <div id="myLoader"></div>
</div>

<script>
    // I have missed some code for sake of breviety
    var makeRequest = function() {
        //get the value entered by the user in name input box
        var data = {name: 'xyz'};
        data.name = document.getElementsByName('name').value;

        //Since your request is about to begin 
        //after user has clicked on action button
        //Show loader
        document.getElementById("myLoader").style.opacity = 1;
        //Loader is visible to user

        var xhr = new XMLHttpRequest();
        ...
        xhr.addEventListener("readystatechange", function() {
            if (this.readyState === 4) {
                //Since your request is complete
                //Hide loader
                document.getElementById("myLoader").style.opacity = 0;
                console.log(this.responseText);
            }
        });

        xhr.open("POST", "http://mynodeserver/api/perfromOperation");
        xhr.setRequestHeader("content-type", "application/json");
        xhr.send(inputDataForserver);
    }
</script>

另一方面,服务器端将处理来自操作的请求,并在不超过3秒的时间内返回响应。

       //Server.js
       //This will load our index.html on users browser
        app.post('/', function(req, res) {
           res.render('index');
         });
        //OR 
        app.get('/', function(req, res) {
          res.sendFile(path.join(__dirname, 'public/index.html'));
        });

        //This endpoint will be called by user action 
        app.post('/api/perfromOperation', function(req, res) {
          //The data sent from UI is found in req.body
          //Make sure the data path is as needed...
          var name = req.body.name;
          var child = exec('bash sample.sh -n '+name);
          ...
          ...
          child.on('close', function(code) {
            logger.info('Script exit code: ' + code);
            res.json({ "code": code });
          });

        });

<强> 2。操作时间超过3秒(=> 3000ms)

这种情况将要求您拥有更复杂的流程,您可以从前端调用服务器,这将触发创建Azure群集的漫长过程。

这将在临时数据库中创建一个关于操作的记录,其中包括 - [operationId:#1] [状态:&#39; In_Progress&#39;] 然后,在ID#1的操作完成或出错后,您将更新此记录。

同样,这将要求您从前端拨打另一个电话来检查状态。

* note :时间用作参考,可能会根据您自己的规格和偏好而有所不同。

我希望这会有所帮助,如果您想在页面加载时触发群集创建操作,您也可以通过在文档onLoad事件上进行前面提到的XHR调用来实现。