Skip to content

web客户端缓存机制

Readme

如果你已经熟悉客户端的缓存机制,可以直接跳过,看最后一节的代码规范。

Bug 场景

比如我们在服务器发布了一个页面:http://domain.com/cate/page.html

在这个页面当中我们引入了一个样式文件 style.css

    <link rel="stylesheet" type="text/css" href="./css/style.css" />

这时候产品经理告诉你,页面需要把背景换成灰色。于是你迅速把修改后的 style.css 交给了发布,等发布的同事说OK了之后你欣喜雀跃的告诉产品:改完了!

产品打开浏览器,刷新了 page.html 并没有看到修改后的效果。

于是你又不得不告诉产品说:Ctrl+F5试试?

如果这是一个移动端页面,那就没有办法给产品经理的iPhone上装一个 Ctrl 和 F5 键了。

问题原因

简单来讲,当你访问一个页面的时候,页面引入的资源(assets)以及页面自身都会被浏览器下载到你自己的电脑上。当你再次访问同一个页面,你电脑的浏览器会先从你电脑中查找上一次的“访问痕迹”,如果有这个文件记录,就不会去服务器请求这个文件。

页面中的图片,音视频,外引js脚本、css文件都会被缓存。

当然,服务器端也会有缓存,这时候通过 Ctrl+F5 就无效了(本文不做讨论)。

为什么要缓存

  1. 用户不需要每次浏览都重新去服务器取文件,为服务器减轻了半数以上的压力。

  2. 从用户角度,大大缩短了网页的加载时间。

缓存规则

问题来了,如果浏览器缓存了文件,服务器文件有了更新,怎么通知浏览器更新文件呢?

1 缓存时效

我们可以在 http 头信息(header)里面设定该文件缓存的有效期。

打开 Chrome 的控制台,查看网络请求,我们会看到如下信息。

image

其中,Expires 和 Cache-Control 字段控制着这个文件在浏览器缓存的失效。Expires 指在这个时间点以前,这个文件缓存都是有效的。Cache-Control 中的 max-age 是说从 Date 字段的时间开始算,43200 秒以内,这个文件缓存是有效的。

Expires 是 HTTP1.0 就有的,max-age 是 HTTP1.1 提出的,所以低版本浏览器不支持 max-age。max-age 比 Expires 更好(因为一个时间长度比写死一个时间点更有灵活性,也更符合“有效期”的逻辑),优先级更高。

Expires 详情

Cache-Control 详情

这两个值在 html 页面中都是可以设置的。在 html 的 meta http-equiv 中可以设置文件的头信息。如:

<meta http-equiv="expires" content="1 Nov 2017" />

我们也可以设置不缓存这个页面,如:

<meta http-equiv="cache-control" content="no-cache">

后端语言在输出 html 的时候也可以设置相应的头信息(header)来控制缓存。下面是一个 JSP 示例:

<%
response.setHeader("expires","sat,6 May 1995 12:00:00 GMT"); //将expire时间设置为一个过去时间或0,-1等
response.setHeader("cache-control","no-store,no-cache,must-revalidadate"); //设置HTTP/1.1 cache-control头
response.addHeader("cache-control", "post-check=0,pre-check=0"); //设置IE 扩展HTTP/1.1 no-cache header
response.setHeader("Pragma", "no-cache"); //设置标准HTTP/1.0 no-cache header
%>

但是如果是其他资源文件(css、img、js等),我们可以通过web服务器配置来设置,比如 Nginx 可以通过在 .conf 文件中设置 Expires。下面代码分别为图片设置30天缓存、为 js 和 css 设置12小时缓存:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    expires      30d;
}

location ~ .*\.(js|css)?$ {
    expires      12h;
}

那么,是不是缓存过期了,浏览器就会去服务器重新请求一份新的文件呢?其实也不是的。当缓存过期,浏览器会携带头信息去与服务器的该文件进行比对。如果有更新,就返回状态码 200,重新请求文件。如果服务器文件没有更新,就会返回状态码 304,浏览器依旧使用缓存中的文件,这样就不需要再从服务器下载一份 http 的主体信息(body)。

2 状态码 304

如果缓存已经过期,浏览器在 Request 的时候,携带 ETag 和 Last-Modified 与服务器的文件进行比对。

image

如果服务器的文件在 Last-Modified(上次修改)之后更新了服务器端的文件,就会重新下载文件主体信息,如果没有修改,服务器返回状态码 304,依旧从缓存读取文件。

ETag 是服务器资源的唯一标识符,比对的优先级高于 Last-Modified。

ETag 详情

无论是 Last-Modified 还是 Etag,可以减少传输成本,但是不会减少 http 请求数,也就是说,服务器的并发数不会少。

另外,前面提到的 Cache-control 中 max-age=0 表示缓存立马过期,请求服务器会返回 304(有缓存的前提)。Cache-Control 值为 no cache 表示总是请求服务器最新文件,不会返回 304。

3 状态码 200

状态码 200 是请求成功,这里不是说服务器请求成功,也包含了从缓存文件请求成功。

在 Chrome 浏览器,我们还会发现,状态码是 200 的文件,也会有 from memory cache(缓存到内存) 和 from disk cache(缓存到本地硬盘) 两种情况:

image

缓存到内存(memory)中的文件,加载的时间几乎是瞬间。

至于 Chrome 如何区分 from memory cache 和 from disk cache,目前我也不知道。

3 为什么 html 页面很少遇到文件不更新的 bug?

我们遇到不更新的 bug 的时候,多数是页面外引的css和js,而页面本身做了修改,只需要刷新一下就可以更新,并不需要 Ctrl+F5 强制刷新。

这是因为点击浏览器的刷新按钮(包括微信浏览器->右上角->刷新),或者新开窗口,或者地址栏敲回车,都会重新请求 html 页面(IE8以下可能有出入,但是刷新按钮肯定会重请求)。

用户基本上已经习惯了刷新按钮,所以 html 极少遇到缓存bug(除非服务器端使用缓存),但是页面引入的其他资源就很难保证及时刷新了。

避免缓存

1 添加后缀

因为浏览器的 http 请求是基于 URL 来的,而且缓存机制不适用于 POST 方法,POST 是不会有缓存的。如果在请求文件的时候添加或修改携带的参数,浏览器就会认为这是一个新的文件,从而不考虑缓存,直接去请求。比如在地址栏请求新的 html 页面:

  • http://domain.com/sample/page.html?201711011801

或者在引入文件的时候使用:

<script src="./bundle.js?20171101114908"></script>
2 ajax

因为 ajax 可以设置头信息,所以在 ajax 中:

xmlHttpRequest.setRequestHeader(“If-modified-since”,”0″);
xmlHttpRequest.setRequestHeader(“Cache-Control”,”no-cache”);

jquery 使用 ajax 方法的时候设置 cache:false。

ajax 中也可以使用随机数参数。

3 后端

response.setHeader(“Cache-Control”,”no-cache,must-revalidate”);

4 POST

最后,因为浏览器的 http 请求是基于 URL 来的,缓存机制不适用于 POST,所以可以用 POST 代替 GET。

缓存负面影响

缓存损坏

image
image
image

有时候我们打开网站会发现页面失去了样式,这种情况多数原因是网络环境差(加载css失败)或者页面错误,也有极少可能是缓存在本地的 css 缓存被损坏了,浏览器使用了本地缓存,但是并不知道缓存已经失效,而是加载了一个无效的缓存文件。
当然,这种情况发生的概率小到可以忽略,就算发生了这种情况,我们可以把解决方案推给用户(用户只需要清除缓存或者使用 Ctrl+F5 强制刷新即可)。

不需要缓存的网站

个人观点认为:多数网站都被建议使用缓存,如果说要挑出一个例外,那应该是适用一条法则:
更新频率大于用户访问频率
比如股票实时行情页面,秒杀页面……用户对于页面数据请求要保持最新,这样就必须要避免数据缓存。

代码规范

因为我们可以用强制刷新(Ctrl+F5),但是用户可能不会。开发人员一旦习惯强制刷新之后,就很容易忽略缓存问题。所以强制刷新不是好习惯,因为不是最大限度模拟用户行为。

  1. 在 html 中引入资源,包括媒体、CSS、JS,如果引入的资源文件是再次发布的,建议添加该文件的版本号(没有约定版本号可以使用时间串),如:
<script src="./bundle.js?20171101114908"></script>
  1. 在移动端,务必这么做。

  2. 额外的,因为 https 越来越成为主流,为了更好兼容,在使用绝对地址引入外部脚本和样式文件,切勿限定协议类型。如:

<script src="http://domain.com/js/foo.js"></script>

应该替换为:

<script src="//domain.com/js/foo.js"></script>

测试环境的临时解决方案

在测试的时候,每次修改一下版本号(随机数)都太麻烦。因为刷新按钮可以每次都去服务器请求文件,所以我们只要将修改的文件直接放到当前浏览器的地址栏,然后刷新一下页面就可以更新了(注意是和html页面同一个浏览器)。移动端也可以直接打开css或js文件的URI地址刷新一下。

相关文章:微信内置浏览器H5如何清除缓存以及 cookie 和 localStorage 何时清除

参考资料:

前端使用WebViewJavascriptBridge实现JS与iOS、Android客户端交互

  1. JS 调用 native 的 handler(JS 发起请求)
window.WebViewJavascriptBridge.callHandler(
    'handlerName',  // 调用 native 的 handler
    data,   // 传数据给 native
    function(res) {
        // 接收 native 返回的数据 res
    }
);
  1. Native 调用 JS 的方法(提供 handler 给 native)
//注册事件监听
function connectWebViewJavascriptBridge(callback) {
  // Android
  if (window.WebViewJavascriptBridge) {
    callback(WebViewJavascriptBridge)
  } else {
    document.addEventListener(
      'WebViewJavascriptBridgeReady',
      function() {
        callback(WebViewJavascriptBridge)
      },
      false
    );
  }

  // iOS
  if (window.WebViewJavascriptBridge) {
    return callback(WebViewJavascriptBridge);
  }
  if (window.WVJBCallbacks) {
    return window.WVJBCallbacks.push(callback);
  }
  window.WVJBCallbacks = [callback];
  var WVJBIframe = document.createElement('iframe');
  WVJBIframe.style.display = 'none';
  WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
  document.documentElement.appendChild(WVJBIframe);
  setTimeout(function(){
    document.documentElement.removeChild(WVJBIframe)
  }, 0);
}

connectWebViewJavascriptBridge(function(bridge) {
  // 注册一个 JavaScript Handler,native 调用时执行 H5 操作
  bridge.registerHandler("handlerName", function(data, responseCallback) {
     // 接收来自 native 的数据 data
     console.log(data);
     // 返回数据给 Native
     var res = "Response Data";
     responseCallback(res);
  });

  // Android初始化,必须
  bridge.init(function(message, responseCallback) {
     // 接收来自 native 的数据 message
     console.log(message);
     // 返回数据给 Native
     var res = "Response Data";
     responseCallback(res);
  });
});

当一个河南人说“都”的时候

“都 dōu”和“就 jiù”这两个字在我们日常中最熟悉不过了,简单到不足以立文以究其文法。

我们平时说话的时候,不需要考虑什么时态啊语法啊,几乎没有人会把这两个用错,更不会把这两个字用混。比如:

“我这都到了。”

语音 1

意思大概是说,老刘啊,我都已经到了,你怎么还不来?

如果是:

“我这就到了。”

语音 2

意思应该是说,老刘啊,我马上就要到了,你再等等。

都,是已完成;就,是即将进行。

但是情况在河南人身上发生了一些微妙的变化,当一个河南人说:

“我这都到了。”

(wō zhè dǒu dào le)

语音 3

他很可能在说:我就要到了。

其实,普通话和河南话在说“我这都到了”的时候,除了口音,语气上也有一些细微的差别。普通话(语音 1)当中,强调“到了”,河南话(语音 3)里面,强调“这”。“都”好像是前面“这”的附属语气词(虽然事实上也应该是后面动作“到”的一个副词)。

一个不说河南话的人和一个河南人面对面交流的时候,加上河南人的口音,可能也发现不了这个问题,但是当大家用文字交流的时候,一个河南人给你发过来“我这都到了”,可能你就会糊涂了。

当然,我们上面提到的所谓普通话,其实也是非常口语化的表达,如果正式一点:

我这都到了。

应该是:

我已经到了。

我这就到了。

应该是:

我马上就到了。

总之,在河南人眼里,“都”很可能是“就”的意思。

当然,在普通话当中,“我这都到了”还有一种可能性,就是重音放在“都”上面:

“我这都~到了”

语音 4

这句话的意思大概是:老刘啊,我这里这些人全部都已经到了,你还来不来?

这个时候的“都”就和时态没有太大关系,而是最基本的意思“全部”。

那么,“都”有多少种意思呢?

(这里,我们只说“都 dōu”字,不谈“都 dū”字。)
1. 全部:我们对你的爱都是满满的。
2. 从“全部”引申出来,与“是”合用表示原因:都是你的错。
3. 强调:1) 你看你来都来了。2) 你吃的比我都多。
4. 如我们前面所说,表示完成:我都到了。
在河南人的字典里应该还有一项:
5. 表示将要进行,同“就”:我马上都来了。

“就”字的意思就更多了

“就”的本意是“去往高处”(动词),比如:老刘就任新一届主席。

“就”除了动词,还可以是介词、连词、语气词,这些应该都是引申自动词“去往”。比如:

  • 介词:就这篇文章来看,你的观点还是不错的。
  • 连词,表示假设或让步:1) 就让他去吧。2) 就算是这样。
  • 语气词(其实我觉得应该是表示态度的副词),比如:我就要这样!

下面我们不考虑“就”作为以上的动词、介词、语气助词,只看它容易和“都”混淆的副词。

“就”作为副词的时候,应该也是引申自“去往”,所以可以表达“即将发生”,比如:春天就要来了。

“就”字在字典有以下释义:

  1. 表示即将发生:我这就到了。(正如我们上面背景交代的例子)
  2. 表示既定的:一个小时之前我就到了。(划重点,这里好像和前面提到的“都”字用法很像!)
  3. 表示事件连续性:我一下课就去了图书馆。(很像连词)
  4. 只:我就一个苹果。
  5. 表示无争议事实:你找的衣服就在桌上。
  6. 表示某种条件下有某种结果:码农不写代码就没有饭吃。(感觉这个像是连词)

上面提到的所有“就”字的副词释义,我觉得有些存有争议,比如 3 和 6 很像是连词,难于作为副词理解。不过我们也发现了,1 和 2 是容易和“都”字混用的。但是我们在平时交流中并没有发现表达、沟通的时候会有难度。因为很多词语在实际使用中,表意性不是很强烈,比如我们说:

“你这件衣服黑难看!”

“黑难看”是什么意思呢?我们看到书面这几个词可能很费解,但是实际说话的时候,如果“黑”字发音比较轻,听者会自动代入一个正确的字把“黑”字替换掉,于是这句话对方得到的信息大概是:

“你这件衣服很难看!”

“你这件衣服还难看!”

只要不是正式沟通场合,这个“黑”字不影响我们交流。这就说明,“黑”字在这个语境中,算是存在感比较弱的,我姑且叫它“表意性”不是很强烈。
上面说了,平时说话我们不会用错,但是一旦这个字成为没有语气的书面文字,就很容易被我们误解。(当然不止这些字,很多话书面表达,不带语气,都可能被阅读者理解成多种意思)。比如:

我一天就写了五行代码。

这句话的意思可能是:

  1. 我今天特别懒,一天只写了五行代码。
  2. 我很牛,仅仅用了一天的时间就写了五行代码。(当然,这个并不牛,所以结合常识,我们不会理解成这句,但是对于那些不知道一个程序员一天正常能写多少代码的人来说,就很容易误解成这句。)

如果你没有和一个讲河南话的人沟通,可能很难理解,他们说“我这都到了”怎么会是“我这就到了”的意思呢?

其实河南人的用法,在普通话当中也可以找到一些痕迹,为了帮助大家更好地体会,我们假设一个场景:

小明从小喜欢打羽毛球,为了响应国家“把爱好变成社会奉献”的号召,小明和他的同学刘穿越在居委会办了一个班,免费教大爷大妈们打羽毛球。这事儿让3号楼的王大爷知道了。王大爷是看着小明长大的,知道小明喜欢打羽毛球,但是他不认识小明的同学刘穿越,不知道刘穿越是不是和小明一样喜欢打羽毛球,就和小明聊天说:“好小伙子!真棒!我说,你那个同学也喜欢打羽毛球?” 这时候小明回答:

“对对对,王大爷,我们都喜欢这个。”

语音 5

小明是想告诉王大爷,他们两个人都是很喜欢打球的,小明喜欢,刘穿越也喜欢。

这事儿5号楼的李大妈也知道了。李大妈不太认识小明,但是李大妈对小明这两人的行为表示高度肯定,就表扬小明说:“好小伙子!真棒!你们花了自己的时间免费教我们,这是做好人好事啊!” 这时候小明回答:

“没什么的李大妈,我们都喜欢这个。”

语音 6

小明是想对李大妈的夸奖谦虚一下,告诉她说两个人就是好这口儿,做好事也是顺带的事情。

后者的“都”其实就是一个表意性不强烈的表达。但是上面这个场景下,主语就不能是单数了。比如只有小明一个人,他就只能说“我就喜欢这个。”而不是“我都喜欢这个。”

我们再回到河南人那里。

场景1:你的一个河南好朋友要出远门了,给你发消息说:

“我这都走了,你不来送送我吗?”

语音 7

意思是他就要走了。

场景2:我们假设他没有发消息给你,你主动问他要不要去送行一下,结果他回复说:

“我这都走了,你还来干么?”

语音 8

意思是他已经走了。

这两个送行场景,放到普通话里面,其实也都是说的通的。

场景1普通话版:

“我这都走了,你不来送送我吗?”

语音 9

普通话里这个“都”不是“就要”的意思,而是强调,这句话其实应该是这样的:

“我都要走了,你不来送送我吗?”

上面那句省略了“要”,加了口语化的助词“这”,这里“都”的意思是强调后面“要走”,但这个“都”也可以理解成“已经”。如果把“都”当做“已经”来讲,就是“我已经要走了”,虽然是将要发生的事情,但是是既定的事情,其实“已经”的意思也是强调,强调他要走的事实。汉语真的是博大精深啊!
场景2的普通话版就好理解了,“我这都走了,你还来干么?”符合我们日常表达习惯。

语音 10

如果我们把这两个字连起来用会怎么样?

你大学室友要结婚了,在群里问你们几个室友能不能及时参加婚礼,张三能不能赶到?李四呢?刘穿越呢?你在群里替大家回复说:

“等你结婚那天,我们都就到了。”

语音 11

意思是你替大家担保能赶到。你还可以说:

“等你结婚那天,我们就都到了。”

语音 12

意思其实相差不大,甚至没有区别。前者强调全部,不会有人不到。后者强调会及时到场,是对结婚那天这个假定条件的结果。

好的,以上就是全部。

另外的,我觉得“都”表示“全部”的时候也很有趣,这个字其实是连接了两个复数对象。比如:

“我们都喜欢你。”

主语“我们”是复数,宾语“你”是单数。

“我都喜欢。”

这里省略了宾语,“我”喜欢什么呢?喜欢的对象可能是“苹果和梨”:

“苹果和梨,我都喜欢。”

这时候宾语前置了,而且必须前置,如果说“我都喜欢苹果和梨”就会怪怪的。

“都”连接的两个对象,主语“我”是单数,宾语“苹果和梨”是复数。
上面两个例子说明,“都”连接的两个对象只要有一个是复数就可以了,而且,宾语是复数的时候,必须是有区别的。苹果和梨是有区别的,如果说:

“这两个苹果,我都喜欢。”

那这两个苹果肯定也是有不同的地方,不然就没法用“都”字了。

看完此文,是不是觉得不会说话了?

在电脑上通过Chrome调试安卓手机app中的webview以及移动端页面

如果需要调试 iOS 设备,移步这里

本文基于 Windows 10 操作系统,Mac OS 尚未实践


背景

如果我们开发一个移动端的网页,调试的时候我们可以在 Chrome 的 DevTools 中选择移动设备(Toggle device toolbar)。但是如果我们开发的是一个手机 app 内置的 webview 页面,或者想把网页放在真机中调试,则需要本文中的方法。

特别注意

首次调试可能要求翻墙。

在电脑上调试iOS设备webview以及iOS移动端页面

本文尚未完成。

Chrome内部协议

https://www.cnblogs.com/highsea90/p/4269801.html

  1. chrome://flags
    可用来启用或者关闭某些 chrome 的体验特性
  2. chrome://dns
    该命令将显示浏览器预抓取的主机名列表
  3. chrome://downloads
    该命令同时也可以从菜单中的下载来访问,其快捷键是 Ctrl + J
  4. chrome://extensions
    该命令等同于菜单 – 工具 – 扩展
  5. chrome://bookmarks
    改名了等同于菜单-书签-书签管理器,快捷键 Ctrl+Shift+O
  6. chrome://history
    该命令可从菜单-历史直接访问,快捷键 Ctrl+H
  7. chrome://memory
    该命令将重定向到 “chrome://memory-redirect/”. 它将显示浏览器使用内存的情况,以及系统中运行的其他浏览器,包括 firefox。同时还显示浏览器进程的详细信息。
  8. chrome://net-internals
    该命令显示网络相关信息,用来捕获浏览器生成的网络事件,可导出数据,可查看DNS主机解析缓存。
    其中一个很重要的功能就是“测试”,如果你无法访问某个网址,那么可以使用 “chrome://net-internals” -> 点击“Tests” tab -> 输入网址,并点击开始测试,Chrome 将报告具体的问题所在。
  9. chrome://quota-internals
    该命令用来显示浏览器所使用磁盘空间配额的情况。
  10. chrome://sessions
    该命令用来显示当前运行的浏览器的会话信息数以及详细列表
  11. chrome://settings
    该命令可通过菜单-选项直接访问,可用来控制浏览器各项设置值
  12. chrome://sync-internals
    用来显示 chrome 的同步状态
    最后,如果你想查看 chrome 所有的命令,可使用 chrome://about/

JavaScript需要特别注意的地方

1 转换

parseInt(0.000001)  // 0
parseInt(0.0000001)  // 1

'5' == 5  // true

2 null

typeof null  // "object"

null == undefined  // true

10 + null  // 10
10 + undefined  // NaN

3 NaN

typeof NaN  // "number"

NaN == NaN  // false

isNaN('blue')  // true

4 Boolean

false == 0  // true
true == 1  // true
true == 2  // false
undefined 

小程序能力汇总

1 入口

  • 扫码或识别二维码(可以进入指定小程序指定某页面)
  • 分享到群/好友(可以进入指定小程序指定某页面)
  • 微信搜索框(搜索指定小程序,进入默认首页)
  • 微信首页下拉界面(进入最近使用过的小程序默认首页)
  • 关联公众号菜单(进入指定小程序)
  • 推送给用户的模板消息(指定小程序)
  • 同公众号的其他关联小程序(可以进入指定小程序指定某页面)
  • App(详见 与 app 交互)
  • 公众号文章底部广告位(需投放)
  • 手机QQ浏览器(可以搜索小程序,但是目前不能搜到所有的小程序)

2 基础功能

  • 录音(10分钟)、拍照、扫码、录像、播放音视频(后台播放音频),可保存图片、视频到手机
  • 获取用户头像、昵称,统一主体的不同小程序可以识别同一用户
  • 获取运动步数(最近30天)
  • 购买支付(需要认证)
  • 系统硬件接口:定位、系统信息、网络状态、罗盘、拨打电话、扫码、剪贴板、蓝牙、iBeacon、屏幕亮度、监听用户主动截屏、振动、手机联系人、NFC、WIFI

3 其他功能

  • 支持直播
  • 内嵌 H5:H5 和小程序可以相互跳转,两者可以相互通信,H5 页面中可以实现的功能可以简单的理解为与微信内置 H5 类似。
  • 同一主体的不同小程序之间可以相互跳转
  • 卡券

4 分享转发功能

  • 小程序可以转发给好友/群,不能转发到朋友圈以及其他任何渠道。
  • 可以使用右上角“…”转发,也可以在小程序页面上放置按钮转发。
  • 转发的时候可以自定义转发到聊天窗口的小程序卡片的标题、图片、描述。
  • 微信用户点击转发出去的小程序卡片,可以进入小程序中任意指定的某页面,并非必须是触发转发的页面。

5 与 app 交互

  • 从 app 分享到微信,微信用户可以直接点击分享打开小程序。
  • 从 app 分享到微信,打开小程序以后,可以通过点击小程序页面的按钮跳转到分享来源的 app。

6 其他

  • 支持小游戏开发
  • 支持快捷切换
  • 支持微信小店
  • 可以关联公众号500个
  • 支付后可以提示用户关注关联公众号
  • 支持指纹(有指纹识别的手机、以后或将开放人脸识别和声纹识别)
  • 获取用户保存的发票抬头
  • 获取微信用户在微信保存的地址信息
  • 附近的小程序,5KM 以内。
  • 关联公众号
  • 支持查看小程序新增或活跃用户的性别、年龄、地区、手机设备

7 开发

  • 可以使用小程序插件,开发者工具“代码片段”功能
  • 支持 ES6

8 官方示例小程序,可以看一下下方导航的“接口”部分。

image

JavaScript截取字符串slice()、substr()、substring()的区别

共同点

第二个参数都可以省略,省略以后都是截取到字符串最后。

区别

第一个参数
  • substring() 不能为负数
  • substr() 可以是负数,是负数从尾部开始计算
  • slice() 可以是负数,是负数从尾部开始计算
第二个参数
  • substring() 不能为负数,终点的位置,需要大于第一个参数
  • substr() 不能为负数,截取的长度
  • slice() 可以是负数,终点的位置,是负数从尾部开始计算

Markdown文件工具

1 手册

2 编辑器

  • 2.1 推荐:有道云笔记,多平台客户端,我正在用。

  • 2.2 马克飞象 在线编辑器,带公式和流程图,为印象笔记(Evernote)打造的Markdown编辑器

  • 2.3 DILLINGER 在线编辑器

  • 2.4 Mou Mac系统编辑器

  • 2.5 https://stackedit.io/

  • 2.6 https://hackmd.io/

3 格式转换

  • 3.1 WXMarkdown,微信公众号格式化工具

  • 3.2 Pandoc 提供多种格式的相互转换

  • 3.3 推荐:MDwiki,直接将markdown转为html网站,非常方便。

4 其他

码字必备:18 款优秀的 Markdown 写作工具 | 2015 年度盘点


TOP