<table class="text">
<tr class="li1"><td class="ln"><pre class="de1">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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555 方法 JavaScript有五种方法可以确定一个值到底是什么类型,分别是 typeof运算符:数组,对象或者null时,都是object constructor法:constructor属性被修改之后,就无法用这个方法判断数组是数组了 instanceof运算符: Object.prototype.toString方法: Object.prototype.toString.call(arg) === '[object Array]'; Array.isArray法:es5 2.一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个50 级的台阶总共有多少种跳法。 restful-API URL 设计:动词 + 宾语/避免多级 URL - GET:读取(Read) - POST:新建(Create) - PUT:更新(Update) - PATCH:更新(Update),通常是部分更新 - DELETE:删除(Delete) 状态码 - 1xx:相关信息 - 2xx:操作成功 - 3xx:重定向 - 4xx:客户端错误 - 5xx:服务器错误 服务器回应 不要返回纯本文:application/json 函数式编程: 把运算过程定义为不同的函数,赋予名称,更直观,ramda库 var result = add(1,2).multiply(3).subtract(4) 特点: - 没有"副作用":函数内部与外部互动(最典型的情况,就是修改全局变量的值),所有功能就是返回一个新的值,没有其他行为 - 不修改状态:只是返回新的值,不修改系统变量 - 引用透明:运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。 好处: - 大量使用函数,减少了代码的重复 - 接近自然语言,易于理解 - 有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合:独立单元,输入一致,输出一致 react组件设计 将各种逻辑堆放在一起,到时候这个组件就会变得无比庞大,直到“无法收拾” 需要架构出商业用的云课堂,抽离了一部分样式组件,dom/样式 有些区别但很相似 设计思想:规范 vs. 自由 规范的组件库 产品风格和交互的统一,降低业务开发的复杂度 一些看似相似实则不同的业务需求,那就是实现 A 需求需要使用 a 组件,但是现有的 a 组件又不能完全支持 A 需求 - 重新开发一个完美支持 A 需求的 a+ 组件 成本增大 - 修改 a 组件源码使其支持 A 需求 后期难以维护 自由的组件库 借鉴antd,多写一些代码,不是该业务所特有,因为调用起来很麻烦:那就是默认值。我们可以在组件库中内置许多常用的子元素,当用户不指定子元素时,使用默认的子元素来完成渲染,开发很多借口,用户来选择定制,允许插入dom等,comment: 支持点赞/回复/收藏 内容:图片/文字/音频/时间/头像,需求变动,更改好更改,包会非常小,把代码都抽离出去了 规范: 回调规范: 内部方法用handler:eg imput获取值,暴露给外部方法用on来定义(依赖层级较深的底层组件时,就可以在 render 方法中一眼看出某个回调是在处理内部状态,还是将回调至更高一层。) CSS 类名:style-componet:前缀的方式来实现一套简化版的 CSS Modules 组件类别:维护者在一秒钟内判断出某个组件是纯渲染组件还是智能组件,将无样式组件抽离+逻辑组件container (有某种含义的就拆出来,并且有自己的逻辑) HOC:抽离相同逻辑,使用装饰器写法,清晰明了,shouldcomponnetupdate+immutable.js/页面埋点统计 https://zhuanlan.zhihu.com/p/24207409 哪些方法是通用的,其他程序可能也会用到,如果这些代码和React无关,那么就改成*纯函数, 原则: 单功能原则 让组件保持简单: 无状态/明确命名/太多的判断逻辑(if-else语句)通常意味着这个组件需要被拆分成更细的组件或模块。 https://github.com/frontend9/fe9-library/issues/172 1.写完的这个组件和其他的组件有没有什么通用的地方 comment/brief 2.在多嵌套和多循环的 - 考虑抽离dom为组件 3.将通过逻辑抽离为hoc:eg 数据埋点统计/pluginfy 把需要挂载到body下的功能抽离出(ad/未登录下载引导/激励发放) 只要出现两次就复用:避免修改完这个,又要改另一处使用 高阶组件的使用,推荐函数式的compose。例如 <真皮> - 高阶组件 <轮子> - 高阶组件 <椅子> - 组件 compose(<真皮>,<轮子>)(椅子) => 真皮轮椅 compose(<轮子>)(椅子) => 轮椅 compose(<真皮>)(椅子) => 真皮椅子 异步的几种方式和对比 redux-thunk:代码简单,实现简单,使reducer能接受一个函数(disptach/getState) function createThunkMiddleware(extraArgument) { return ({ dispatch,getState }) => next => action => { if (typeof action === 'function') { return action(dispatch,getState,extraArgument); } return next(action); }; } 函数内部极为复杂 如果需要为每一个异步操作都如此定义一个action,显然action不易维护,action的形式不统一,有的返回object,有的是函数 export function fetchData() { return (dispatch) => { dispatch(getData()) getPeople() .then((data) => { dispatch(getDataSuccess(data)) }) .catch((err) => console.log('err:',err)) } } Redux-promise:和redux-thunk连用,自动派发状态pending/success/fail function fetchData() { return { type: FETCH_DATA, payload: getPeople() } } action还是不统一,要抽离异步操作,混杂在里面 Redux-saga: https://github.com/Pines-Cheng/blog/issues/9 - takeLatest/takeEvery/throttle方法,可以便利的实现对事件的仅关注最近事件、关注每一次、事件限频 - 提供cancel/delay方法,可以便利的取消、延迟异步请求 - 提供race(effects),[…effects]方法来支持竞态和并行场景 系统交互的常驻进程 Saga = Worker + Watcher 感觉像是同步的在写代码,还加入了takeLasted等的一些流程控制方法 saga 就像是应用程序中一个单独的线程,它独自负责处理副作用,不改变同步化的代码,看起来清晰明了 Take // 监听一个type为 'FETCH_REQUESTED' 的action的执行 put - disptach Selector - 获取state数据 Call - 异步代码、fork不会等上一个返回,异步执行 export function fetchData() { return { type: FETCHING_DATA } } function* fetchData (action) { try { const data = yield getPeople() yield put({ type: FETCHING_DATA_SUCCESS,data }) } catch (e) { yield put({ type: FETCHING_DATA_FAILURE }) } } Rx.js - obserbel的思想 流的概念,复杂的用户操作 总结: Saga 更适用于较为复杂的应用,除此之外的其他所有情况 Redux Promise Middleware 都是十分合适的。笔者十分喜欢 Saga 中的 Generators 和 async-await,这些特性很有趣 Vue双向数据绑定+依赖收集 1、data属性,递归调用defineReactive,重写getter和setter方法 2、每个data属性维护一个dep实例(发布者)getter方法中,将每个模板上用到这个data属性创建一个watcher实例,render时,粗发getter,收集依赖,更改时,在setter中notify这些watcher,调用update方法 首先在 observer 的过程中会注册 get 方法,该方法用来进行「依赖收集」。在它的闭包中会有一个 Dep 对象,这个对象用来存放 Watcher 对象的实例。其实「依赖收集」的过程就是把 Watcher实例存放到对应的 Dep 对象中去。get 方法可以让当前的 Watcher 对象(Dep.target)存放到它的 subs 中(addSub)方法,在数据变化时,set 会调用 Dep 对象的 notify 方法通知它内部所有的 Watcher 对象进行视图更新。 这是 Object.defineProperty 的 set/get 方法处理的事情,那么「依赖收集」的前提条件还有两个: 1. 触发 get 方法; 2. 新建一个 Watcher 对象。 这个我们在 Vue 的构造类中处理。新建一个 Watcher 对象只需要 new 出来,这时候 Dep.target已经指向了这个 new 出来的 Watcher 对象来。而触发 get 方法也很简单,实际上只要把 render function 进行渲染,那么其中的依赖的对象都会被「读取」,这里我们通过打印来模拟这个过程,读取 test 来触发 get 进行「依赖收集」。 ssr react Babel-node bable支持jsx语法 renderString 将react的页面转换 css/png hook 拼接模板,把css/js挂载上去 更好的 SEO 无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记, MVC、MVVM model与服务端model相联通 view数据绑定的声明、 指令的声明、 事件绑定的声明 viewmodel 具体业务逻辑,联通mdoel 1. View 传送指令到 Controller 2. Controller 完成业务逻辑后,要求 Model 改变状态 3. Model 将新的数据发送到 View,用户得到反馈 SEO 1、扁平化结构(大网站一般为树形结构) 2、辅助导航、面包屑导航、次导航 关键词keywords 描述description H1H2H3使用 head标签 关键字强调 图片Alt属性 标题title 控制文章内部链接数量 添加外链 通用sass设计 各种color:主题色/背景色/辅助色/active,非active的状态 字体:字体颜色/大小/权重 - 会和UI定好(标题、副标题、正文)/高清方案 布局样式:flex的居中 尺寸:图标尺寸/常见间隔 装饰:圆角/边框(一般都为0.5px)/阴影 文字超出效果 Normarlize 兼容方案:ios取消点击灰色背景等 移动端适配 rem: html的大小,pc浏览器一般为16,在监视器看,不一样,动态设置根元素fontSize 计算:750px*1334px设计稿中 1rem = lib-flexible 计算缩放比:var scale = 1 / dpr 自动转换rem-sass插件 页面终端适配开源库:lib-flexible 方案关键点: - 动态改写<Meta name="viewport">标签 - 给元素添加data-dpr属性,并且动态改写data-dpr的值 - 给元素添加font-size属性,并且动态改写font-size的值 数据库范式 数据库表中的字段都是单一属性的,不可再分 数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖,即符合第二范式(只能依赖唯一主键) 传递依赖:在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合3NF。 web app与hybrid app差别 web app 开发快,迭代快,跨多个平台和终端 无法获取系统级别的通知,提醒,动效等等/体验较差 hybrid app 访问本地资源(通讯录,相册)/体验强 维护成本高(例如一款App已更新至V5版本,但仍有用户在使用V2, V3, V4版本,需要更多的开发人员维护之前的版本) 更新慢 关系型数据库与非关系数据库 性能更高、成本更低、好扩展 后期表多了,不容易维护,和其他MysqL库交互也不好,数据迁移很难 node 单线程,单线程的好处,减少了内存开销,操作系统的内存换页。 如果某一个事情,进入了,但是被I/O阻塞了,所以这个线程就阻塞了。 非阻塞I/O, 不会傻等I/O语句结束,而会执行后面的语句。 非阻塞就能解决问题了么?比如执行着小红的业务,执行过程中,小刚的I/O回调完成了,此时怎么办?? 事件机制,事件环,不管是新用户的请求,还是老用户的I/O完成,都将以事件方式加入事件环,等待调度。 区别: Node.js不是一种独立的语言,运行在JavaScript引擎上(V8) Node.js没有web容器 缺点: 单进程,单线程,只支持单核cpu,不能充分的利用多核cpu服务器,计算量大的不行,一蹦就全蹦了,高IO Bridge: 实现:JS调用Native,借助iframe来实现,只要发现是jsbridge://开头的地址,就不进行内容的加载,转而执行相应的调用逻辑: - H5向Native通信,以下为常见场景: 1. H5打开一个原生界面,H5只作为一个入口,后续逻辑均在原生界面处理 sample://route/module ID/sub ID 2. H5唤起一个原生界面执行一些逻辑,需要将结果返回给H5 sample://login/callback 使用消息分发机制(一种Android客户端架构设计分享 中也有说明)通知WebView调用此JavaScript回调 (所需的传值如登录状态、用户ID可封装为JSON格式,通过callback参数方式返回给H5。H5中处理此回调提取返回值,如登录成功,接下来可执行用户登录后相关的刷新操作) - Native向H5通信 1. 通常表现原生界面将某些结果传给H5页面或触发某些H5的行为 sample://lifecircle/status OC环境中如果要调用js方法,就可以通过window.WebViewJavascriptBridge在加上具体方法来调用。,该方法返回js脚本的执行结果 在原生代码中根据原生页面的生命周期触发一个JS回调,有需要监听页面生命周期的H5自行实现该回调即可,实现后JS即可获取原生页面状态从而进行对应处理 新版:初始化桥接对象,OC可以通过WebViewJavascriptBridge来调用JS里面的各种方法 在这个文件中也初始化了一个iframe实现webview的url跳转功能,从而激发webview代理方法的调用 OC环境和javascript环境的bridege都建立完毕。OC和javascript环境都有一个bridge对象,这个对象都保存着注册的每个方法和回调,并且维护着各自的消息队列、回调id、requestId等一系列信息。 初始化一个WebViewJavascriptBridge对象 ->有javascript环境注入的提供给OC调用的方法registerHandler,javascript调用OC环境方法的callHandler -> _fetchQueue这个方法的作用就是把javascript环境的方法序列化成JSON字符串,然后传入OC环境再转换->handleMessageFromObjC就是处理OC发给javascript环境的方法 - 分别在OC环境和javascript环境都保存一个bridge对象,里面维持着requestId,callbackId,以及每个id对应的具体实现。 - OC通过javascript环境的window.WebViewJavascriptBridge对象来找到具体的方法,然后执行。 - javascript通过改变iframe的src来出发webview的代理方法webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler从而实现把javascript消息发送给OC这个功能。 算法 快排 (1)在数据集之中,选择一个元素作为"基准"(pivot)。 (2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。 (3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。 var quickSort = function(arr) { if (arr.length <= 1) { return arr; } var pivotIndex = Math.floor(arr.length / 2); var pivot = arr.splice(pivotIndex,1)[0]; var left = []; var right = []; for (var i = 0; i < arr.length; i++){ if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat([pivot],quickSort(right)); }; 斐波那契数列求和 function fibonacci(n) { if(n==0 || n == 1) return n; return fibonacci(n-1) + fibonacci(n-2); } var fibonacci = (function () { var memory = {} return function(n) { if(n==0 || n == 1) { return n } if(memory[n-2] === undefined) { memory[n-2] = fibonacci(n-2) } if(memory[n-1] === undefined) { memory[n-1] = fibonacci(n-1) } return memory[n] = memory[n-1] + memory[n-2] } })() webSocket WebSocket 协议基于 TCP,解决过去为了实现即时通讯而采用的轮询方案,解决了大量交换 HTTP header,信息交换效率低的问题。在浏览器和服务器之间建立双向连接, 测试mocha supertest - 为 app 创建 http 服务器 - 对各个 API 发出请求 - 对响应内容进行断言 如何写入cookie 写一个中间件,判断为测试库的话,就req.cookie写一个已有的 escribe('User API',function () { // 为每个单元测试初始化数据 // 每个单元测试中可以通过 context 来访问相关的数据 beforeEach(function (done) { co(function* () { self.user1 = yield UserModel.create({ username: 'user1' }) self.token = jwt.sign({ _id: self.user1._id },config.jwtSecret,{ expiresIn: 3600 }) done() }).catch(err => { console.log('err: ',err) done() }) }) // 正常情况下访问 /user it('should get user info when GET /user with token',function (done) { const self = this request .get('/user') .set('Authorization',self.token) .expect(200) .end((err,res) => { res.body._id.should.equal(self.user1._id) done() }) }) 输入URL发生什么 SPA路由/历史管理 前端工程化 webpack原理 设计模式 路由 原文链接:https://www.f2er.com/note/411507.html