Javascript--离线运用与客户端贮存

开辟离线Web运用须要几个步骤:

  1. 起首确保运用晓得装备是不是能上网。

  2. 运用必需能接见肯定的资本(图象,Javascript,CSS),如许才平常事情。

离线检测

navigator.onLine

HTML5新定义的属性,这个属性值为true示意装备能上网,值为false示意离线装备。这个属性的关键是阅读器必需晓得装备可否接见收集,从而返回准确的值。

相干事宜范例:online和offline

HTML5还定义了两个事宜:online和offline。

当收集从离线变成在线或许从在线变成离线,离别触发著两个事宜。

兼容性

运用缓存

HTML5的运用缓存,或许简称为appcache,是特地为开辟离线Web运用而设想的。Appcache就是从阅读器缓存平分出来的一块缓存区。

要想在这个缓存中保留数据,能够运用一个形貌文件(manifest file),列出要下载和缓存的资本。即运用户在离线状况下按了革新按钮,您的运用也会平常加载和运转。

运用缓存接口可为您的运用带来以下三个上风:

  • 离线阅读 – 用户可在离线时阅读您的完全网站

  • 速率 – 缓存资本为当地资本,因而加载速率较快。

  • 服务器负载更少 – 阅读器只会从发作了变动的服务器下载资本。

清单文件

清单文件必需以 text/cache-manifest MIME 范例供应

清单文件花样
CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
login.php
/myapi
http://api.twitter.com

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
*.html /offline.html

清单可包括以下三个差别部份:CACHE、NETWORK 和 FALLBACK。

  1. CACHE: 这是条目的默许部份。体系会在初次下载此标头下列出的文件(或紧跟在 CACHE MANIFEST 后的文件)后显式缓存这些文件。

  2. NETWORK:
    此部份下列出的文件是须要衔接到服务器的白名单资本。不管用户是不是处于离线状况,对这些资本的一切请求都邑绕过缓存。可运用通配符。

  3. FALLBACK:
    此部份是可选的,用于指定没法接见资本时的后备网页。个中第一个 URI 代表资本,第二个代表后备网页。两个 URI 必需相干,而且必需与清单文件同源。可运用通配符。

NOTE这些部份可按恣意顺序排列,且每一个部份均可在统一清单中反复涌现。

援用清单文件
<html manifest="example.appcache">
  ...
</html>

NOTE:

  • CACHE MANIFEST 字符串应在第一行,且必不可少。

  • 网站的缓存数据量不得凌驾 5 MB。

  • HTTP 缓存标头以及对经由历程 SSL 供应的网页设置的缓存限定将被替换为缓存清单(也就是加了密的网站Are https URLs encrypted)。因而,经由历程 https 供应的网页可完成离线运转。

  • 假如您要编写的是针对 Chrome 网上运用店的运用,可运用 unlimitedStorage 作废该限定。
    假如清单文件或个中指定的资本没法下载,就没法举行全部缓存更新历程。在这类情况下,阅读器将继承运用原运用缓存。

applicationCache对象

applicationCache对象有一个status属性,属性的值是常量,示意运用缓存的状况。

applicationCache.status

  • 0:无缓存,即没有与页面相干的运用缓存

  • 1:闲置,即运用缓存未取得更新

  • 2:搜检中,即正在下载形貌文件并搜检更新

  • 3:下载中,即运用缓存正在下载形貌文件中指定的资本

  • 4:更新完成,即运用缓存已更新了资本,而且一切资本都已下载终了,能够经由历程swapCache()来运用了

  • 5:烧毁,即运用缓存的形貌文件已不存在了,因而页面没法再接见运用缓存

相干事宜范例

  • checking:在阅读器为运用缓存查找更新时触发

  • error:在搜检更新或下载资本时期发作错误时触发

  • noupdate:在搜检形貌文件无变化时集约

  • downloading:在最先下载运用缓存时资本时触发

  • progress:在文件下载运用缓存资本时集约

  • updateready:在页面新的运用缓存下载终了,而且能够经由历程swapCache()时触发。

兼容性

Cookie

HTTP cookie,平常叫做cookie,最初是在客户端用于存储会话信息的。该范例请求服务器的恣意HTTP请求发送Set-Cookie HTTP头部作为相应的一部份,个中包括会话信息。

// HTTP相应
HTTP/1.1 200 OK
Content-type: text/html
Set-cookie: name=value
Other-header: other-header-value 

// HTTP请求
GET /index.html HTTP/1.1
Cookie: name=value
Other-header: other-header-value

第一段会话历程
服务器:设置name=value的cookie,并将其作为相应头部的一部份,发送给阅读器。
阅读器:贮存name=value的cookie并将其作为请求头的一部份,发送给服务器。

NOTE:

  1. 会话历程的称号和值都是经由URL编码的。

  2. 每一个域的cookie总数是有限的,差别阅读器之间各有差别。当凌驾单个域名限定以后另有再设置cookie,阅读器就会消灭之前的cookie。

  3. cookie在性子上是绑定在特定域名下的。当设定一个cookie后,再给建立它的域名发送请求时,都邑包括这个cookie。

cookie组织

// HTTP相应
HTTP/1.1 200 OK
Content-type: text/html
Set-cookie: name=value; expires=Mon, 22-JAN-07 07:10:24 GMT; domain=.wrox.com;path=/;secure
Other-header: other-header-value 

// HTTP请求
GET /index.html HTTP/1.1
Cookie: name=value
Other-header: other-header-value
  • 称号(name):一个唯一肯定cookie的称号,cookie的称号必需是经由 URL编码的。

  • 值(value):贮存在cookie的字符串值,值必需被 URL编码

  • 域:cookie关于谁人域是有用的。一切向该域发送的请求中都邑包括这个cookie信息。假如没有明白设定,那末这个域会被认作来自设置cookie的谁人域。

  • 门路:关于指定域中的谁人门路,应当向服务器发送cookie

  • 失效时刻:示意cookie应当被删除的谁人时刻戳

  • 平安标志:指定后,cookie只能在SSL的衔接时,才发送到服务器

第二段会话历程
服务器:设置name=value的cookie,同时通知阅读器

  1. 它会在格林威治时刻2007年1月22日7:20:24失效。

  2. 关于一切wrox.com的子域和域名下(由path参数指定的)都有用

  3. 同时经由历程SSL衔接才传输。
    并将其作为相应头部的一部份,发送给阅读器。

阅读器:贮存name=value的cookie并将其作为请求头的一部份,发送给服务器。

Note:后四个,域/门路/失效时刻/平安标志都是 服务器给阅读器的指导。以指定什么时刻该发送cookie。这些参数并不会作为发送到服务器的标志,名值对才会被发送。只需cookie的名字和值是必需的。

document.cookie

用来猎取属性值时,document.cookie返回当前页面可用的(依据cookie的域,门路,失效时刻和平安设置)一切的cookie的字符串。

[]()

当用来设置值得时刻,document.cookie能够用来设置新的cookie字符串。这个cookie字符串会用来诠释并添加到现有的cookie中。设置的值并不会掩盖cookie,除非设置的值已存在。

var cookieUtil = {

    get: function ( name ) {

        var cookieName = encodeURIComponent( name ) + '=',
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null;

        if( cookieStart > -1 ) {
            var cookieEnd = document.cookie.indexOf(';',cookieStart);
            if( cookieEnd === -1 ) {
                cookieEnd = document.length;
            }
            cookieValue = decodeURIComponent( document.cookie ).substring(cookieStart+cookieName.length, cookieEnd)
        }

        return cookieValue;
    },
    
    set: function ( name, value, expires, path, domain, secure ) {
        var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value);

        if( expires instanceof Date ) {
            cookieText += "; expires=" + expires.toGMTString();
        }

        if( path ) {
            cookieText += '; path=' + path; 
        }

        if( domain ) {
            cookieText += '; domain=' + domain;
        }

        if( secure ) {
            cookieText += '; secure';
        }

        document.cookie = cookieText;
    },

    unset: function ( name, path, domain, secure ) {

        this.set( name, '' , new Date(0), path, domain, secure)
    }
}

子cookie

为了绕开 阅读器 的单域名下的cookie数限定,一种开辟人员运用了一种称为子cookie(subcookie)的观点。子cookie是寄存在单个cookie中的更小段的数据。也就是运用cookie值来贮存多个称号值对儿。

子cookie平常以查询字符串的花样举行花样化。然后这些值能够运用单个cookie举行贮存和接见
name=name1=value1&name2=value2&name3=value3

上面展现了如何写入,读取和删除cookie,下面展现操纵子cookie的要领。

var SubCookieUtil = {

    get: function ( name, subName ) {

        var cookieValue = this.getAll( name );

        if( subName ) {

            return result[subName];
        }
        else {

            return null;
        }
    },

    getAll: function ( name ) {

        var cookieName  = encodeURIComponent( name ) + '=',
            cookieStart = document.cookie.indexOf( cookieName ),
            cookieValue = null,
            cookieEnd,
            result      = {};

        if( cookieStart > -1 ) {

            cookieEnd = document.cookie.indexOf( ';', cookieStart );

            if( cookieEnd === -1 ) {

                cookieEnd = document.cookie.length;
            }
        }

        cookieValue = document.cookie.substring( cookieStart+cookieName.length, cookieEnd );

        decodeURIComponent( cookieValue );

        if( cookieValue.length > 0 ) {

            subCookies = cookieValue.split( '&' );

            for( var i = 0; i < subCookies.length; i++  ) {

                var parts = subCookies[i].split( '=' );

                result[parts[0]] = parts[1];

            }

            return result;
        }
        else {

            return null;
        }
    },

    set: function ( name, subName, value, expires, path, domain, secure ) {

        var subCookies = this.getAll( name ) || {};

        subCookies[subName] = value;
        this.setAll( name, subCookies, expires, path, domain, secure );
    },

    setAll: function ( name, subCookies, expires, path, domain, secure ) {

        var cookieText = encodeURIComponent( name ) + '=',
            subCookiesParts = [],
            subName;

        for( subName in subCookies ) {

            if( subCookies.hasOwnProperty( subName ) ) {

                subCookiesParts.push( encodeURIComponent(subName) + '=' + encodeURIComponent(subCookies[subName]) );
            }
        }

        if( subCookiesParts.length > 0 ) {

            cookieText += subCookiesParts.join('&');

            if( expires instanceof Date ) {

                cookieText += '; expires=' + expires.toGMTString(); 
            }

            if( path ) {

                cookieText += '; path=' + path;
            }

            if( domain ) {

                cookieText += '; domain=' + domain;
            }

            if( secure ) {

                cookieText += '; secure'
            }

        } else {

            cookieText += '; expires=' + (new Date(0).toGMTString());
        }


        document.cookie = cookieText;

    },

    unsetAll: function ( name, subCookies, expires, path, domain, secure ) {

        this.set( name, null, new Date(0), path, domain, secure );
    },

    unset: function ( name, subName, expires, path, domain, secure ) {

        var subCookies = this.get( name );

        if( subCookies ) {

            delete subCookies[subName]
            this.setAll( name, subCookies, expires, path, domain, secure );
        }

    }
}

关于cookie的机能与平安

  1. 由于一切的cookie都邑由阅读器作为请求头发送,所以在cookie中存储大批信息会影响到特定域的请求机能。cookie信息越大,完成对服务器请求的时刻也就越长。

  2. cookie数据并不是存储在一个平安环境中,个中包括的任何数据都可被别人接见。所以肯定不要在cookie中贮存重要和敏感的数据。

IE用户数据

在IE5.0中,微软经由历程一个自定义行动引入了耐久化用户数据的观点。用户数据许可每一个文档最多128KB数据,每一个域名最多1MB数据。要运用耐久化用户数据,起首,必需以下所示,运用CSS在某个元素上指定userData行动。

`<div style="behavior:url(#default#userData)" id="dataStore"></div>`
var dataStore = getElementById('dataStore');
// 写入数据
dataStore.setAttribute('name','Nicholas');
dataStore.setAttribute('book','Professional Javascript');
dataStore.save('BookInfo');

// 猎取数据
dataStore.load('BookInfo'); 
// 接见数据
console.log(dataStore.getAttribute('name'));
console.log(dataStor.getAttribute('book'));

// 删除数据
dataStore.removeAttribute( 'name' );
dataStore.removeAttribute( 'book' );
dataStore.save('BookInfo');

Note:

  • 和cookie一样,IE用户数据并不是平安的,一切不能寄存敏感信息。

  • 用户数据默许是能够逾越会话耐久存在的,同时也不会逾期

  • 要接见某个数据空间,剧本运转的页面必需来自于统一个域名,门路并运用与举行存储的剧本一样的协定。

Web存储机制

Web Storage的两个重要目的是

  • 供应一种在cookie以外存储会话数据的门路

  • 供应一种存储大批能够跨会话存在的数据的机制。

兼容性

Note:与其他客户端贮存计划比拟,WebStorage一样也有限定,这些限定因阅读器围而异。平常来说,对存储空间大小的限定都是以每一个泉源(协定,域名,端口号)为单元的。换句话说,每一个泉源都要牢固大小的空间用于保留本身的数据。考虑到这个限定,就要注重剖析和掌握每一个泉源中有若干页面须要保留数据。

webStorage限定测试

Storage范例

Storage供应最大的空间(因阅读器而异)来贮存名值对。

sessionStorage instanceof Storage // true
localStorage instanceof Storage// true

localStorage.__proto__ === Storage.prototype // true
sessionStorage.__proto__ === Storage.prototype // true

由上可知,sessionStorage对象localStorage对象都为Storge范例的实例。因而它们都能够接见到Storage范例的原型对象上的要领。有以下这些要领。

  • clear():删除一切值;Firefox中没有完成

  • getItem(name):依据指定的名字name猎取对应的值

  • key(index):取得index位置处的值得名字

  • removeItem(name):删除由name指定的名值对

  • setItem(nname, value):为指定的name设置一个对应的值

同时能够运用length属性推断Storage对象中有若干名值对。但没法推断对象中一切数据的大小,不过IE8供应了一个remainingSpace属性,用于猎取还能够运用的存储空间的字节数。

Note:Storge范例只能存储字符串。非字符串的数据在存储之前会被转换为字符串。

sessionStorage对象

为每一个给定的源(given origin)坚持一个自力的存储地区,该存储地区在页面会话时期可用(即只需阅读器处于翻开状况,包括页面从新加载和恢复)。

sessionStorage对象重要用于仅针对会话的小段数据的存储。它贮存特定于某个会话的数据,也就是该数据只坚持到阅读器封闭。这个对象就像会话cookie,也会在阅读器封闭后消逝。

  1. 存储在sessionStorage中的数据能够逾越页面而存在,同时假如阅读器支撑,阅读器崩溃重启后依旧可用(Firefox和Webkit都支撑,IE不可)。

  2. sessionStorage对象绑定于某个服务器会话,一切当文件在当地运转的时刻是不可用的。

  3. 存储在sessionStorage的数据只能由最初给对象贮存数据的的页面接见到,所以对多页面运用有限定。

// 写入数据
sessionStorage.setItem( 'name', 'Nicholas' );

// 接见数据
sessionStorage.getItem( 'name' );

// 迭代数据
for( var i = 0,len = sessionStorage.length; i < len; i++ ) {
    
    var key = sessionStorge.key( i );
    var value = sessionStorage.getItem( key );
    console.log( key + '=' + value );
}
for(key in sessionStorage) {

    var value = sessionStorage.getItem( key );
    console.log( key + '=' + value );
}

// 删除数据
sessionStorage.removeItem( 'name' );

Note:差别阅读器写入数据的要领略有差别。Firefox和Webkit完成了同步写入,一切添加到贮存空间的数据是马上被提交的。而IE的完成是异步写入数据,所以在设置数据和将数据写入磁盘之间可能有一些耽误。关于少许数据而言,这个差别是能够疏忽的。关于大批数据,你会发明IE比其他阅读器更快的恢复实行,由于它会跳过现实的磁盘写入历程。
在IE8中可强迫把数据写入磁盘,以下。

// 防备代码实行的时刻,不会发作其他磁盘写入操纵
sessionStorage.begin();

sessionStorage.name = 'Nicholas';

// 确保name的值在挪用commit()以后马上写入磁盘
sessionStorage.commit();

localStorage对象

localStorage 一样的功用,但是在阅读器封闭,然后从新翻开后数据依然存在。

localStorage完成逾越会话存储数据,在HTML5范例中作为耐久保留客户端数据的计划庖代了globalStorage。
划定规矩:要接见统一个localStorage对象,页面必需来自于统一个域名(子域名无效),运用统一种协定,在统一个端口上。

由于localStorage是Storage的实例,一切能够像运用sessionStorage一样来运用它。

storage事宜

对Storage对象举行任何修正,都邑在文档上触发storage事宜。

storge事宜对象

  • domain:发作变化的贮存空间的域名

  • key:设置或许删除的键名

  • newVaule:假如是设置值,则为新值;假如是删除键,则为null

  • oldValue:键被变动之前的值

    原文作者:Murphywuwu
    原文地址: https://segmentfault.com/a/1190000004564178
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞