浏览器的高层结构

浏览器的主要组件为:

  1. 用户界面 - 包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面。
  2. 浏览器引擎 - 在用户界面和呈现引擎之间传送指令。
  3. 呈现引擎 - 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
  4. 网络 - 用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。
  5. 用户界面后端 - 用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
  6. JavaScript 解释器。用于解析和执行 JavaScript 代码。
  7. 数据存储。这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。
阅读全文 »

keyword: mocha, nightmare, nightwatch


Web 应用越来越复杂,意味着更可能出错。测试是提高代码质量、降低错误的最好方法之一。

  • 测试可以确保得到预期结果。
  • 加快开发速度。
  • 方便维护。
  • 提供用法的文档。
  • 对于长期维护的项目,测试可以减少投入时间,减轻维护难度。

测试的类型

  • 单元测试(unit testing)
  • 功能测试(feature testing)
  • 集成测试(integration testing)
  • 端对端测试 (End-to-End testing)
阅读全文 »

keyword:nodejs,webpack,vue-cli,vue-router,vue-resource,vuex,vux

首先假装自己已经熟悉了nodejs和webpack的基本使用方法

阅读全文 »

一、文件结构

本文主要分析开发(dev)和构建(build)两个过程涉及到的文件,故下面文件结构仅列出相应的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├─build
│ ├─build.js
│ ├─check-versions.js
│ ├─dev-client.js
│ ├─dev-server.js
│ ├─utils.js
│ ├─vue-loader.conf.js
│ ├─webpack.base.conf.js
│ ├─webpack.dev.conf.js
│ ├─webpack.prod.conf.js
│ └─webpack.test.conf.js
├─config
│ ├─dev.env.js
│ ├─index.js
│ ├─prod.env.js
│ └─test.env.js
├─...
└─package.json
阅读全文 »

微信宣布小程序开放内测第二天,公司运营拿到内测资格,欣喜若癫,誓要拿下微信给的这第一波红利。
当即随着微信开始了踩坑之旅。

代码结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
wxapp
│ app.js 主程序入口
│ app.json 配置
│ app.wxss 全局样式
│ config.js 环境变量配置
│ configureStore.js 创建store
├─actions
│ index.js
├─pages 各业务页面存放目录
│ ├─index
│ │ index.js
│ │ index.json
│ │ index.wxml
│ │ index.wxss
│ ~...
├─public 公共资源:图片,组件
│ ├─image
│ └─components
│ ├─toast
│ │ toast.js
│ │ toast.wxml
│ ~...
├─reducers
│ index.js

└─utils 公共函数
mta_analysis.js
promise.js
redux.js
util.js
阅读全文 »

概念

ES6 原生提供了 Promise 对象。
所谓 Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。
Promise 对象有以下两个特点。

  • (1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。
  • (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
    有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
    Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

用法

在写微信小程序的时候,有时需要等第一个异步请求返回内容之后再开始第二个异步请求,然后再做逻辑处理,
受够了层层嵌套的回调,决心换一个直观的写法。

原写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$.ajax({
method:'',
data:'',
success:function() {
$.ajax({
success:function() {
//Do something
},
error:function() {
alert('err')
}
})
},
error:function() {
alert('err')
}
})

用了promise之后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var a = new Promise(function(resolve,reject){
$.ajax({
success:function(data) {
resolve(data)
},
error:function(e) {
reject(e)
}
})
})
var b = new Promise(function(resolve,reject){
$.ajax({
success:function(data) {
resolve(data)
},
error:function(e) {
reject(e)
}
})
})
a().then(function(data){console.log(data);return b}).then(data=>console.log(data));

##简单实现:

语法是es6,后面是经过babel编译的代码,不熟悉es6的同学不太影响阅读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class Promise{
constructor(fn){
this.state = 'pending';
this.value = null;
this.deferreds = [];

this._resolve = this.resolve.bind(this)
this._reject = this.reject.bind(this)
fn(this._resolve,this._reject)
}
handle(deferred) {
if (this.state === 'pending') {
this.deferreds.push(deferred);
return;
}
var cb = this.state === 'fulfilled' ? deferred.onFulfilled : deferred.onRejected,
ret;
if (cb === null) {
cb = this.state === 'fulfilled' ? deferred.resolve : deferred.reject;
cb(this.value);
return;
}
try {
ret = cb(this.value);
deferred.resolve(ret);
} catch (e) {
deferred.reject(e);
}
}
resolve(newValue) {
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
then.call(newValue, this.resolve, this.reject);
return;
}
}
this.state = 'fulfilled';
this.value = newValue;
this.finale();
}
reject(reason) {
this.state = 'rejected';
this.value = reason;
this.finale();
}
finale() {
setTimeout(function () {
this.deferreds.forEach(function (deferred) {
this.handle(deferred);
}.bind(this));
}.bind(this), 0);
}
then(onFulfilled, onRejected){
return new Promise(function (resolve, reject) {
this.handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
}.bind(this));
}
}
//测试
var a = new Promise(function(res,rej){
setTimeout(function(){
let a = 1;
let b = 2;
if(1){
res(a)
}else{
rej(b)
}
},2000)
});

var b = new Promise(function(res,rej){
setTimeout(function(){
let c = 3;
let d = 4;
if(1){

res(c)
}else{
rej(d)
}
},2000)
});
a.then(y=>console.log(y),
n=>console.log(n)
).then(()=>{return b}).then(y=>console.log(y))

编译之后;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var Promise = (function () {
function Promise(fn) {
_classCallCheck(this, Promise);

this.state = 'pending';
this.value = null;
this.deferreds = [];
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
fn(this.resolve, this.reject);
}

_createClass(Promise, [{
key: 'handle',
value: function handle(deferred) {

if (this.state === 'pending') {
this.deferreds.push(deferred);
return;
}
var cb = this.state === 'fulfilled' ? deferred.onFulfilled : deferred.onRejected,
ret;
if (cb === null) {
cb = this.state === 'fulfilled' ? deferred.resolve : deferred.reject;
cb(this.value);
return;
}
try {
ret = cb(this.value);
deferred.resolve(ret);
} catch (e) {
deferred.reject(e);
}
}
}, {
key: 'resolve',
value: function resolve(newValue) {
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
then.call(newValue, this.resolve, this.reject);
return;
}
}
this.state = 'fulfilled';
this.value = newValue;
this.finale();
}
}, {
key: 'reject',
value: function reject(reason) {
this.state = 'rejected';
this.value = reason;
this.finale();
}
}, {
key: 'finale',
value: function finale() {
setTimeout((function () {
console.log(this);
this.deferreds.forEach((function (deferred) {

this.handle(deferred);
}).bind(this));
}).bind(this), 0);
}
}, {
key: 'then',
value: function then(onFulfilled, onRejected) {

return new Promise((function (resolve, reject) {

this.handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
}).bind(this));
}
}]);

return Promise;
})();

var a = new Promise(function (res, rej) {
setTimeout(function () {
var a = 1;
var b = 2;
if (1) {
res(a);
} else {
rej(b);
}
}, 2000);
});

var b = new Promise(function (res, rej) {
setTimeout(function () {
var c = 3;
var d = 4;
if (1) {

res(c);
} else {
rej(d);
}
}, 2000);
});

a.then(function (y) {
return console.log(y);
}, function (n) {
return console.log(n);
}).then(function () {
return b;
}).then(function (y) {
return console.log(y);
});

一点人生的经验:

2016读过的书
2016读过的书,从一个拍黄片(php)的学着学着学到前端。。。

总结一下,外加一下觉得必须要学的知识。

使用Chrome DevTools的Timeline分析页面性能

前端基础进阶系列
一系列能够把JS的一些概念理解透彻,并且梳理的清楚的文章。认真看完获益匪浅,不禁想责怪作者为什么这么迟才把文章写出来。文章依然在更新,期待中。

阅读全文 »

一款js插件应该满足以下8个要求:

  1. 代码相对独立
  2. 链式操作
  3. 插件可配置
  4. 有可操作的方法,插件的生命周期可控制
  5. 配置可被缓存
  6. 可扩展
  7. 无冲突处理
  8. 事件代理,动态初始化

以往我们写插件的方式如下:

1
2
3
4
5
6
function pluginName($selector){
$.each($selector, function () {
// to do something...
});
}
// pluginName(document.getElementsByClassName("demo"));
阅读全文 »

技术向,
不搞笑。

0%