现有一文件,需要显示其进度状态,涉及到调用c++底层的exe,然后与c++ 进行 socket 通信获取返回值,其中包含进度
处理逻辑: 前端界面写入一笔数据,服务中线程一进行监听,(更改数据状态后)并调用exe,另一线程监听Socket 返回值,根据关键字解析后将进度更新其中,最后web前端按照固定时间去表中读取进度后赋值给UI即可。
<body> <script> $(function () { var ccont = 0; var ttpPos = "0"; var subPos = ""; var loadvideo = 0; function subViddeoCall(id,videoId) { var taskid = '@ViewBag.taskid'; var videoId = videoId; if (subPos != "-1" && subPos != "100") { //按照进度-截取视频操作 $.post("../Kiaser/QuertTaskPartProgress", { Id: id }, function (data) { if (data != null) { subPos = data.Pos == null ? "0" : data.Pos; //判断当前进度停留时间 //CountMinuDate(taskpos, ttpPos, videoId, taskid) //ttpPos = subPos; $("#prog").val(subPos).show(); $("#spe").html(subPos + "%").show(); }; }, "JSON"); } if (subPos == "-1") { //截取失败 loadvideo = 0; subPos = "0"; //停止循环 clearInterval(sub); //刷新列表 SubVideoFail(videoId, taskid); } if (subPos == "100") { loadvideo = 0; subPos = "0"; //$.ajaxSettings.async = false; $.post("../Kiaser/UpdateUploadType", { value: 9, videoId: videoId, taskId: taskid }, function (data) { //刷新视频列表状态 VideoStatus(); //关闭进度条 $("#prog").val(0).hide(); $("#spe").html(""); clearInterval(sub); }, "JSON"); //$.ajaxSettings.async = true; } } var sub; $("#btnGetPos").click(function () { //先执行一次 subViddeoCall(id, videoId); //循环取值3000 sub = setInterval(subViddeoCall, 3000, id, videoId); }); }) </script> <div> <span>进度</span> <progress max="100" value="0" id="prog" style="display:none"></progress> <span id="spe"></span> </div> <input type="button" id="btnGetPos" value="获取进度"/> </body>
单一刷进度的话,没啥,就是将进度值付给 progress 标签的 value属性值(HTML5),然后判断进度值,不为-1到100 则查询并赋值,为-1则失败,为100则成功,这里需要注意的是要把进度值为 [1,100) 的赋值写在最前面,因为ajax 是异步的,如果写在后面的话,会出现进度异常,除非把赋值的ajax 改成同步 ($.ajaxSettings.async = false; ajax .... ; $.ajaxSettings.async = true;),这是一个坑.
还要考虑一种情况, 比如进度正在刷新时,服务突然停止或者资源沾满等原因,进度则会长时间停留在某一固定值中,体验感很差。这是就需要设置一个时间点,来计算当前进度和上一次进度如果一样,则开始计时,超过一定时间仍然一样,则判断当前任务执行失败。于是做了如下处理
//计算时间差 当前进度/上一次进度/文件Id/任务Id function CountMinuDate(taskpos, tpPos, videoId, taskid) { if (taskpos == tpPos) { ccont += 1; console.log("当前进度:" + taskpos + " 上次进度:" + tpPos + " 执行次数:" + cont + " 类型:" + typeof (cont)); if (ccont == 10) { console.log("任务执行失败"); //重复次数清零 ccont = 0; //调用失败方法 Fail(videoId, taskid); } } else { //重复次数清零 ccont = 0; } }
这里当出现当前进度和上次进度相同时,调用此方法,并计算次数,注意,如果不相同,需要清零计数变量,同样在超过3秒后(10*3000),计数变量仍然需要清零。然后在之前的获取进度的方法体中调用此方法即可。
if (subPos != "-1" && subPos != "100") { //按照进度-截取视频操作 $.post("../Kiaser/QuertTaskPartProgress", { Id: id }, function (data) { if (data != null) { subPos = data.Pos == null ? "0" : data.Pos; //判断当前进度停留时间 CountMinuDate(taskpos, ttpPos, videoId, taskid) ttpPos = subPos; $("#prog").val(subPos).show(); $("#spe").html(subPos + "%").show(); }; }, "JSON"); }
至于用在项目中的话,肯定还需要考虑正在刷新进度的时候,关闭界面,然后在重新进来,这时,需要在界面时初始化的时候,多加一个判断,是否有任务,若有,先查询进度值,或正常,或失败,或完成。根据不同的状态值,再执行各自的方法即可