今天做项目时遇上一个需求,当浏览器或页面关闭时将数据存储到数据库内。实现思想是采用js监测onunload然后发送请求。结果失败,刷新可以发送但是关闭并不能,整了一整天并没有解决,最后找到了解决办法。

先贴个能实现功能的方法:

function saveStatus(){
    /*结束时保存设备状态*/
    window.onbeforeunload=function(){//必须使用beforeunload
        var url ="device_saveDeviceStatus";
        $.ajax({
            url:url,
            async:false                //必须采用同步方法
        });
    }
}
saveStatus();

接下来来解释一下:

  1.一开始的想法是采用onunload方法,但最后经过查询,需要使用onbeforeunload方法。它们之间的区别在于:onbeforeunload是正要去服务器读取新的页面时调用,此时还没开始读取;而onunload则已经从服务器上读到了需要加载的新的页面,在即将替换掉当前页面时调用。onunload是无法阻止页面的更新和关闭的。而 onbeforeunload 可以做到。

  2.在发送请求上,一开始采用简单的$.post(),但是$.post()是异步的方法,不行。为什么这里不能采用异步方法呢?我的理解是,如果采用异步方法,那么浏览器会在方法成功发送并响应前先unload,从而导致请求丢失。如果采用的是同步方法,浏览器就会等待请求成功,然后再unload。按照这个理解,如果采用异步方法发送后,再采用alert()进行拦截等待,应该也是可以的,只是这个方法太影响体验,所以抛弃。

      但是onbeforeunload有个小毛病,就是页面刷新时,他还是会调用到onbeforeunload,为什么?其实刷新就相当于关闭了这个IE再重新打开的意思,因此还是会调用到onbeforeunload。
究竟怎么解决刷新不调用onbeforeunload呢?网上提供很多方法,本人觉得最实用还是以下这段JS

window.onbeforeunload = function(){   
      var n = window.event.screenX - window.screenLeft;   
      var b = n > document.documentElement.scrollWidth-20;   
      if(b && window.event.clientY<0 || window.event.altKey)   
      {   
          alert("是关闭而非刷新");   
          window.event.returnValue = "是否关闭?";
      }else{
          alert("是刷新而非关闭");   
      }   
}

  附:提供一个替代的想法,在j2ee开发中,可以采用监听器监听session的销毁事件,达到类似的效果。