伪随机的种子问题

Posted on

最近前端的工作不是很多,所以就帮忙写写后端的ruby on rails。在写测试用例的时候,虽然单元测试的数据每次都是随机生成的,但是我们需要根据单元测试来生成API文档。如果测试文档每次都是随机的数据会很难检查每次API更新了什么,所以我们需要在生产测试文档的时候,保证随机数据的稳定性。

Random seed

seed的意义就在于,初始化了随机数生成器。保证了每次随机的结果都一样。例如代码:

@rand = Random.new(1234)

puts @rand.rand

puts @rand.rand(0..1050)

puts @rand.rand(0..1050)

puts @rand.rand

这段代码每次执行都会输出:

0.1915194503788923
674
699
0.2725926052826416

rand range

但是当我们把中间的rand的范围稍微修改:

@rand = Random.new(1234)

puts @rand.rand

puts @rand.rand(10..150)

puts @rand.rand(10..150)

puts @rand.rand

会发现输出发生了变化:

0.1915194503788923
48
63
0.4377277390071145

第一次的输出还是不变,当然2,3两次肯定是变化的,重点是最后一次。我们发现最后一次的随机数也发生了变化。

总结

通过调查ruby源码发现,对于有范围的rand。ruby会不断生成随机数,判断是否落在区间范围内,如果是在范围内就返回,否则继续尝试。默认在0到1之间是百分百命中,所以是随机一次。如果是其他范围,命中次数不一样会导致生成随机数的次数发生变化。所以影响到之后的随机数生成。

参考:

ruby

Random

Web离线的解决方案

Posted on

最近的工作是做嵌入在IOS程序内部的页面,其中有一个需求就是需要满足在离线的情况下显示页面。当然,现在主流的离线方式是使用Service Worker来完成离线需求。 但是IOS内置的WKWebView并不支持最新的Service Worker(取决于IOS版本)最新版本已经支持,所以不得不想办法来解决。

Application Cache

AppCache是一个过时的技术,但是在IOS下勉强还能用。不过Chrome对这种过时的技术支持不是很好,单个缓存文件最大只支持5MB。而且还有请求的BUG:Accept header on GET request for appcache manifest。触发AppCache是在html标签中添加manifest属性。

<html manifest="manifest.appcache">
  ...
</html>

通过manifest.appcache文件来定义需要缓存的文件,不过载入manifest.appcache的页面会被作为Master entries缓存起来。因为AppCache出现的时候还是以静态网站为主,所以并不能缓存请求的Ajax数据。我们需要自己再手动实现缓存所有请求在localStorage,但是localStorage同样也有最大5MB的限制。所以也需要考虑相应的解决方案。不过,我最终采取的方式是通过嵌入iframe来实现触发AppCache,这样做的好处是因为SPA应用是自己来控制路由的,所以导致每个路径都会保存一份Master entries。但是通过iframe的话,我们的Master entries永远只有一份。并且当前页面的所有资源也被顺利缓存,因为SPA无论访问哪个路径返回的都是相同的index.html。由JS来控制路由并加载相应的组件。

这里要补充的一点是,针对https的Application Cache是无法完成跨域请求的,所以请慎重。

WorkBox

Service Worker是现在主流的缓存技术,会帮你缓存所有的静态文件和数据请求。但是对于SPA项目,我们不可能自己手动书写缓存清单。所以还是借助现有的开源解决方案,这里最出名的解决方案是谷歌的Workbox。通过使用Webpack插件和简单的配置,我们便可以做到缓存所有的静态资源和数据。Service Worker有很多种缓存策略可以选择,例如Cache First和NetWork First。但是AppCache每次都会优先使用缓存,然后再去更新最新的文件。所以我们不得不在发生更新的时候去重新加载页面。

总结

最终的解决方案是优先使用Service Worker,当不支持Service Worker的时候再回退到AppCache。但是想要从AppCache升级到Service Worker的时候,必须清除所有AppCache的所有数据。浏览器并没有提供相应的接口,我们目前采用的方式是手动删除AppCache储存的数据库来完成这一需求。

参考:

Using the application cache

HTML5 Offline Application Cache

Application Cache plugin for Webpack

Workbox webpack Plugins

Appcache Facts

如何封装第三方vue组件

Posted on

终于算是正式接触SPA的前端工作了,最近在解决很多Vue组件的问题,其中就有一个针对第三方组件的定制化需求,花了不少时间来折腾。

解决v-model绑定

这次封装的就是element的前端vue框架,因为框架本身对IOS兼容性不好,所以需要二次封装。封装的是一个select组件。所以需要数据的双向绑定,官方教程也已经解释了。 v-model 本质上就是绑定一个值和监听相应的事件。 这次本质是封装的一个input元素,所以我们需要手动绑定value和监听事件。

<template>
  <el-select
    v-bind:value="value"
    v-on="$listeners">
  </el-select>
</template>

官方文档也解释了这个内置变量的用法vm-listeners

继承父元素的属性

父元素的属性继承可以使用v-bind="$attrs"来完成。所以完成组建的透明封装只需要加上三个指令。

<template>
  <el-select
    v-bind="$attrs"
    v-bind:value="value"
    v-on="$listeners">
  </el-select>
</template>

虽然知道答案之后很简单,但是探索的过程中还是比较花时间的。希望能帮助大家解决这个问题,如果有什么疏漏之处,也请大家指正。