`
uule
  • 浏览: 6358024 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

手机版倒计时问题 + 伪异步

 
阅读更多

倒计时:

手机倒计时会有两个问题:

1、返回到倒计时页面时,倒计时不是最新的

2、锁屏后,再打开,倒计时不是最新的

 

经校验发现,后退时,Jquery的该方法都会执行,因此可解决问题1.

$(function(){

 

});

 

 

第一方案

会有问题:后退更新,锁屏不更新

$(function(){	
	$.get('/auction/getTimeCountDown.html',{ auctionIds: timeIds.join(","),idd : Math.random()},
		function(data) {
			afterGetNewSeconds(data);
		}
	);
});

 启动方法中加入getTimeCountDown请求,每次获取最新倒计时秒数

 

第二版:

正常,没有问题。

         进入时取一次剩余倒计时秒数m

         请求前纪录客户端时间a,请求后纪录客户端时间b, (b-a)/2 为网络延时

         请求后由当前客户端时间,加上返回的剩余倒计时秒数m,再减去网络延时,得到当前客户端的倒计时结束时间

 

         客户端JS定时器,10秒刷新一次,获取到当前时间与客户端结束时间的秒数差c,刷新倒计时

         若定时器倒计时的秒数(1秒刷一次,10秒后的秒数)与 c 误差在1秒内,不刷新定时器,否则清除老定时器,生成新定时器

 

 具体代码如下:

HTML:

倒计时:<i class="auctTime" id="<@getStringValue cdo=cdoAuction col='nAuctionId' />"></i>

 

timer.js:

var finishArray = [];
var timerArray = [];
//处理网络延时时间
var startTime ;
var endTime ;
//保存歌倒计时定时器,清除定时器时使用
var map = new HashMap();
//保存本地倒计时中的最新秒数,与10秒刷新获取的本地客户端结束时间倒计时比较
var map2 = new HashMap();
var obj = new Object();

$(function(){	

	//获取需倒计时的兑换产品Id
	var timeIds = [];
	$(".auctTime").each(function(){
		var id = $(this).attr("id");		
		timeIds[timeIds.length] = id;
	})
	
	if(timeIds.length == 0) return;
	startTime = new Date();

	//获取最新时间
	$.get('/auction/getTimeCountDown.html',{ auctionIds: timeIds.join(","),idd : Math.random()},
		function(data) {
			afterGetNewSeconds(data);
		}
	);


	window.setInterval(refreshCountDown,10000);
});


function timer(intDiff,id){
	var intervalname = "interval"+id;
    var timerVar = window.setInterval(function(){
	    var day=0,
	        hour=0,
	        minute=0,
	        second=0;//时间默认值       
	    if(intDiff > 0){
	        day = Math.floor(intDiff / (60 * 60 * 24));
	        hour = Math.floor(intDiff / (60 * 60)) - (day * 24);
	        minute = Math.floor(intDiff / 60) - (day * 24 * 60) - (hour * 60);
	        second = Math.floor(intDiff) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60);
	    }
	    hour = day * 24 + hour;
	    if (hour <= 9) hour = '0' + hour;
	    if (minute <= 9) minute = '0' + minute;
	    if (second <= 9) second = '0' + second;
	    
	    var str = "";
	    str += hour + ":";
	    str += minute + ":";
	    str += second;
	    intDiff--;
	    
	    console.log("=======================");
	    map2.put(intervalname,intDiff);
	    $("#" + id).html(str);
	    if(intDiff <= 0){
	    	if(typeof isdetail != "undefined" && isdetail == "1"){
	    		//刷新当前页面
	        	location.reload();
	    	}else{
	    		$("#bidding_"+id).remove();
	    		$(".cd_"+id).hide();
		    	$("#btn_"+id).text("竞拍结束");
		    	clearInterval(timerVar);
	    	}
	    	
	    }
    }, 1000);

    map.put(intervalname,timerVar);
    	
    timerArray[timerArray.length] = timerVar;
}


//获取客户端当前时间与 客户端结束时间作比较,刷新倒计时
function refreshCountDown(){
	if(finishArray.length >= 0){
		for(var i in finishArray){						
			refreshPerCountDown(finishArray[i]);
		}		
	}
	
}

function afterGetNewSeconds(data){	
	endTime = new Date();
	var interval = endTime.getTime() - startTime.getTime();
	data = eval('(' + data + ')');
	if(data.code == 0){
		var result = data.result;
		if(typeof result == "undefined" || result.length == 0) return;
		
		for(var i in result){			
			var exId = result[i].auctionId;
			var newSecond = result[i].seconds;
			var newMiSeconds;
			if(interval > 0){
				//newSecond = newSecond - (interval/1000);
				newMiSeconds = (newSecond * 1000) - (interval/2);
			}
			//计算客户端结束时间
			var finishTime = new Date().getTime() + newMiSeconds;
			var finishTimeStr = exId+"_"+finishTime;
			finishArray[finishArray.length] = finishTimeStr;

			refreshPerCountDown(finishTimeStr);
		}
	}

}


var exId,finishTime,seconds;
//刷新单个 已保存客户端结束时间的倒计时
function refreshPerCountDown(finishTimeStr){
	//clearInterval(intervalVar);
	
	var curTime = new Date().getTime();
	exId = finishTimeStr.split("_")[0];
	finishTime = finishTimeStr.split("_")[1];
	seconds = (finishTime - curTime)/1000;
	
	refreshTimer(exId,seconds);	
}


//刷新最新倒计时
function refreshTimer(exId,newSecond){
	
	var intervalname = "interval"+exId;
	var sed = map2.get(intervalname);
	var diff = parseFloat(sed) - parseFloat(newSecond);
	if(sed == null || diff >=1){
		clearInterval(map.get(intervalname));
		timer(newSecond,exId);
	}
}

 

后台:

/**
	 * 获取最新倒计时
	 */
	public void getTimeCountDown(){
		CDO seconds = new CDO();
		
		String auctionIds = request.getParameter("auctionIds");
		if(StringUtils.isBlank(auctionIds)){
			seconds.setStringValue("code", "-1");
	    	ajaxForAction(response,	seconds.toJSON());
	    	return;
		}
			
		cdoRequest.setStringValue(ITransService.SERVICENAME_KEY, "AuctionService");
    	cdoRequest.setStringValue(ITransService.TRANSNAME_KEY, "getTimeCountDown");
    	cdoRequest.setStringValue("auctionIds", auctionIds);
    	Return ret = getServiceBus().handleTrans(cdoRequest, cdoResponse);
    	if(ret.getCode() == 0){
    		if(cdoResponse.exists("cdosExchange")){
    			CDO[] cdos = cdoResponse.getCDOArrayValue("cdosExchange");
        		CDO[] cdosExchange = new CDO[cdos.length];
        		int i = 0;
        		for(CDO cdo : cdos){
        			String dataString = cdo.getStringValue("ex");
        			//if(StringUtils.isBlank(dataString)) continue;
        			
        			String exId = dataString.substring(0,dataString.indexOf("-"));
        			String strTime = dataString.substring(dataString.indexOf("-")+1);
    				long nSecond = DateUtil.getSecond(strTime); 
    				CDO exchangeCdo = new CDO();
    				exchangeCdo.setStringValue("auctionId", exId);
    				exchangeCdo.setLongValue("seconds", nSecond);
    				cdosExchange[i] = exchangeCdo;
    				i++;
        		}
        		if(cdosExchange.length >0){
        			seconds.setCDOArrayValue("result", cdosExchange);
        		}
    		}
    		
    	}
		
    	seconds.setStringValue("code", "0");
    	
    	ajaxForAction(response,	seconds.toJSON());
	}

 SQL:

select CONCAT_WS("-",a.nAuctionId,a.dtEndTime) ex
				 from tbauction a where a.nAuctionId in (

 。。。

 

 

 最新版优化:

最后1分钟或几分钟内,出价后,时间就变为1分钟,直到无人出价为止

参考了西部数码的竞拍,发现以前考虑的太复杂了,哈哈

西部的JS见附件。

注意的点:

出价成功或失败时,提示使用的不是alert弹窗,而是用的jbox。

alert弹窗出现时,若一直不点,则定时器也会暂停,点击后才继续接着执行,这样如果各客户端点击快慢不同,就会导致各客户端最后的倒计时时间不同。而Jbox则不会阻塞JS,使用jbox.tip也更人性化。

 

参考:

setTimeout和setInterval的深入理解

当有非常多的setTimeout和setInterval时,哪种用法效率高?

解决setInterval计时器不准的问题

 

======================================================================

1、setInterval计时器不准的问题(setInterval回调堆积): 在js中如果打算使用setInterval进行倒数,计时等功能,往往是不准确的,因为setInterval的回调函数并不是到时后立即执行,而是等系统计算资源空闲下来后才会执行.而下一次触发时间则是在setInterval回调函数执行完毕之后才开始计时,所以如果setInterval内执行的计算过于耗时,或者有其他耗时任务在执行,setInterval的计时会越来越不准,延迟很厉害.

    

2、setTimeout基于JavaScript运行时内部的事件队列 

 jQuery源码里很多地方都用到了setTimeout(callback)可以去看看。打个比方:

 

   function read_data(){

        read_file();

        write_log();

        //setTimeout(write_log,0);

   }

   read_data();

   show_data();

假设write_log()花费1秒,那么read_data()得多等1秒才能返回,然后show_data()才能把数据展示给用户。但是用户根本不关心你的日志,让用户为此多等1秒其实毫无意义,这种场景就可以用setTimeout(callback,0)来调用write_log,让read_data()立刻返回并将数据展示给用户。node里可以用nextTick,会更快一些。

 

伪异步:

【斩草除根】重新认识所谓的“异步” 

我们知道,js是单线程执行的。事实上setTimeout和setInterval只是简简单单地通过插入代码到代码队列来实现代码的延迟执行(或者说异步执行)。但是事实上所谓的异步只是一个假象——它同样运行在一个线程上! 

那么问题就来了,要是在插入点前的代码执行时间超过了传入setTimeout或setInterval的设定时间会怎样呢?让我们来看看这段代码: 

function fn() { 
	setTimeout(function(){alert('can you see me?');},1000); 
	while(true) {} 
} 

 

你觉得这段代码的执行结果是什么呢?答案是,alert永远不会出现。 

这是为什么呢?因为,while这段代码没有执行完,插入在后面的代码便永远不会执行。 

综上所述,其实JS终归是单线程产物。无论如何“异步”都不可能突破单线程这个障碍。所以许多的“异步调用”(包括Ajax)事实上也只是“伪异步”而已。只要理解了这么一个概念,也许理解setTimeout和setInterval也就不难了。 

 

=============================================================================

概要代码:

 

var leftsecond=0;
var timerobj = null ;

$(function(){	

	//获取需倒计时的兑换产品Id
	var timeIds = [];
	$(".auctTime").each(function(){
		var id = $(this).attr("id");		
		timeIds[timeIds.length] = id;
	})
	
	if(timeIds.length == 0) return;
	startTime = new Date();

	//获取最新时间
	$.get('/auction/getTimeCountDown.html',{ auctionIds: timeIds.join(","),idd : Math.random()},
		function(data) {
			afterGetNewSeconds(data);
		}
	);

	if(state == "2"){
		daojishi();
	}
	
	//window.setInterval(refreshCountDown,10000);
});

///////////////////////////////////////////////////////////////

function timespan(intDiff){
	console.log("intDiff::::::" + intDiff);
	//if(intDiff <= 0) return;
	var day=0,
    hour=0,
    minute=0,
    second=0;//时间默认值       
	if(intDiff > 0){
	    day = Math.floor(intDiff / (60 * 60 * 24));
	    hour = Math.floor(intDiff / (60 * 60)) - (day * 24);
	    minute = Math.floor(intDiff / 60) - (day * 24 * 60) - (hour * 60);
	    second = Math.floor(intDiff) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60);
	}
	hour = day * 24 + hour;
	if (hour <= 9) hour = '0' + hour;
	if (minute <= 9) minute = '0' + minute;
	if (second <= 9) second = '0' + second;
	
	var str = "";
	str += hour + ":";
	str += minute + ":";
	str += second;

	console.log("str:" + str);
	return str;
}

function daojishi(){
	var time = timespan(leftsecond--);
	$("#" + auctionId).text( time );
	clearTimeout(timerobj);
	timerobj = setTimeout("daojishi()",1000)
}


function afterGetNewSeconds(data){	
	endTime = new Date();
	var interval = endTime.getTime() - startTime.getTime();
	data = eval('(' + data + ')');
	//console.log("data=================");
	if(data.code == 0){
		//console.log("data2=================");
		var result = data.result;
		if(typeof result == "undefined" || result.length == 0) return;
		//console.log("data3=================");
		for(var i in result){			
			var exId = result[i].auctionId;
			var newSecond = result[i].seconds;
			
			
			if(parseInt(auctionId) - parseInt(exId) == 0){
				if( Math.abs(newSecond-leftsecond)>=3 ){
					leftsecond = parseInt(newSecond) - 1;	//正负10的情况下才去改变这个数字// 减1是因为网页上timer要延迟一秒
					//console.log("leftsecond=================" + leftsecond);
				}
			}
		}
	}
	
}



function refreshDetailTime(autId,seconds){
	console.log("seconds :" + seconds + ",leftsecond:" + leftsecond);
	if( Math.abs(seconds-leftsecond)>=3 ){
		console.log("refreshDetailTime33====" + leftsecond);
		leftsecond = parseInt(seconds) - 1;	//正负10的情况下才去改变这个数字// 减1是因为网页上timer要延迟一秒
		console.log("refreshDetailTime44  leftsecond====" + leftsecond);
	}
}
 

 

refreshDetailTime 方法为刷出价时,同时刷回来最新的剩余倒计时秒数。

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    元旦倒计时工具-kaic

    元旦倒计时代码+可设置时间+自动计时 元旦倒计时代码+可设置时间+自动计时 元旦倒计时代码+可设置时间+自动计时 元旦倒计时代码+可设置时间+自动计时 元旦倒计时代码+可设置时间+自动计时 元旦倒计时代码+可设置时间...

    倒计时进度条+翻页效果

    倒计时进度条+翻页效果

    PPT倒计时插件+如何在PPT2007内加载宏

    在PPT演示文稿中,有时我们需要添加倒计时功能,以便在演讲、培训或比赛中把握时间。"PPT倒计时插件+如何在PPT2007内加载宏"是一个专为此目的设计的工具,由作者沈兵于2009年12月17日发布。这个加载宏能够方便用户在...

    小程序源码 电商-拼团 倒计时 (代码+截图)

    小程序源码 电商-拼团 倒计时 (代码+截图)小程序源码 电商-拼团 倒计时 (代码+截图)小程序源码 电商-拼团 倒计时 (代码+截图)小程序源码 电商-拼团 倒计时 (代码+截图)小程序源码 电商-拼团 倒计时 (代码+截图)小...

    小程序源码 辩论倒计时 (代码+截图)

    小程序源码 辩论倒计时 (代码+截图)小程序源码 辩论倒计时 (代码+截图)小程序源码 辩论倒计时 (代码+截图)小程序源码 辩论倒计时 (代码+截图)小程序源码 辩论倒计时 (代码+截图)小程序源码 辩论倒计时 (代码+截图)小...

    倒计时器+定时关机+温馨提示

    标题中的“倒计时器+定时关机+温馨提示”揭示了这个软件或程序的主要功能,它包括三个核心部分:倒计时器、定时关机和温馨提醒。这是一款小巧但功能丰富的工具,适用于那些需要时间管理或者自动化电脑操作的用户。 ...

    元旦倒计时代码+HTML+JavaScript

    【标题】:“元旦倒计时代码+HTML+JavaScript”是一个基于HTML、CSS和JavaScript实现的网页应用,用于显示距离下一个元旦的倒计时。这个应用能够帮助用户追踪时间,为庆祝活动做准备。 【HTML】:HTML(HyperText ...

    js倒计时 天+时+分+秒

    JavaScript倒计时是一种常见的网页动态效果,用于显示距离某个特定时间点还有多少天、小时、分钟和秒。在本文中,我们将深入探讨如何使用JavaScript实现一个功能完整的倒计时功能,包括从服务器获取结束时间以及实时...

    商品秒杀倒计时功能+ViewPager实现画廊效果

    在Android应用开发中,"商品秒杀倒计时功能+ViewPager实现画廊效果"是常见的电商应用中的两个重要特性。这两个功能的结合可以为用户提供更丰富的互动体验,增强购物的吸引力。 首先,我们来深入理解商品秒杀倒计时...

    微信小程序——电商-拼团 倒计时(截图+源码).zip

    微信小程序——电商-拼团 倒计时(截图+源码).zip 微信小程序——电商-拼团 倒计时(截图+源码).zip 微信小程序——电商-拼团 倒计时(截图+源码).zip 微信小程序——电商-拼团 倒计时(截图+源码).zip 微信小...

    日期计算、倒计时、天数计算

    日期计算、倒计时以及天数计算是编程领域中常见的功能需求,特别是在日历应用、项目管理、事件提醒等场景中。以下将详细介绍这些概念及其在实际应用中的实现方法。 日期计算涉及到对日期的加减操作,比如计算两个...

    元旦倒计时Mind+开源

    一个简单的倒计时程序。 谁说用图形化编程的一定是垃圾?只要用得好,做出好作品不是吹。 不喜勿喷。 一个简单的倒计时程序。 谁说用图形化编程的一定是垃圾?只要用得好,做出好作品不是吹。 不喜勿喷。 一个简单的...

    易语言倒计时源码+软件+皮肤

    本资源包含的是一个易语言编写的倒计时软件的完整源码、软件成品以及配套的皮肤模块,非常适合初学者学习和研究。 首先,我们来详细探讨易语言倒计时源码的核心知识点: 1. **倒计时功能**:倒计时是程序设计中...

    元旦倒计时代码+(HTML+css+JavaScript + canvas)写的一个 2023 年跨年倒计时代码

    前端语言(HTML+css+JavaScript + canvas)写的一个 2023 年跨年倒计时代码 倒计时日期格式:月-日-时-分-秒 也可以自定义日期格式 自定义添加祝福语等 代码时按照元旦作为计算日期 也可以按照农历新年作为日期格式

    微信小程序——辩论倒计时(截图+源码).zip

    微信小程序——辩论倒计时(截图+源码).zip 微信小程序——辩论倒计时(截图+源码).zip 微信小程序——辩论倒计时(截图+源码).zip 微信小程序——辩论倒计时(截图+源码).zip 微信小程序——辩论倒计时(截图+...

    倒计时html+css+javascript

    通过html+css+javascript写的一个倒计时页面,通过输入分钟和秒数能够倒计时,通过if来判断输入的值得正确性

    Verilog数字钟(自动计时+手动校时+倒计时+整点报时+LCD显示)附完整源代码、详细注释和word报告.zip

    本项目以Verilog为工具,设计并实现了具有自动计时、手动校时、倒计时、闹钟以及整点报时功能的数字钟,并通过LCD显示器进行直观展示。该设计充分利用了Cyclone II FPGA的性能,实现了高度集成和灵活可配置的数字...

    前端开发+JavaScript+倒计时+封装+可执行的HTML模板+实现网页倒计时展示

    无论是招聘网站、商品秒杀还是新年倒计时等,展示网页倒计时的需求都很常见,本示例代码可以帮助开发人员快速实现和调整倒计时效果,从而提高用户体验和网站吸引力。 该代码的使用场景比较灵活,可以在电商、招聘、...

    C# 多线程计时器,倒计时

    可以结合`Task.Delay`来实现异步倒计时,避免阻塞线程。 总之,C#的多线程计时器和倒计时功能是构建高效、实时应用程序的重要组成部分。通过理解这些概念和实践,开发者可以更好地控制程序的执行流程,实现复杂的...

Global site tag (gtag.js) - Google Analytics