admin 发布于 08月18, 2016

【译】JavaScript中该如何安排后台任务

原文:http://www.zcfy.cc/article/258

关于JavaScript,大家要牢记一点:它阻塞

想象一下,浏览器里有一个进程小精灵,负责处理一切。渲染HTML、响应菜单命令、绘制屏幕、处理鼠标点击、运行JavaScript函数……。跟我们人一样,这个小精灵每次只能做一件事。如果一次交给它很多任务,那么就会有一个待办事项列表,小精灵按顺序一项一项去处理。

小精灵在碰到script标签或者要运行JavaScript函数时,会停下其他任务。下载代码(必要时)然后立即运行,之后才会触发其他事件 ,以及渲染页面。这是必要的,因为脚本几乎什么都可能做:加载更多代码、删除DOM元素、重定向URL,等等。就算有两个甚至更多小精灵,那其他小精灵也需要在首次处理代码时停下来。这就是阻塞。这也是为什么运行时间过长的脚本会导致浏览器无响应的原因。

我们通常想让JavaScript尽快运行,因为代码要初始化部件和事件处理程序。可是,有些没那么重要的后台任务并不会直接影响用户体验,比如:

  • 记录分析数据
  • 向社交网络改送数据(或发送57个“分享”按钮)
  • 预先取得内容
  • 预先处理或预先渲染HTML

这些任务并不要求立即完成,而为了保证页面持续响应,不应该在用户滚动页面或浏览内容期间执行这些任务。

为此可以使用Web Workers,在另一个线程里并发地运行代码。这个技术非常适合预先取得和处理数据,但无权直接访问或修改DOM。你可保证自己的脚本不那么干,但却无法保证Google Analytics等第三方脚本不那么干。

还有一个选择是setTimeout,比如setTimeout(doSomething, 1);。浏览器会在立即执行的任务完成后紧接着执行doSomething()函数。实际上是把它放在了待办事项的最后一项。问题在于无论有没有处理需求,这个函数都会被调用。

requestIdleCallback

requestIdleCallback是新API,用于在浏览器空闲的时候安排一些没那么重要的后台任务。这个API会让人联想到requestAnimationFrame,后者会在下一次绘制前调用函数更新动画。具体内容可以参考这篇文章:Simple Animations Using requestAnimationFrame

可以这样检测浏览器是否支持requestIdleCallback

if ("requestIdleCallback" in window) {
  // 支持requestIdleCallback
  requestIdleCallback(backgroundTask);
}
else {
  // 不支持,换一种方式
  setTimeout(backgroundTask1, 1);
  setTimeout(backgroundTask2, 1);
  setTimeout(backgroundTask3, 1);
}

还可以通过一个选项对象参数,指定暂停时间(以毫秒计),比如:

requestIdleCallback(backgroundTask, { timeout: 3000; });

这样可以保证你的函数在三秒钟内执行,无论浏览器是否空闲。

requestIdleCallback只会调用一次你的函数,并传入一个包含以下属性的期限(deadline)对象:

  • didTimeout — 如果可选的暂停时间已到则为true
  • timeRemaining() — 函数,返回留给任务执行的毫秒数

timeRemaining()会给你的任务分配不超过50ms的执行时间。它不会让任务停止超过这个时间限制,不过你可以再次调用requestIdleCallback以安排进一步的处理。

下面看一个例子,按顺序执行几个任务。任务以函数引用形式保存在一个数组中:

// 要运行的函数数组
var task = [
  background1,
  background2,
  background3
];

if ("requestIdleCallback" in window) {
  // 支持requestIdleCallback
  requestIdleCallback(backgroundTask);
}
else {
  // 不支持,待会一次性运行所有任务
  while (task.length) {
    setTimeout(task.shift(), 1);
  }
}

// requestIdleCallback回调函数
function backgroundTask(deadline) {

  // 有可能的话运行下一个任务
  while (deadline.timeRemaining() > 0 && task.length > 0) {
    task.shift()();
  }

  // 还有未执行的任务,再次申请处理
  if (task.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}

有没有什么不应该通过requestIdleCallback做的

正如Paul Lewis在他关于这个主题的博客文章所说的,requestIdleCallback应该执行小任务,不适合执行时间不确定的任务(像操作DOM,最好还是用requestAnimationFrame回调来做)。在resolve(或reject)Promise的时候也要注意,因为空闲回调完成后会立即调用Promise的回调,而不管剩下的时间还够不够执行该回调。

requestIdleCallback的浏览器支持情况

requestIdleCallback是一个实验性的API,规范仍在制定中,今后很可能有改动。Chrome 47支持它,Opera应该也会跟进。Microsoft和Mozilla都在关注它,前景不错。Apple照例没有表态。如果你现在就想试一试,最好用Chrome Canary

Paul Lewis写了一个简单的requestIdleCallback“垫片脚本”,实现了上述API的行为,但它不是一个可以模拟浏览器空闲检测行为的“腻子脚本”。他使用的是类似前面例子中的setTimeout。不过,如果你不想依赖对象检测也不想写分支代码,用这个脚本还是不错的。

虽然今天的浏览器对requestIdleCallback的支持有限,但这个API的确非常有助于提升网页性能。你对此有什么想法吗?欢迎留言。

英文原文:http://www.sitepoint.com/how-to-schedule-background-tasks-in-javascript/

阅读全文 »

admin 发布于 06月13, 2016

【译】不用jQuery实现简单的JavaScript幻灯片

原文:http://www.zcfy.cc/article/411

“我就想不用jQuery实现简单的JavaScript幻灯片”

这里所说的幻灯片,或者叫图片传送带、图片滑块、旋转图等等,是JavaScript学习者必修课之一。

本教程内容如下:

  • 不用jQuery等外部库实现简单的幻灯片
  • 理解UX和无障碍问题,包括是否该用幻灯片
  • 给幻灯片添加控件

不依赖库实现幻灯片的主要好处是页面速度会变快,因为代码少了。而且,随便用到哪里都不用担心加载外部文件的问题。

读者最好懂JavaScript,包括函数、事件、样式过渡。另外推荐大家看看我的这个尽可能只用JavaScript做一些实用的东西都要学什么的路线图

做个简单的幻灯片

HTML代码

HTML需要有个容器,容器里是幻灯片:

<ul id="slides">
    <li class="slide showing">Slide 1</li>
    <li class="slide">Slide 2</li>
    <li class="slide">Slide 3</li>
    <li class="slide">Slide 4</li>
    <li class="slide">Slide 5</li>
</ul>

CSS

CSS要做下面几件事:

  • 确定幻灯片的容器
  • 在容器里将幻灯片堆叠起来
  • 确定幻灯片长啥样以及何时显示或隐藏
  • 实现淡入淡出效果

看CSS前,请注意不要使用与你的网页可能冲突的类或ID。本文使用了简短的名字。

CSS在这儿:

/*
基本样式:
支撑幻灯片
*/

#slides {
    position: relative;
    height: 300px;
    padding: 0px;
    margin: 0px;
    list-style-type: none;
}

.slide {
    position: absolute;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
    opacity: 0;
    z-index: 1;

    -webkit-transition: opacity 1s;
    -moz-transition: opacity 1s;
    -o-transition: opacity 1s;
    transition: opacity 1s;
}

.showing {
    opacity: 1;
    z-index: 2;
}

再添加一些装饰性的幻灯片样式,以下是示例:

/*
非基本样式:
想要什么样,你自己定
*/

.slide {
    font-size: 40px;
    padding: 40px;
    box-sizing: border-box;
    background: #333;
    color: #fff;
}

.slide:nth-of-type(1) {
    background: red;
}
.slide:nth-of-type(2) {
    background: orange;
}
.slide:nth-of-type(3) {
    background: green;
}
.slide:nth-of-type(4) {
    background: blue;
}
.slide:nth-of-type(5) {
    background: purple;
}

JavaScript

JavaScript做一件事:隐藏当前幻灯片,显示下一张。为此,只需改变相关幻灯片的类名。

JavaScript代码:

var slides = document.querySelectorAll("#slides .slide");
var currentSlide = 0;
var slideInterval = setInterval(nextSlide,2000);

function nextSlide() {
    slides[currentSlide].className = "slide";
    currentSlide = (currentSlide+1)%slides.length;
    slides[currentSlide].className = "slide showing";
}

下面分析一下。

  1. 先用querySelectorAll 拿到容器中的幻灯片
  2. 然后声明一个变量保存当前幻灯片
  3. 最后通过定时器每2秒(2000毫秒)切换一次幻灯片

重点看看nextSlide函数。

  • 首先,把当前幻灯片的类置为不可见(去掉showing),CSS过渡会自动实现淡出。
  • 然后给当前幻灯片加1,这里使用%运算实现到最后一张后自动归零,即回到第一张;%运算符执行两个数相除,然后取得余数。 这个运算特别适合计算时间、日历等需要循环归零的情景。我们这个例子有5张幻灯片,那么依次执行取余运算的过程就是:1%5=1, 2%5=2, 3%5=3, 4%5=4, and 5%5=0。
  • 得到当前幻灯片编号之后,再给它的类加上showing。同样,CSS不透明度的渐变会自动出现。

祝贺你,一个简单的幻灯片诞生了。

注意兼容性

CSS过渡在IE9及以下版本是不能用的,在这些浏览器里,幻灯片会简单地切换到下一张。

这个简单的幻灯片是什么效果呢,看这里:Basic JavaScript Slideshow without jQuery

用户体验与无障碍

使用幻灯片之前,先要好好想想为什么在网页里用它。如果不小心的话,幻灯片很可能给你的网页带来用户体验和无障碍方面的问题。

幻灯片可能隐藏重要内容

如果是非常重要的内容,不应该放在幻灯片里。不能指望所有人都能使用合适的浏览器,这还不算无障碍问题。

根据 美国圣母大学的一项研究,只有1.07%的人会点击幻灯片中最突出的一张图,3%甚至更少的人会点击第一张之后的其他幻灯片。这说明通过幻灯片传达重要内容有多危险。

用户可能分不清你的网站是干什么的

如果幻灯片做得非常大,那么这真是个问题。如果你都不知道向用户展示什么,还怎么指望用户做出你期望的决定? (原推文)

网站应该明确告诉用户自己需要他们干什么,如果幻灯片妨碍了你达成这个目标,那该好好反思一下。

转换率优化公司WiderFunnel曾对幻灯片的有效性做过测试,并得出如下结论:

我们多次测试了轮播图,发现通过它展示主页内容效果很差;

有空的话,真的建议读一读他们这篇文章

移动用户可能不会高兴

幻灯片会导致加载时间过长,造成界面卡顿。

什么情况下可以使用幻灯片

既然幻灯片有这么多问题,那么什么情况下可以用它呢?下面是我的一些建议。

给人一个大体的印象

如果你不在乎用户是否会注意到某张幻灯片,只是想传达一种大概的印象,可以用。这种情况下,只要用户看到一张幻灯片,目的就达到了。

幻灯片外的主要内容很容易找到

比如,可能你想通过幻灯片展示某个景点、博物馆、会议或某系列产品的图片,但网站的其他地方也准备了相应图库或产品图片的完整展示区。这时候用幻灯片还是不错的。

在渐进增强的情况下

这种情况更普遍,前提是不要因为这个非网站主要功能的装饰带来太多问题。只要它只是装饰不是障碍就好。

无障碍指南

如果幻灯片的内容比较重要,应该做无障碍处理。当然,应该首先考虑到底该不该用幻灯片。

如果你(或你的客户)坚持要用,这是一篇关于幻灯片无障碍化的文章

根据这篇文章

幻灯片要做到无障碍,必须有五个条件:

  1. 允许用户停止全部切换

  2. 为键盘、鼠标和触摸设备提供无障碍访问机制

  3. 为幻灯片提供有效、可理念的焦点顺序指示

  4. 有效的代码和样式

  5. 为幻灯片提供有意义的替换

此外,这篇文章有一位评论者给出了是否决定使用幻灯片的有用资源

为了让幻灯片无障碍,下面我们就来添加一些控件。

为幻灯片添加控件

我们要添加“暂停/播放”、“下一张”和“上一张”按钮。

暂停/播放

首先为按钮添加HTML:

<button class="controls" id="pause">Pause</button>

接下来写JavaScript:

var playing = true;
var pauseButton = document.getElementById("pause");

function pauseSlideshow() {
    pauseButton.innerHTML = "Play";
    playing = false;
    clearInterval(slideInterval);
}

function playSlideshow() {
    pauseButton.innerHTML = "Pause";
    playing = true;
    slideInterval = setInterval(nextSlide,2000);
}

pauseButton.onclick = function() {
    if(playing) {
    pauseSlideshow();
  } else {
    playSlideshow();
  }
};

以上脚本都做什么了?

  • playing变量保存着幻灯片是否在播放的状态
  • 接着把暂停按钮也保存到一个变量中
  • pauseSlideshow函数负责暂停幻灯片,并把“暂停”改成“播放”
  • playSlideshow相反
  • 最后,为暂停/播放按钮添加一个单击处理程序,用于切换暂停和播放

加了这个按钮后的效果怎么样?看这里:JavaScript Slideshow With Pause Button

下一张和上一张

还是先添加HTML:

<button class="controls" id="previous">Previous</button>
<button class="controls" id="next">Next</button>

JavaScript,把

function nextSlide() {
    slides[currentSlide].className = "slide";
    currentSlide = (currentSlide+1)%slides.length;
    slides[currentSlide].className = "slide showing";
}

改成:

function nextSlide() {
    goToSlide(currentSlide+1);
}

function previousSlide() {
    goToSlide(currentSlide-1);
}

function goToSlide(n) {
    slides[currentSlide].className = "slide";
    currentSlide = (n+slides.length)%slides.length;
    slides[currentSlide].className = "slide showing";
}

为灵活起见,增加了goToSlide函数。同时,currentSlide变量的计算也做了一点改动,目的是防止出现负值。如果你想测试,可以给slides.length一个值,看看随着n变化currentSlide会怎么样。

下面添加JavaScript,让这个按钮在被点击时干它该干的事:

var next = document.getElementById("next");
var previous = document.getElementById("previous");

next.onclick = function() {
    pauseSlideshow();
    nextSlide();
};
previous.onclick = function() {
    pauseSlideshow();
    previousSlide();
};

控制添加好了。效果如何呢?看这里:JavaScript Slideshow With Controls

为用户提供了“下一张”和“上一张”按钮,用户就不会被自动播放“欺负”了。

因为这些控件就是HTML按钮,所以可以通过键盘来操控。

至于它们的样式和位置,随便你,只要明显,能用就行。

如果你还想加上用键盘上的左、右键控制,那么要保证用户在其他地方使用这两个键的时候关闭此处的控件。

防止没有JavaScript

偶尔会碰到JavaScript加载失败、被关闭,甚至设备不支持的情况。理想的情况当然是让用户仍然可以正常使用。如何做后备取决于你的目的。可以只展示第一张图片,也可以用一个列表展示所有图片。

如果幻灯片的主要目的只是给人一个大概的印象,那么显示保持网页布局不变比展示所有图片更重要。

如果确实需要展示所有图片,那你就把它们都罗列出来呗。

这两种情况,下面都会介绍。

无JavaScript时隐藏控件

默认使用CSS隐藏控制:

.controls {
    display: none;
}

然后使用JavaScript显示控制。这样,用户会在有JavaScript的时候看到控件。

var controls = document.querySelectorAll(".controls");
for(var i=0; i<controls.length; i++){
    controls[i].style.display = "inline-block";
}

以上代码循环所有控制,把它们都显示出来。

无JavaScript时列出所有图片

首先把.slide类的CSS由position: absolute;改为position: static;。这样,默认就是列出所有幻灯片。

然后添加JavaScript循环每一张幻灯片并将它们的定位改为绝对,像下面这样(一定要把这些代码放在slides变量后面):

for(var i=0; i<slides.length; i++) {
    slides[i].style.position = "absolute";
}

这样,幻灯片在JavaScript可用时就不会列出来了。

小结一下

我们讲了怎么做一个简单的幻灯片,如果处理用户体验和无障碍问题,以及如何添加控件。

本文最重要的,是想让大家思考:到底什么时候该用幻灯片,如果你想在网页中放个什么东西,请先想一想会对用户造成什么影响,以及它对你实现目标有没有帮助。如果答案明确,再去做或不做。

你想到什么了?关于幻灯片你有没有自己的经验或教训?或者有好玩的故事?欢迎留言。

英文原文:https://www.sitepoint.com/make-a-simple-javascript-slideshow-without-jquery/

阅读全文 »

admin 发布于 06月02, 2016

【译】Web会不会重生

原文:http://www.zcfy.cc/article/244

2015年7月,受Mat MarquisTXJS 2015上发言的启发,我建议网页的平均大小应该等于经典DOC游戏Doom安装的图片大小。

大约7个月平均下来,网页大小与Doom安装的图片大小相同。我们做到了,越来越大。 pic.twitter.com/xtSAtZjPGl

— ronan cremin (@xbs) July 30, 2015

我们做到了,虽然比预期晚了一点。这是我们当前的情况:

web page size revisited revised

阅读全文 »

admin 发布于 05月24, 2016

如何在众成翻译获得打赏

众成翻译(http://www.zcfy.cc)是360最大前端团队奇舞团推出的一个在线翻译平台,今年5月10号刚刚发布了1.0版。众成翻译的目标是做国内最好的技术翻译和内容产出社区,同时力争做最懂译者的翻译平台。本周一(5月23日),众成翻译上线译文打赏功能,本文将为大家详细介绍如何在众成翻译平台让自己的译文获得读者的打赏。

概述

要获得打赏,关键是在自己译文下方显示一个(或两个)收款二维码,这样读者才能把银子给你。比如这样:

alt

因此,要获得打赏,最重要的是学会生成自己的收款二维码。众成翻译目前支持上传两个二维码,默认为微信和支付宝的。下面就来看一看怎么在这两个手机应用中生成你自己的收款二维码。

阅读全文 »

admin 发布于 05月18, 2016

【译】FIDO联盟规范简介

原文:http://www.zcfy.cc/article/189

FIDO(Fast IDentity Online)联盟成立于2012年7月,致力于解决当前网络环境下强认证设备间缺乏互操作性,以及用户需要创建并记住多套用户名和密码的问题。FIDO联盟将开发出开放、可扩展、具有互操作性的规范,取代依赖密码认证的传统方式。这个针对安全设备和Web浏览器的规范,将允许任何网站和云应用与支持FIDO的设备通信,实现更便捷、更安全的在线用户认证。

FIDO联盟有两套规范:U2F和UAF。联盟为部署该技术者提供维护新的fido-dev@fidoalliance.org公共邮件讨论列表的支持。

最新修订版可以访问规范下载页面

阅读全文 »

admin 发布于 05月13, 2016

【译】W3C TAG候选人简介

原文:http://www.zcfy.cc/article/141

David Baron (Mozilla)*

我是Mozilla的“杰出工程师”(Distinguished Engineer),从它2003年独立成一家公司开始,我就在里边工作了。从1998年起,我主要关注CSS社区,并参与了Gecko布局引擎(Firefox及其他Mozilla产品在用)的开发。2004年,我开始担任Mozilla在W3C顾问委员会和CSS工作组的代表,并在2015年5月的特别选举中成为TAG委员会委员。

在Mozilla工作期间,我实现了媒体查询、CSS过渡和动画、CSS calc()函数,设计并实现了针对布局测试的反射测试(reftest)的递归测试格式,也参与了Gecko很多方面的开发工作,包括架构设计变化和安全bug修复。

阅读全文 »