深圳node party小结

实战ES2015

  • classes
  • export&import 统一标准
  • 使用rollup.js打包、HTTP/2

平台化运营实践

腾讯MTT对比pm2设计

  • 进程管理
  • 日志类型(按大小滚动,按时间滚动)
  • 日志输出 时间|pid|级别|文件名:行号
  • 可配置的服务(不重启)
  • TAF协议与JCE规范(编解码,不动态解析方便debug)
  • 调用监控(流量、耗时、超时率、异常率、服务+接口)与特性监控(自定义)

日常问题

  • 时间计算 Date.now()最快,process.uptime()最好
  • 内存与进程 虚拟核心与物理核心问题
  • 用户环境 服务调用只在同环境中进行,服务转发??
  • 染色应用 将整个服务调用链日志统一收集展示

    push 类推送业务 (峰值流量->削峰)
    用户访问相关业务 (越平滑流量越大)
    定时拉取任务(持续资源使用->错峰)

process.setMaxListeners(Infinity)隐患
load高、cpu不高 -> 查io(socket)、swap使用率

Nodejs广发证券:koa2与微服务

nodejs定位(实现API Server)

  • Restful Extend(Filter&Sort,Bulk Inserts,Pagination,Optional-filds)
  • Falcor @ Netflix
  • 使用Koa2 async&await(异步,错误处理)koa-adapter
  • 接口验证与数据验证 koa-validate&joi(数据验证)

日常

  • es2015使用
  • npm scripts(npm-check)
  • 入库前检查 使用husky检查,
  • 测试覆盖 (经常修改、复杂、多人合作)npm run coverage:lab plato(js源码可视化)

线上运行

  • StrongLoop 性能优化系列文章
  • 上线准备(Event Loop监控,通过环境变量与信号来调整log级别,异常重启比忽略好)
  • 支持几千几万的流量(request-debug)
  • docker运维,镜像部署方便,链路监控(Zebking)

TypeScript在Nodejs应用

techird.com

2015 shen JSconf大会总结(第一天)

两个星期前7月11~12日在深圳前海举行了第四届中国jsconf会议,第一次参加纪录一下学习内容与个人思考。本次会议由李学斌(hk)推广,wiredcraft公司承办

##Part One 2015-07-11

###1. Database everywhere - EvanYou@Meteor

  • UI - Client data - Server data (sync)
    Solution: UI - Client data (react, angular, vue)
  • How about Client & Server data?
    REST (Backbone Model, ngResource, Restangular, Flux Stores)
    pull-centric imperative/ trouble with non-conventional APIs/ difficult managing optimistic updates
  • IDEA: UI - Server data (GraphSQL, JSON Graph, Om Next) not ready

METEOR: DDP, Tracker, minimongo(both cli& ser)
UI - minimongo - Server data

publish & subscribe? component-level template

$meteor.collection(new Mongo.Collection("Task"))
Tasks.find().fetch() ???

QA: actions record -> rollback

ppt地址 Slide.com [http://slides.com/evanyou/shenjs]

###2. ES6 generators - BIHOLT@Netflix
node 0.12
as ES2015

  • generators: async pro -> sync
    (Meteor, Babel use Regenerator)

a function return a generator obj which is iterable

1
2
3
4
5
6
7
8
9
const colorGenerator = function*() {
for (let color of colors) {
yield color;
}

}
let generator = colorGenerator();
//use generator.next();
//let values = Array.from(generator);

simulate ES7 asyc/await

1
2
3
4
5
6
7
8
co(function* (){ 
let user = yield promiseAjax.get("url");
handleUserData(user);
});

async function() {
let user = await promiseAjax.get("url"); handleUserData(user);
}

solution: gen store state between calls!

//for WebSockets or polling
function *poll() {
    while(true) {
        let id = yield;
        req.get(id).accept('json').end(function(err, data){
        logger.next(data);
        })
    }
}
let poller = poll();
//use poller.next(); poller.next(id++)

also call .return() or .throw()[inject into]

ppt地址 speakerdeck.com/btholt

##Lucky Draw
raffle.js漏洞百出

###3. Koa&Toa - Yan
vs express req, res, next P:异步流程控制

  • koa this, yield next generator 函数 每个中间件可以分为前后两部分,都可以终止 P:流程复杂,第三方暴露
  • toa vs koa this, yield 回到body this.body

异步原语:

  • promise 标准接口,链式返回promise,任意多promise组合(多异步)
  • thunk 新callback形式,返回thunk函数(thunk(function(callback){ return Promise //thunk}))
  • generator (function *() { yield promise })

###4. AngularJS real-time app - loddit(BohanLi)@BearyChat
demo: 二维码刷新 meteor

api server – RPC – keep-alive ser

Protocol: XMPP / IRC , DDP(Meteor)[quick demo], CRDT(Swarm.js)

Ping/pong to check, use object as singleton, push for everything

Q:分组,消息等信息:普通Obj, Array;事件类型太多(命名,gonn);

Q:交互性能:减少watch(改用ng-switch);消息丢失处理:长连接保证,update时序更需要保证;

###5. PM2 - alexandre@Keymetrics
a process manager dedicated to Node.js [distributed!]

##NodeBot Session - ajfisher
NodeBots stack [<3] IO Plugin – NodeJS (Johnny Five) – HTTP – clients

  • Adurino.cc IDE
  • npm install jornny-five -g
  • nodebotsday.com
  • github.com/jsconfcn/nodebots-session

##light talk

  1. undoZen (require('co'); co.wrap(fun);)
  2. zhangwenli.com/Polyvia vs Naive Random Method
    selected vectile (webgl sobel edge) -> dynamic -> center of mass 视频淘汰率
  3. pmq20 body.toString()
  4. socket 1000连接问题? ulimit 设置!默认1024
  5. 输入法 js
  6. Zearlin/重鱼

###6. NodeJS 分布式应用 - WenTianle@UCloud

C++ -> 分布式RPC架构(配置管理,服务自动发现,自动扩容,脚本)
umaster/zookeeper cluster 名称服务 -> rabbitmq/zookeeper 服务异构(扩容)/配置管理

node-amqp 3.4.1

遇到的问题

  1. nodejs [protobuf extension]
  2. 异步编程效率[Fibers]
  3. nodejs 内存泄漏(网络框架中回调函数导致)
  4. 异步超时处理(定时清理?)
  5. 异步中日志记录(Fibers包装为task queue,带上其id)
  6. rabbitmq ha(ser HA-》cli HA ip选择来解决100s定时断问题,heart beat时间约定机制)
  7. rabbitmq ha 网络闪断导致节点分区
  8. zookeeper session expired 网络断导致,client重连成功后由于session key不同导致server要求再次重连,同时产生一次session expired回调 容易导致内存泄漏

###7. JS Frameworks - Eyalarubas.com@EF
全是吹水,外国人包装能力真强!

###8. 前端可视化技术 - pissang @Echarts.baidu
Canvas vs SVG

  1. 性能考虑,特效绘制,像素操作
  2. demo:尾迹特效(保存上一帧,另一个canvas alpha值调整),热力图(像素操作)

问题: 没有图像对象(层级,样式,变换),事件

解决:图像对象管理(借鉴SVG方法),事件绑定(容器绑定代理,反向循环判断鼠标是否在某图像上,这时要将鼠标进行坐标变换-> 包围盒判断 / 路径的精确判断,js实现isPointPathisPointInStroke 不需要重新构建路径)

latest: Path2d

WebGL

  1. 加速二维图像绘制
  2. 问题:Shader计算动画小点位置

demo: lambertShading

2D图形处理:Meth -> canvas surface -> canvas -> 2D objects

9. NERD Disco - TimPietrusky@

  • web audio
var audio_context = new AudioContext();
var audio_anay = audio_context.analyser();

try ndAudio -> ndVisualization -> NeoMatrix Adafruit (nodejs server)

try web mini api

2015 shen JSconf总结(第二天) 

第二天干货非常多,全是实战经验,基本没有什么技术介绍。

##Part Two 2015-07-12

###1. 七牛前端测试实践 - 马逸清
angularjs dom隔离,测试不需mock;依赖注入可以mock (service, controller) 可以使用stub

stub适合返回值依赖,mock行为验证

官方jasmine
View状态测试

phantom,sinon(stub),fixture(karma)

###2. Node Profiler - 朴灵@阿里云alinode
hack了部分v8代码,跟CPU Profile相关

  • 常用工具: benchmark.js,node-webkit-agent,ab/wrk(压力测试),–prof & mac-tick-processor(v8)
  • v8以JIT方式执行js(产出机器码),以函数为单位处理
    Crankshaft架构(可以运行时优化 fulCompiler -> optimizeCompiler) P:bailout, deoptimize
  • Profiler: 更多函数状态,优化建议(v8能否优化) http://alinode.aliyun.com
  • (program) 系统空转

? 第一次访问测试

###3. P2P pipes - mafintosh(dat)

demo: multiplayer game(socket)
websockets, webrtc

**ndjson, nc, crypto, dupsh(two app in-out pipe), airpaste(udp multicast with pipe), blecat(blutooth with pipe), webcat(webrtc with pipe)

###4. 微服务架构下的服务通信 - 老雷leizongmin @ucdok.com/ superid.me一登
后台Node逻辑
SDK - 多进程?- API服务器(人脸识别模块)

=》 SDK - API服务器 -人脸识别进程(多线程)

=》 - 更多应用(后台微服务架构)

–> 服务注册(消息队列总线式 / P2P)+远程调用

实现原理

总线可以用redis实现,通信也用redis订阅机制(服务提供者可以动态加入)
vs amqp-rpc, eureca.io

未来:备份切换,数据量太大

服务发现 + 服务通信

ppt地址 github.com/leizongmin/clouds

etcd + k8s + docker

###5. 前端服务化之路 - Herman@阿里CXDC 客服中心

前后端分离-》前端给后端提供接口(服务化)-》web component
**flipper.js 支持IE8以上 – webcomponents.js 更好的隔离性

###6. JS lang - hax贺诗俊@百姓网
NodeJS + CommonJS -> ES6 module( class, arrow function[this bind], map/set, for..of..[for in] )

WebAssembly

babel(es6 compiler)

###7. JS on Fiber - 庄恒飞@孢子社区fibjs-> 那么社区named.cn
fibjs vs nodejs, Fiber-Driven,No Callback

  • Module lib: CommonJS,async require
  • coroutine.parallel 【改变nodejs单线程】多CPU利用率
    js,用
    brew install fibjs [http://fibjs.org]
    fibjs底层多种线程(fiber) -> js线程-》work线程池【实际改动了v8下一层,解决了nodejs的callback与计算密集】

##Lighting Talk

  1. tangrui.net (js in JVM: 1.6 ringo 1.8 nashorm(vert.x/avatar.js)) cde.io
  2. wangyan @oneapm.com (npm2dot) 转换dot格式
  3. dafeng @strikling.com “GraphQL & Relay”: restful api问题:依赖多次发送->custom endpoint-》 GraphQL帮忙管理
  4. homlinju @fontmin js方案的字体最小化
  5. 一狂 @阿里cxdc www.zouyesheng.com angular问题:不单单使用,模块化加载,自己的渲染机制,怎么合作?模块内定义dir最后手动触发bootstrap
  6. EvanYou @vue webpack vue-element.js
  7. xeodou crazyapp.net/#/explore

###8. Persistent data structure in JS-NiYue@splunk
persistent data structure [like COW] -> concurrency
real good:

  1. performance(判断状态是否变化)
  2. features on copy(undo/redo,recording/reply,time traveling)

实现策略:COW -> structual sharing
问题:内存消耗,内存回收

mori, Immutable

一页千级dom元素?
LightTable演示

###9. WebIDE with React - hulufei @coding.net
React - Flux - karma

Components: <WebIDE/>

1
2
3
4
5
var App = React.createClass({
render: function() {
<div><Menu/><Tree/></div>
}
})

Flux: Dispatchor -> store -> view -> action
<Editor/><SettingModel/> 通信:
SettingStore -> SettingAction

Addons: store或action引用API层

roit, ace rather than codemirror
QA:store划分标准:组件需要,共享; 数据放store里面方便做数据缓存,返回promise;Flux写太多模板代码;

###10. WebGL & WebVR - Martin @Zurich - archilogic.com @g33konaut

faces + vertices -> GL buffers -> shader code -> print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var renderer = THREE.WebGLRenderer();
var box = new THREE.Mesh(
new THREE.BoxGeometry(100, 100, 100),
new Three.MeshBasicMaterial()
);


scene.add(box);

var light = new THREE.PointLight()
light.position.set();
renderer.render(function(){
box.rotation.y += Math.PI / 200;
});
//OBJMITLoader()

//VR
var vrEffect = new THREE.VREffect(render),
vrControls = new THREE.VRControls()

###11. maintainable nodejs - 死马 不四@天猫前端,dead-horse@github koa
提供固定的输出

异步try-catch -> promise 可以传递error
默认的错误监听函数,可以利用事件方式让外层感知

bluebird, co

创建你的hexo博客

目前由于hexo的升级。在github上搭建hexo博客的过程与网络上的文章指导内容会有少许变化。

第一步当然还是安装hexo,接着在本地创建自己的hexo博客目录

1
2
$ npm install hexo -g
$ hexo init <YOU_BLOG_DIR_NAME>

然后切换到那个目录下面,安装必备的node插件

1
2
3
$ cd <YOU_BLOG_DIR_NAME>
$ npm install
$ npm install hexo-deployer-git --save

这时你的博客已经准备就绪啦,接着按照自己的需求修改配置文件,需要注意的是deploy部分

1
2
3
deploy:
type: git
repo: <YOUR_GITHUB_REPO_URL>

万事大吉,可以使用hexo new <POST_NAME>来创建新文章,写完后使用

1
2
3
$ hexo server #本地查看博客效果
$ hexo generate #生成静态文件用于部署
$ hexo deploy #部署同步到Github的项目上

有些遗憾的是这个git的deploy插件有点傻,仅把博客的静态文件提交到了远程仓库的master分支,而没有提交原始配置文件。没办法,只能自己动手进行分支同步。

1
2
3
4
5
$ cd <YOU_BLOG_DIR_NAME>
$ git init
$ git add remote origin <YOUR_GITHUB_REPO_URL>
$ git commit -a
$ git push origin master:<YOUR_REMOTE_BRANCHNAME>

好啦,以后任何位置都可以利用Github同步文章写博客啦

JavaScript实用代码片段

最近抽空在忙小项目,总结了下一些项目中碰到的常见问题,搜集对应的实用JS代码片段,跟大家分享。

1.产生限定范围内不重复的随机数

在深js也碰到了完全相同的问题,即抽奖程序的核心算法,结果是bug频出。这里给出js抽奖程序,大家去鄙视一下。
一种思路是在给定大小数组中每次抽取一个随机位置的数进行剔除,这个程序的问题是必须始终维护抽取的数组,好处是不会重复抽取:

var originalArray=[];
for (var i=0;i<len;i++) { 
    originalArray[i]= i; 
} 
var getRandom = function(){
    var index=Math.floor(Math.random()*originalArray.length); //随机取一个位置 
    var value = originalArray[parseInt(index)];
    originalArray.splice(index,1);
    return value;
}
有什么其他好方法不妨分享一下。 ## 2\. 数字保留两位小数 数字进行截断保留两位小数只想到如下方法
floatNum = Math.round(floatNum*100)/100;
但是还有情况是仅展示两位小数,这时只要用原生的API方法就可以了
floatNum.toFixed(2)

3. 触发change事件

这是在使用AmazeUI中按钮组时碰到的问题,按钮组并没有对应的js封装,所以点击div模拟的按钮并不能触发实际单选按钮的change事件,因此需要jquery来手动触发。估计Bootstrap应该有进行更好的封装吧。

$button.children().attr('checked',true).trigger("change");
这里使用`children`仅是为了获得包含在外层`div`下的单选按钮,还得设置check状态 ## 4\. 单选按钮选择信息获取 按钮组中究竟选择了哪一个可以使用下面代码获得
$('input[name="radio-options"]:checked').val()

5. 中文编解码

在URL中传递中文就需要进行URI编码转为16进制的数字表示

location.href = "result.html?u="+encodeURIComponent(name)+"&b="+invest_status.profit+"&r="+invest_status.rounds;
展示也得使用相应的URI函数解码进行
user = decodeURI(name);
发现不少浏览器现在已经支持直接在URL中插入中文,估计这里有些变化了。 ## 6\. 转换为数字类型 两种方法,一种是
option = parseInt(IntNumStr);
另一种是
option = Number(IntNumStr);
注意单选按钮的选择值就可以用这个方法进行转换 ## 7\. 浏览器url信息处理 主要是处理GET请求的分隔符"&"与值的获得,也就是运用`.split("&")`和`.split("=")`
infos = url.split('&'), user = (infos[0].split('='))[1];
搜到一个大而全的[处理工具](https://github.com/websanova/js-url) ## 8\. 网页title设置 直接给`document.title`赋值即可 ## 9\. 异步加载与性能优化 promise ## 10.文件上传处理

window.Blob slice
file

11. 多场景管理

12. 简单模板与双向绑定

使用data-*属性指南

本文内容参考自MDN的using-data-attributes-in-javascript-and-css一文



一篇2012年的文章,目前data-属性作为HTML5规范已经不能算是新特性了,主要是JSconf里看到troopjs使用,而boss问其他小伙伴时他们居然都不知道,于是就想总结一番。

data-
属性使用起来也很直观:
<article id=”electriccars” data-columns=”3” data-indexnumber=”12314” data-parent=”cars”>…</article>

;

JS可以使用getAttribute方法获得data-属性的值,当然HTML5规范里也提供更为简便的方法:

    var article = document.querySelector(‘#electriccars’),
data = article.dataset;

// data.columns -> “3”
// data.indexnumber -> “12314”
// data.parent -> “cars”


每个属性返回都是string类型,但是可以直接设置article.dataset.columns = 5 从而改变属性的值

大多数人不知道的是HTML5还规定了data-属性相关CSS接口,可以通过该属性值来填充内容:

    article::before {
content: attr(data-parent);
}


你也可以在选择器中使用data-
属性:

    article[data-columns=’3’]{
width: 400px;
}
article[data-columns=’4’]{
width: 600px;
}


data-*属性的优势在于相关数据直接与dom节点绑定,css接口使用也挺方便,至于效率方面是否比window storage更高,留待以后测试。未来结合Web Component技术,倒是又可以大放异彩。

漫谈Web Components技术

第一次听说Web Components相关技术是在2013年从Shadow DOM 101这篇文章得知,只当是个模板技术的浏览器实现。谁想在Google IO 2014竟然将基于Web Components技术的Polymer专门做了个专题进行大篇幅介绍,其中Custom Element加上Imports的组合概念堪称惊艳,有种前端界的MapReduce的感觉。其实Google早在13年就已经花了部分精力对Web Components技术进行了介绍(链接是当时演讲里的ppt,部分协议标准已经产生了变化),只是未像IO 14一样做专题介绍。

比如:

Live demo - 自己实现了一个,得用现代浏览器(推荐webkit内核)打开才行

使用Custom Element创建后可以通过HTML Import加载,然后直接使用

<x-gangnam-style></x-gangnam-style>

1. 规范现状

Web Components技术由W3C规范进行定义,实际由四种技术组成:

  • Custom ELements,可以创建自定义html标签元素,而且支持对现有html元素进行扩展,从而自定义新的API
  • HTML Template, 使用template标签包含html相关代码片段,作用行为基本类似于JS模板引擎里的视图(View)
  • Shadow DOM,,可以创建对外隐藏的web片段,关键是支持独立的样式,不会影响所在文档内的其他样式
  • HTML Imports, 提供对模板或者自定义元素这些资源的加载支持,可以像引用JS或CSS一样引用HTML组件
    截至2014年8月17日,四个技术标准中HTML Template已经从Web Components规范中移除,并加入到HTML5标准中,这意味着该技术协议已经处于完成状态,不会再出现改动。Custom ELements也进入“Last Call”阶段,今后改动可能性也不大了。另外两个仍然存在修改的可能,因此下面的介绍只能当做谈资了解了解罢了。有关Web Components的规范现状与详细定义可以在这个链接中找到。

2. Custom ELements

原本Custom ELements设计是通过新增的element标签来实现自定义html标签元素,但由于种种问题,最终删去了相关规范。目前只能通过document.registerElement(tagName, prototype)方法来定义标签。该方法提供元素原型继承的接口,可以通过Object.create方法创建元素作为prototype传入。在这个gangnam-style示例中就使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
var gangnamProto = Object.create(HTMLElement.prototype);

gangnamProto.createdCallback = function(){
// deal with element view create
}

gangnamProto.attachedCallback = function(){
// deal with event bind
}

document.registerElement("x-gangnam-style", {
prototype: gangnamProto
});

接着就可以直接在html文件中使用x-gangnam-style标签了

3. HTML Template

该技术规范已经加入到HTML5规范中,成为一个新增的HTML5标签。使用非常简单,直接在html文件中添加template标签即可。该标签在浏览器中会被渲染处理,但不会展示,因此会比以前使用script做js的模板容器在效率上会高一些。需要注意的是获得template标签中的内容,需要使用其content属性,该属性返回documentFragment类型。而将content内容插入到目标元素中后会导致内容丢失,因此需要使用cloneNode方法进行拷贝保证其他元素仍然可以使用这个template中的content内容,或是使用document.importNode方法进行拷贝。在这个gangnam-style示例中就使用:

<template id="gangnam-style-tmpl">
<style>
...
</style>

<div id="maia-signature">
<div id="sig" class="zg-sig">
 <div id="psydroid" class="zg-psydroid">
 <img alt="" class="zg-psydroid-head" src="http://www.google.com/zeitgeist/2012/images/psydroid-head.png"> 
 <img alt="" class="zg-psydroid-body" src="http://www.google.com/zeitgeist/2012/images/psydroid-body.png"> 
 <img alt="" class="zg-psydroid-arm-l" src="http://www.google.com/zeitgeist/2012/images/psydroid-arm-l.png">
 <img alt="" class="zg-psydroid-arm-r" src="http://www.google.com/zeitgeist/2012/images/psydroid-arm-r.png">
 <img alt="" class="zg-psydroid-leg-l" src="http://www.google.com/zeitgeist/2012/images/psydroid-leg-l.png">
 <img alt="" class="zg-psydroid-leg-r" src="http://www.google.com/zeitgeist/2012/images/psydroid-leg-r.png">
 </div>
</div>
</div>
</template>
<script>
 ...  
gangnamProto.createdCallback = function(){     
   //deal with element view create     
   var thisDoc = document.currentScript.ownerDocument;  
   var tmpl = thisDoc.querySelector("#gangnam-style-tmpl");               
   //shadow.appendChild(tmpl.content.cloneNode(true)); also works!
   shadow.appendChild(document.importNode(tmpl.content, true)); 
} 
...  
</script>

这样就可以在Custom Element中使用template中已经定义好的html结构与样式。当然为保证接口与样式的封装性,这里还将HTML Template与Shadow DOM结合了起来。

4. Shadow DOM

这个技术规范堪称Web Components的灵魂所在,而且早已经用于HTML5标签技术中,只是不曾暴露接口给JS调用罢了。例如HTML5中的video标签就包含了Shadow DOM。现在可以在任何DOM节点上创建Shadow DOM,使用这个技术的好处在于Shadow DOM可以完全封装其中的dom结构与style样式,使得相关信息对用户透明。特别是包含在其中的样式,完全不会影响到其他元素,从而使得形成独立UI组件成为可能。Shadow DOM创建起来非常简单,调用createShadowRoot即可:

 gangnamProto.createdCallback = function(){

var shadow = this.createShadowRoot();
shadow.appendChild(document.importNode(tmpl.content, true));
}

同时Shadow DOM还提供<content>标签,该标签可以使用rel属性让浏览器选择性的填充其中的内容。(不知为何该标签在Chrome 36里失效 实际没有失效,只是dev tool展示比较奇怪,让本人误会了)
为方便CSS样式进行Shadow DOM的匹配选择,该技术还提供了多个CSS相关选择符,包括::shadow,/deep/,::host,::host-context,::content等。
目前该技术仍然在修订中,所以还存在不少变数。

5. HTML Import

在前面将Web Component封装在一个HTML文件中后,如何引用该组件并重复运用就成为了问题,这时就需要使用HTML Import技术。该技术使用起来很方便,一句话即可:

<link rel=”import” href=”./x-gangnam-style.html”>

同时可以使用rel=import获得该link节点:

var link = document.querySelector(‘link[rel=import]’);

目前该技术也仍然在修订中,而且很多细节都在变更。

6. 总结

这些技术目前还没有浏览器完全支持,而且规范还在修改中,因此完全不存在工业界使用的可能性。但是这些技术其实早就在浏览器中不断使用,只是没有暴露相关接口而已,规范需要决定的只是怎么暴露,如何让开发者方便使用而已,因此这些Web Component技术的普及可谓是必然。当然,Web组件的最终形态肯定不是直接使用这些规范,多看看微软GUI组件的发展轨迹就可以知道基于新的Web Component规范的Web组件未来还有很长的路要走。

出自jquery作者简单js模板中的技巧

短短的一段代码,看懂之后能真正认识javascript语言中的各种技巧 来自JavaScript Micro-Templating

// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
  var cache = {};
  // tmpl解析函数,参数str通常为模板tag的id,参数data为传入的数据
  this.tmpl = function tmpl(str, data){ 
   //首先判断传入str第一个字符是否为非单词字符,\W等价于[^A-Za-z0-9_],注意判断条件取反
    var fn = !/\W/.test(str) ? 
      //为真,说明开头字符为单词字符,即str表示id,则首先查找缓存中的模板函数
      cache[str] = cache[str] || 
        //未缓存则并取出模板中的内容运行tmpl解析函数,由于未传入data参数,故返回模板函数指针进行缓存
        tmpl(document.getElementById(str).innerHTML) : 

      // 为假,说明开头字符为非单词字符,即str表示模板内容,则创建相应的模板函数fn对象
      new Function("obj", //fn接受一个参数obj,实质即data
         //函数内容,p为需要显示的内容以数组形式保存,内部函数print即调用p的push方法将所有参数压入(该函数用法不明)
        "var p=[],print=function(){p.push.apply(p,arguments);};" + 

        //使用with关键字,将参数obj即data带入到执行环境中,这样模板中的变量即可使用
        "with(obj){p.push('" +
        // 在创建fn函数对象时即将str模板内容转换为完全的js代码,
        // 例子:<i class='a'><%=user.id%></i>
        str
        // 先清除各种换行符以方便后面作为替代符号进行使用
          .replace(/[\r\t\n]/g, " ")
        // 将模板开头标志替换为缩进符,
        // 例子:<i class='a'>\t=user.id%></i>
          .split("<%").join("\t")           
        // 模板中非脚本部分(即html标签)中的单引号替换为换行符,其中$1即正则中小括号能匹配的内容
        // 例子:<i class=\ra\r>\t=user.id%></i>
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
        // 将模板中直接显示的变量提取出来,用单引号与逗号进行分隔,由于字符串使用单引号,故而上一步需要记录
        // 例子:<i class=\ra\r>',user.id,'</i>
          .replace(/\t=(.*?)%>/g, "',$1,'")
        // 将代替模板开头标志的缩进符替换为push调用结束,注意例子中的\t在上一步已被删去
          .split("\t").join("');")
        // 将模板结束标志替换为p.push调用开始,意为模板标志之间的html标签即以字符串的形式压入p数组
        // 注意例子中的%>也在显示变量那步被删除
          .split("%>").join("p.push('")
        // 还原模板中原有字符串部分的单引号
        // 例子:<i class=\\'t\\'>',user.id,'</i>
          .split("\r").join("\\'")
        // fn函数返回最终拼接的字符串,p.push('<i class=\\'t\\'>',user.id,'</i>');,注意push方法是可以压入多个元素的
      + "');}return p.join('');");

    //如果传入data,则返回运行模板函数后的最终结果,否则返回模板函数fn指针
    return data ? fn( data ) : fn; 
  };
})();

制作Bookmarklet书签

基本模板就是这样,主要是javascript:起了作用,导致代码执行。

javascript:(function(){

if(window.bookmarklet!=undefined){bookmarklet();}
else{document.body.appendChild(document.createElement('script')).src='http://YOURURL/bookmarklets.js';}

})();
本站总访问量