My Little World

learn and share


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于
My Little World

阿里云服务器使用

发表于 2018-05-01

购买云服务器

按照网站指引,配置服务器相关参数,提交订单,付钱

需要注意的是镜像就是将来在服务上安装的操作系统
如果这里选错,稍后还可以更换

更换镜像

相当于更换操作系统
更换操作系统
更换系统盘(公共镜像)

部署阿里云

在云端服务器搭建nodejs开发环境
远程连接ECS实例
分盘
部署Node.js项目(CentOS)
安装git(仅供参考)

部署自己的项目

安装好开发环境后就可以像在本地运行项目一样克隆项目运行项目

域名备案

我们在购买域名后,还要对域名进行备案
域名备案系统
按照流程进行备案即可

http转https

域名控制台

我们需要购买云盾证书服务
购买页面
在专业版OV SSL下选择品牌Symantec,
然后保护类型选择1个域名
会发现证书类型出现‘免费型DV SSL’,选择这个就可以买到免费证书

购买后根据申请流程填写资料等待流程走完就可以拿到证书
注意1.购买的域名在云解析DNS服务中又绑定,DNS会自动生成映射,2.选择系统生成CSR

拿到证书后
在CA证书管理页面可以下载到xxxxx.key,xxxx.pem文件

因为我这里用nodejs搭建服务器,所以只需将文件放入项目,修改项目文件为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Koa = require('koa');
const fs = require('fs');
const https = require('https');
const http = require('http');
var enforceHttps = require('koa-sslify');

const app = new Koa();

//将http请求强制转换成https请求
app.use(enforceHttps());

var options = {
key: fs.readFileSync('./ssl/214645895910665.key'),
cert: fs.readFileSync('./ssl/214645895910665.pem')
};

http.createServer(app.callback()).listen(80);
https.createServer(options, app.callback()).listen(443);
console.log('server is running....');

还要注意安全组有没有设置放行https的443端口
进入云服务器控制台
网络和安全下安全组, 点击配置规则, 进入规则列表
如果没有443端口,则点击添加安全组规则,端口设置为443即可

My Little World

异步函数generator和async

发表于 2018-03-28

generator/yield/next

generator函数即生成器函数,可以理解为用于产生生成器的函数
yield 关键字是只能用于generator函数,作为异步断点,相当于continue+return功能
next 关键字是生成器用于执行生成器函数的关键字,
即每调用一次,执行到yield定义的语句,把yield 后面的表达式结果当做返回值返回来
如果调用时传递了参数,则覆盖上次yield 的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function* helloworld(){
yield 'hello';
yield 'world';
let aa = 0;
let a = yield aa++; //yield赋值不用小括号
console.log(a);
yield 123+1;
console.log('Hello' + (yield 123)); //使用yield表达式用小括号
return 'endig';
}
let obj = helloworld();//并不会执行generator函数,只是生成生成器
obj.next();//{value: "hello", done: false}
obj.next();//{value: "world", done: false}
obj.next();//{value: 0, done: false}
obj.next('456');// 456 {value: 124, done: false} 如果不传值的话,a的值为undefined
obj.next();//{value: 123, done: false}
obj.next();// Helloundefined {value: "endig", done: true}; 不传参,yield返回undefined

next()是将yield表达式替换成一个值。
throw()是将yield表达式替换成一个return语句。
return()是将yield表达式替换成一个return语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const g = function* (x, y) {
let result = yield x + y;
return result;
};

const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}

gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;

gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));

gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;

如果yield表达式后面跟的是一个遍历器对象,需要在yield表达式后面加上星号,表明它返回的是一个遍历器对象。这被称为yield表达式
yield
后面的 Generator 函数(没有return语句时),等同于在 Generator 函数内部,部署一个for…of循环。
for…of循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法。

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
例1
function* inner() {
yield 'hello!';
}

function* outer1() {
yield 'open';
yield inner();
yield 'close';
}

var gen = outer1()
gen.next().value // "open"
gen.next().value // 返回一个遍历器对象
gen.next().value // "close"

function* outer2() {
yield 'open'
yield* inner()
yield 'close'
}

var gen = outer2()
gen.next().value // "open"
gen.next().value // "hello!"
gen.next().value // "close"

例2
let delegatedIterator = (function* () {
yield 'Hello!';
yield 'Bye!';
}());

let delegatingIterator = (function* () {
yield 'Greetings!';
yield* delegatedIterator;
yield 'Ok, bye.';
}());

for(let value of delegatingIterator) {
console.log(value);
}
// "Greetings!
// "Hello!"
// "Bye!"
// "Ok, bye."

如果yield*后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员。

1
2
3
4
5
function* gen(){
yield* ["a", "b", "c"];
}

gen().next() // { value:"a", done:false }

上面代码中,yield命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。

Generator 函数返回的遍历器对象,可以继承prototype,但不能当做普通构造函数,不会返回this

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
function* g() {
this.a = 11;
}

let obj = g();
obj.next();
obj.a // undefined
//可以进行改造
//执行的是遍历器对象f,但是生成的对象实例是obj
function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var f = F.call(F.prototype);

f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var f = F.call(F.prototype);

f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3
function* gen() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}

function F() {
return gen.call(gen.prototype);
}

var f = new F();

f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

实际应用

状态机

1
2
3
4
5
6
7
8
var clock = function*() {
while (true) {
console.log('Tick!');
yield;
console.log('Tock!');
yield;
}
};

异步操作的同步化写法

IMPORTANT!!!

Generator函数的暂停执行的效果,意味着可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield语句下面,反正要等到调用next方法时再执行。所以,Generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数。

只有当yield后面跟的函数先执行完,无论执行体里面有多少异步回调,都要等所有回调先执行完,才会执行等号赋值,以及再后面的操作。这也是yield最大的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function request(url) {
$.get(url, function(response){
it.next(response);
});
}

function* ajaxs() {
console.log(yield request('a.html'));
console.log(yield request('b.html'));
console.log(yield request('c.html'));
}

var it = ajaxs();

it.next();

// a.html
// b.html
// c.html

第1步:将所有异步代码的每一步都封装成一个普通的、可以有参数的函数,比如上面的request函数。上面例子三个异步代码却只定义了一个request函数,因为request函数能复用。如果不能复用的话,请老老实实定义三个普通函数,函数内容就是需要执行的异步代码。

第2步:定义一个生成器函数,把流程写进去,完全的同步代码的写法。生成器函数可以有参数。

第三步:定义一个变量,赋值为迭代器对象。迭代器对象可以加参数,参数通常将作为流程所需的初始值。

第四步:变量名.next()。不要给这个next()传参数,传了也没用,因为它找不到上一个yield语句。

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
//在上述每一步异步中间,都间隔3秒
function request(url) {
$.get(url, function(response){
it.next(response);
});
}

function sleep(time) {
setTimeout(function() {
console.log('I\'m awake.');
it.next();
}, time);
}

function* ajaxs(ur) {
console.log(yield request(ur));
yield sleep(3000);
console.log(yield request('b.html'));
yield sleep(3000);
console.log(yield request('c.html'));
}

var it = ajaxs('a.html');

it.next();

参考资料
参考资料

async/await

async 用于定义异步函数,相当于generator的*号,只不过async函数不需要像generator那样用next()去出发,只需要调用就能实现异步
await 用于async函数内部,作用是等待await 后面的异步流程结束后,执行asyn函数接下来的语句,相当于暂停符

async返回promise对象,因此可以连接then()或者catch()继续进行异步操作或者捕获错误
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,
除非遇到return语句或者抛出错误。
也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。即可以等任意表达式的结果
因此 await 返回异步函数return的结果,或者异步函数返回的promise的resolve的参数

1
2
3
如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

只要一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行。
解决中断执行的方法有两种,
一种是把await放在try…catch…里面,例5
另一种是给await的promise链接catch{},例6

优化:如果两个异步操作没有任何联系,不存在继发关系,最好让他们同时触发 例8,例9

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
例1.
async function lala(val){
let aa = await lili(val);
console.log(aa);//'red'
return 0;
}
function lili(val){
return new Promise((resolve,reject)=>{
resolve('red')
})
}
lala('kk').then(
val=>console.log(val),//0
err=>console.log(11111,err) //如果promise发生reject会传递到这里
);
例2.
async function lala(val){
let aa = await lili(val);
let bb = await bebe(val);
console.log(aa);
return 0;
}
function lili(val){
return new Promise((resolve,reject)=>{
resolve('red')
})
}
function bebe(val){
return new Promise((resolve,reject)=>{
reject('err') //产生错误
})
}
lala('kk').then(
val=>console.log(val),
err=>console.log(11111,err) //11111 "err" 只会打印这一处
);

例3.
async function f() {
return await 123;
}

f().then(v => console.log(v))

例4.
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}

例5.
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world

例6,
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// 出错了
// hello world

例7. //同例5例6

async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}

// 另一种写法

async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}

例8
//原来
let foo = await getFoo();
let bar = await getBar();
//优化
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

例9
async function logInOrder(urls) {
// 并发读取远程URL
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});

// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}

参考资料
相关资料

My Little World

关于性能优化

发表于 2018-03-24

优化哪些方面

加载速度
呈现效果

图片的优化

常见图片有三类
矢量图:几何图形
位图:像素
交错图:随加载过程模糊到清晰

使用策略
·是否有必要使用图片(可不可以不使用;效果能不能用CSS代替–>套路大列表)
·使用合适的格式(小体积webp;矢量图>位图;内容jpeg,修饰png,动画video/svg>gif)

加载策略<提高用户体验>
·先加载小图onload之后再加载交错大图
·懒加载
·尽量减少http请求,合理的使用雪碧图和base64编码的图片

CssSprites:页面风格多变,经常换肤;无需重复图形内容;不会增加css文件体积
Base64:极小极简单图片,可复用,适用小图标(缺点:css文件体积增大,导致解析时间变长)

其他资源的优化

也适用于图片

·懒加载:图片;组件,模块
·预加载:提前加载下一页;异步加载,提前发送数据请求加载数据资源
·减小传输体积——压缩;减少传输数量——打包
·打包分块,资源复用
·加快速度——静态资源放CDN
·网速,服务器响应,CDN

提高首页/加载速度

·雪碧图
·js放底部,css放头部
·减少DOM数量
·script标签设置异步加载async
·减少DNS查找,允许高度并行下载;
·减少http请求
·设置http头部缓存字段expires,E-tag,last-modified;减少/不使用cookie

移动端性能优化

My Little World

关于监控

发表于 2018-03-19

为什么要做监控

对自己的网站做到错误提前预知和排查
统计自己的网站相关数据,对网站进行优化

监控什么

业务数据:
PV(PAGE VIEW,页面浏览量,一个用户打开了网站的几个页面)
UV(unique visitor,访问某个站点或点击某条新闻的不同IP地址的人数)
点击率
转化率(浏览人数与注册人数之间的比率)
跳出率(浏览与离开/不喜欢的人数之间的比率)

稳定性:
所提供服务是否稳定,能否得知偏远地区数据稳定性
网络挂断情况能否立即得知,而不是通过用户告知
异地双活(A地的机器中断工作,通过切换其他地方的机器来提供服务)

性能:
首屏打开的性能
……

错误:
用户端的错误上报

用户操作路径:
操作流程,方便跟踪错误

怎么进行监控

根据监控的对象/内容将监控的数据进行上报,然后根据上报寻找异常

PV/UV,业务操作的上报;
将页面性能数据进行上报; ======>huatuo
将页面产生的错误上报;========>badjs
跟踪用户操作,将操作路径/流程上报;
接口请求成功与否的上报
用户数据的上报

一般的上报方案是

1
2
3
var img = new Image
img.src = `${url}`
//url是上报的接口,上报的数据随接口给到后台

1.上报不需要返回值,Image请求不会返回值
2.可以自动跨域,拿不到返回值,上报也不需要确定是否上报成功

服务端拿到接口传过来的数据,将数据写到log文件中,
在需要时进行搜索统计,或者在定时/计划任务时进行查询

使用grep命令进行查找
bad.js使用

上报

业务数据上报

人工标上报点

对onclick等触发事件手动帮上上报函数

1
2
3
4
5
6
7

function report(data){
var url = '....'+data
var img = new Image
img.src = `${url}`
}
dom.addEventListener("click", report);

点击截获上报

通过事件冒泡和DOM上的标记找到对应行动点,获取具体操作对象DOM进行上报

百度统计/google analytics

通过发送带上COOKIE的Image请求来定位用户与站点信息,对整个页面做定位

若用户把cookie清除了怎么办?
1.尝试让用户啊登录
2.百度、谷歌一般有多个登录态,可以给没有cookie的用户先注册个临时ID,等登录后再映射回来
3.浏览器终端机器本身可以产生一些类似mac地址的唯一识别码的东西,根据识别码进行跟踪,
或者使用指纹采集,fingerprint.js等手段为用户生成指纹进行跟踪

其他方案

将log数据线存储的本地IndexDB等地方,必要时服务器发起收集;
基于DSL的切面事件(before,after),将监控事件可以自动注入,这样实现配置平台让产品也可以自定义上报

轻松理解AOP思想(面向切面编程)

如何利用业务数据

查看统计业务情况
检查系统稳定性
错误如何产生
是否被非法套嵌
检测性能优化程度

性能数据上报

查看真实用户页面打开情况
通过时间这个维度去看

打点上报

在指定位置标记一些时间点标识,然后进行统计

利用permance.timing

关于Performance API

如何利用性能数据

用户真实数据,如白屏时间,从产品/经验值看是否能接收,是否需要优化
对于某些地区的响应慢,是不是网络问题,是否推动网络或CDN优化
验证性能优化效果
找到一个参考值,通过流程化的方式让未来我们的项目都能达到一个基准线

稳定性监控

主要靠后端,前端做辅助

错误上报(bad.js)

为什么要上报

防止出现问题时,能不能及时得知,方不方便排查
偏远地区CDN出现故障,导致页面空白
边界条件未验证导致错误
后台返回结果不符合预期导致错误
用户产生了不可预知的操作

怎么捕获

使用window.error捕获错误,可以将将msg,url,row行,col列,error错误等信息拿到
但以上信息不能确定是那个文件出了错误,
在firefox,chrome中的堆栈信息中可以根据上面的error找到是哪个文件出了错误
所以在上报之前根据堆栈信息找到文件再上报

script error

一般是文件跨域出现的错误
出现的场景和条件如下
通过window.onerror注册监听脚本错误事件
浏览器是firefox,chrome,safari,ie7+
页面内使用script标签引入非同域资源,且发生脚本错误
解决
1.设置cors
将跨域资源的response header的Access-Control-Allow-Origin设置为或者本域,
(一般设为
,因为防止第三个域也来请求该文件时,本域请求完,response header有缓存,导致第三个域资源无法使用)
然后在script标签添加属性 crossorigin
2.对入口和异步方法全部用try-catch包裹,做到任何时刻错误都能捕获
setTimeout setInterval
事件绑定
ajax callback
define require
业务主入口
monitor

My Little World

计算dns时间

发表于 2018-03-17

计算dns时间

H5之前 facebook提出的多普勒测速

1
2
3
4
5
6
7
8
9
t1  http://a-doppler.facebook.com/test_pixel?HTTP1.0&t=1&size=0k
t2 http://a-doppler.facebook.com/test_pixel?HTTP1.1&t=2&size=0k
t3 http://a-doppler.facebook.com/test_pixel?HTTP1.1&t=3&size=0k
t4 http://a-doppler.facebook.com/test_pixel?HTTP1.1&t=4&size=10k

t1 = DNS + TCP/IP +RTT
t2 = TCP/IP + RTT
t3 = RTT
10k /(t4–t3)~TCP bandwidth

第一次请求使用HTTP1.0请求,保证后面的第二次请求可以重新建立TCP/IP链接
因为进行过第一请求,DNS已经在浏览器有缓存,所以进行第二次请求时直接在浏览器查找
所以t2-t1就是DNS查询时间

DNS = t1-t2;

第三次请求在第二次请求已经建立TCP/IP的情况下发起,所以

TCP/IP = t2-t3;

第四次请求只是在第三次基础上新增请求资源大小,利用这个大小,可以计算出大致贷款

bandwidth = 10k/(t4-t3)

H5之后 performance.timing

var time = window.performance.timing
DNStime = time.domainLookupEnd - time.domainLookupStart;

目前safari浏览器移动端均不支持,移动端Android不支持
performance.timing MDN

My Little World

为什么尽量将js放页面底部

发表于 2018-03-17

为什么尽量将js放页面底部

1,js是单线程的,一个时间只能干一件事
2.浏览器是多线程的,一个时候可以并行干多件事
3.一个浏览器打开一个页面,就是一个js线程
4.浏览器的多线线程一般会有:js引擎线程,界面渲染UI线程,浏览器事件触发线程,http请求线程等
5.当我们打开一个页面时,浏览器渲染html文件是从上往下渲染的,
UI引擎会根据html文件里面图片,css等的书写先后顺序依次去download,通过http请求拿到资源即加载结束
但如果碰到js文件,会将js文件先加载,加载结束后通知js引擎线程去执行
6.一旦js文件里面需要请求大量数据或者有对页面DOM的操作,就会造成页面空白或者由于DOM还没有加载完直接报错
7.为避免这样的情况,所以尽量将js放页面底部

哪些js可以不放在底部

1.操作在document.ready之后执行的
2.处理兼容性的文件,例如早期IE兼容H5新增标签的支持文件html5shiv
3.jquery类库,通常引用CDN地址,经压缩后不会很大,而且很大几率已被用户缓存下来

My Little World

四种规范

发表于 2018-01-21

common.js 规范

node.js的模块编程规范,适用于服务端,不能在浏览器使用
涉及到四个环境变量
module,exports,require,global
同步加载
require()引入
module.exports() 输出

AMD规范(require.js)

依赖在服务端,异步加载,提前加载所需模块
require([module], callback); 引入,等待所有依赖模块加载完后再执行回调函数
define() 输出return的内容

CMD规范(sea.js)

可异步加载,按需加载,不用提前加载
define 定义
export 输出
require 引入

es6规范

使用import 引入模块,需要bable转成require,浏览器才能运行
使用export 输出

链接
相关

My Little World

各种框架框架的数据绑定机制

发表于 2018-01-21

angular js

脏检查机制

react

虚拟DOM:react 在初始化的时候会render一颗dom树,当state/props发生改变的时候,render函数会再渲染出另外一棵树与之前的dom树进行对比,新渲染的树就是虚拟dom树
diff 算法:比较dom树时的算法,

只会对同层节点进行比较;
父节点不同,不会再去比较子节点;

同层比较时,遇到结点类型不同,比如结点顺序发生变化时
没有key属性的时候,自己以及自己以后的结点都会被删除,重新建;删除时,会卸载删除的结点以及以后的结点,再新建以后的结点
如果有key的话,则只会新增插入的结点,卸载被替换的结点 其他结点则只是update,不受影响;删除的话,只卸载删除的结点

遇到结点类型相同,
要去比较属性是否相同,如果不同,则只替换属性,只进行update

性能优化:避免不必要渲染
使用shouldComponentUpdate(),当这个方法返回true的时候,需要重新渲染,false的时候不需要(默认是true).
使用PureComponent组件,它会自动浅对比props/state,当两者相同的时候不渲染节点。
PureComponent只会浅比较,所以不适合用于深层嵌套的对象。
同时,PureComponent不仅仅会跳过自己的重新渲染,还会跳过它所有子节点的,所以要注意,用它的时候是最好没有子节点并且不依赖于global state的展示型组件。
reactlife

vue1.0

单检查

vue2.0

虚拟DOM和diff算法

vuelife

检测数据变更的4中方法

手动触发绑定
脏检查机制
数据对象劫持,使用Object.defineProperty
使用proxy

三大框架对比

1.数据检查更新原理不同
angularjs用脏检查
vue和react 使用diff算法
后两者效率更高

2.构建组件使用来说
angularjs更需要遵守框架规则,相对比较严谨
而vue次之,具备自己的响应式机制,所以要遵循一定的规则
最开放的是react,可以从更底层去定义自己想要的组件,
也可能跟react定位有关,一个用于构建UI的js库
它是一个库
库和框架的区别就是
库是,你调用库,作为开发者你有主动权
框架是你被框架调用,作为开发者你要听框架的
缺点就是数据改变自己要写监听逻辑

3.从使用场景上
angularjs和react都比较适合应用于大型网站开发
而vue小巧轻便,适合小项目开发

4.从学习成本上
vue最低,从用人角度来说最好找人
然后由于angular的规范严谨,导致需要学习的文档较多,
学习成本显而易见
react的开发角度相对以上两个框架更加向下,
有点像写早期模板语言,加上JSX语言的引入,
所以学习成本自然也是不低的

My Little World

模板引擎前后端优缺点

发表于 2018-01-04

模板引擎在后端
优点
在第一次请求时不需要发送请求数据的的HTTP,加载速度可能会快一些;
利于SEO;

缺点
前端模板有改动,后端对应的模板页面也要改动;
如果页面有复杂JS,前端因为没有数据不方便调试,后端需要使用js进行修改;
服务器负载压力大

模板引擎在前端
优点
前后端分离,后台只需要处理逻辑业务,提供接口,减少服务端压力;
前端修改方便;
可跨平台,兼容不同后端技术

缺点
不利于SEO(搜索引擎无法抓取页面的数据,因为只是模板,没有数据内容)
JS有可能被用户禁用,数据安全性低

My Little World

ng-src

发表于 2018-01-04

ng-src

img 里面使用src=”{ { } }“会在页面一开始加载模板的时候,不会执行{ { } },直接去请求资源,造成404错误
如果使用ng-src = “{ { } }“就会避免以上问题,ng-src会先去执行{ { } },得到资源地址后再去请求资源
ng-src 指令确保的 AngularJS 代码执行前不显示图片。

1…141516…27
YooHannah

YooHannah

262 日志
1 分类
23 标签
RSS
© 2025 YooHannah
由 Hexo 强力驱动
主题 - NexT.Pisces