From 55a89dc4a589f979e4e39d2ff6549e472319687c Mon Sep 17 00:00:00 2001 From: LiuBinPeng Date: Tue, 24 Aug 2021 09:51:28 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20Hybrid=E3=80=81=E9=A2=86=E5=9F=9F?= =?UTF-8?q?=E9=A9=B1=E5=8A=A8=E8=AE=BE=E8=AE=A1=E4=B8=8E=20BFF=E3=80=81?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 12292 -> 12292 bytes .vscode/1.96.md | 14 +++ Chapter1 - iOS/1.44.md | 111 +++++++++++++---------- Chapter1 - iOS/1.74.md | 26 +++--- Chapter2 - Web FrontEnd/2.18.md | 5 + Chapter3 - Server/3.10.md | 11 +++ Chapter3 - Server/chapter3.md | 3 +- Chapter7 - Geek Talk/7.22.md | 22 +++++ Chapter7 - Geek Talk/chapter7.md | 3 +- Chapter9 - Ragdoll/Chapter9.md | 101 ++++++++++++++++++++- SUMMARY.md | 7 +- assets/Hybrid-OfflinePackageDownload.png | Bin 0 -> 14958 bytes assets/Hybrid-OfflinePackageLoad.png | Bin 0 -> 26112 bytes 13 files changed, 237 insertions(+), 66 deletions(-) create mode 100644 .vscode/1.96.md create mode 100644 Chapter3 - Server/3.10.md create mode 100644 Chapter7 - Geek Talk/7.22.md create mode 100644 assets/Hybrid-OfflinePackageDownload.png create mode 100644 assets/Hybrid-OfflinePackageLoad.png diff --git a/.DS_Store b/.DS_Store index 5693f8e5f30b2ddc594052b1e8c990584b97061b..3cfdfa0088fa1171ba66b24e868c477292e16a83 100644 GIT binary patch delta 75 zcmZokXi3JypZprFuBU1|<1w&J#$?__4jI$=&smL?V-mI#0nRW6)ammTg b#N{`$YJ6c~5@47dr=qagO?49!R6-5_nn@TV delta 81 zcmZokXi37QrBTyd?LmopuLka+)ZWfvV diff --git a/.vscode/1.96.md b/.vscode/1.96.md new file mode 100644 index 0000000..894b632 --- /dev/null +++ b/.vscode/1.96.md @@ -0,0 +1,14 @@ +# 一个提高 App 运算性能的想法 + +想到了一个场景,大概是客户端、H5 网页端、Electron 桌面端都需要大量的 DB 操作、JS 执行大量数据的计算。这些常见的共同特点是计算特别大,耗费 CPU 算力。想到了 H5 网页、Electron 等都会使用 GPU 去渲染,那么这些复杂计算,能不能也利用 GPU 强大的算力去实现。 + + +考虑到某些机器上可能没有 GPU 能力,感觉可以做一个封装,内部根据当前内存情况、GPU 情况,派发任务到 GPU 还是普通的 JS 单线程的异步任务上,没有 GPU 则直接使用异步任务 + +由于我们的场景会存在很多的离线能力,所以这个时候很多的计算都需要本地完成,后续的 PC 收银参考客户端,做离线 DB 的操作、营销 JS 计算、很多运算都可以放 GPU + +比如,营销 JS 的计算代码,目前就在客户端(iOS、Android)存在,H5 JS 也存在,那么 PC 收银桌面端,也可以享用这个能力。 + +利用 CommonJS 规范,Webpack 打包出一个 distJS,多个端服用。内部判断当前设备支不支持 GPU,支持则在 GPU 上运算,不支持则在 CPU 上异步计算。 + +前端开源了 [gpu.js](https://github.com/gpujs/gpu.js],同样客户端也可以实现类似的设计。做到一个高性能计算的效果。 \ No newline at end of file diff --git a/Chapter1 - iOS/1.44.md b/Chapter1 - iOS/1.44.md index 82e5899..ca90742 100644 --- a/Chapter1 - iOS/1.44.md +++ b/Chapter1 - iOS/1.44.md @@ -1,15 +1,15 @@ # 一个 Hybrid SDK 设计与实现 -随着移动浪潮的兴起,各种 App 层出不穷,极速发展的业务拓展提升了团队对开发效率的要求,这个时候纯粹使用 Native 开发技术成本难免会更高一点。而 H5 的低成本、高效率、跨平台等特性马上被利用起来了,形成一种新的开发模式: Hybrid App - -作为一种混合开发的模式,Hybrid App 底层依赖于 Native 提供的容器(Webview),上层使用各种前端技术完成业务开发(现在三足鼎立的 Vue、React、Angular),底层透明化、上层多样化。这种场景非常有利于前端介入,非常适合业务的快速迭代。于是 Hybrid 火了。 - -大道理谁都懂,但是按照我知道的情况,还是有非常多的人和公司在 Hybrid 这一块并没有做的很好,所以我将我的经验做一个总结,希望可以帮助广大开发者的技术选型有所帮助 +> 随着移动浪潮的兴起,各种 App 层出不穷,极速发展的业务拓展提升了团队对开发效率的要求,这个时候纯粹使用 Native 开发技术成本难免会更高一点。而 H5 的低成本、高效率、跨平台等特性马上被利用起来了,形成一种新的开发模式: Hybrid App +> +> 作为一种混合开发的模式,Hybrid App 底层依赖于 Native 提供的容器(Webview),上层使用各种前端技术完成业务开发(现在三足鼎立的 Vue、React、Angular),底层透明化、上层多样化。这种场景非常有利于前端介入,非常适合业务的快速迭代。于是 Hybrid 火了。 +> +> 大道理谁都懂,但是按照我知道的情况,还是有非常多的人和公司在 Hybrid 这一块并没有做的很好,所以我将我的经验做一个总结,希望可以帮助广大开发者的技术选型有所帮助 -## Hybrid 的一个现状 +## 一、Hybrid 现状 可能早期都是 PC 端的网页开发,随着移动互联网的发展,iOS、Android 智能手机的普及,非常多的业务和场景都从 PC 端转移到移动端。开始有前端开发者为移动端开发网页。这样子早期资源打包到 Native App 中会造成应用包体积的增大。越来越多的业务开始用 H5 尝试,这样子难免会需要一个需要访问 Native 功能的地方,这样子可能早期就是懂点前端技术的 Native 开发者自己封装或者暴露 Native 能力给 JS 端,等业务较多的时候者样子很明显不现实,就需要专门的 Hybrid 团队做这个事情;量大了,就需要规矩,就需要规范。 @@ -27,12 +27,12 @@ Hybrid 在大量应用的时候就需要一定的规范,那么本文将讨论 -## Native 与前端分工 +## 二、Native 与前端分工 在做 Hybird 架构设计之前我们需要分清 Native 与前端的界限。首先 Native 提供的是宿主环境,要合理利用 Native 提供的能力,要实现通用的 Hybrid 架构,站在大前端的视觉,我觉得需要考虑以下核心设计问题。 -### 交互设计 +### 1. 交互设计 Hybrid 架构设计的第一要考虑的问题就是如何设计前端与 Native 的交互,如果这块设计不好会对后续的开发、前端框架的维护造成深远影响。并且这种影响是不可逆、积重难返。所以前期需要前端与 Native 好好配合、提供通用的接口。比如 @@ -43,14 +43,14 @@ Hybrid 架构设计的第一要考虑的问题就是如何设计前端与 Native -### 账号信息设计 +### 2. 账号信息设计 账号系统是重要且无法避免的,Native 需要设计良好安全的身份验证机制,保证这块对业务开发者足够透明,打通账户体系 -### Hybrid 开发调试 +### 3. Hybrid 开发调试 功能设计、编码完并不是真正结束,Native 与前端需要商量出一套可开发调试的模型,不然很多业务开发的工作难以继续。 @@ -67,7 +67,7 @@ Android 调试技巧: -## Hybrid 交互设计 +## 三、Hybrid 交互设计 Hybrid 交互无非是 Native 调用 H5 页面JS 方法,或者 H5 页面通过 JS 调 Native 提供的接口。2者通信的桥梁是 Webview。 业界主流的通信方法:1.桥接对象(时机问题,不太主张这种方式);2.自定义 Url scheme @@ -82,7 +82,7 @@ weixin:// 可以打开微信。 -### JS to Native +### 1. JS to Native Native 在每个版本都会提供一些 Api,前端会有一个对应的框架团队对其封装,释放业务接口。举例 @@ -116,7 +116,7 @@ SDGHybridReady(function(arg){ -### Api 交互 +### 2. Api 交互 调用 Native Api 接口的方式和使用传统的 Ajax 调用服务器,或者 Native 的网络请求提供的接口相似 ![Api交互](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HybridApi.jpg) @@ -128,7 +128,7 @@ SDGHybridReady(function(arg){ -### 格式约定 +### 3. 格式约定 交互的第一步是设计数据格式。这里分为请求数据格式与响应数据格式,参考 Ajax 模型: ``` @@ -295,13 +295,13 @@ typedef NS_ENUM(NSInteger){ -## 常用交互 Api +## 四、常用交互 Api 良好的交互设计是第一步,在真实业务开发中有一些 Api 一定会由应用场景。 -### 跳转 +### 1. 跳转 跳转是 Hybrid 必用的 Api 之一,对前端来说有以下情况: - 页面内跳转,与 Hybrid 无关 - H5 跳转 Native 界面 @@ -361,8 +361,7 @@ back 与 forward 一致,可能会有 animatetype 参数决定页面切换的 - -## Header 组件的设计 +### 2. Header 组件的设计 Native 每次改动都比较“慢”,所以类似 Header 就很需要。 1. 主流容器都是这么做的,比如微信、手机百度、携程 @@ -590,8 +589,7 @@ define([], function () { - -## 请求类 +### 3. 请求类 虽然 get 类请求可以用 jsonp 方式绕过跨域问题,但是 post 请求是一个拦路虎。为了安全性问题服务器会设置 cors 仅仅针对几个域名,Hybrid 内嵌静态资源可能是通过本地 file 的方式读取,所以 cors 就行不通了。另外一个问题是防止爬虫获取数据,由于 Native 针对网络做了安全性设置(鉴权、防抓包等),所以 H5 的网络请求由 Native 完成。可能有些人说 H5 的网络请求让 Native 走就安全了吗?我可以继续爬取你的 Dom 节点啊。这个是针对反爬虫的手段一。想知道更多的反爬虫策略可以看看我这篇文章 [Web反爬虫方案](https://github.com/FantasticLBP/Anti-WebSpider) @@ -628,7 +626,7 @@ requestHybrid({ -## 常用 NativeUI 组件 +## 五、常用 NativeUI 组件 一般情况 Native 通常会提供常用的 UI,比如 加载层loading、消息框toast @@ -663,7 +661,7 @@ Native UI与前端UI不容易打通,所以在真实业务开发过程中,一 -## 账号系统的设计 +## 六、账号系统的设计 Webview 中跑的网页,账号登录与否由是否携带密钥 cookie 决定(不能保证密钥的有效性)。因为 Native 不关注业务实现,所以每次载入都有可能是登录成功跳转回来的结果,所以每次载入都需要关注密钥 cookie 变化,以做到登录态数据的一致性。 @@ -704,7 +702,7 @@ HybridUI.logout = function () { -## Hybrid 资源管理 +## 七、Hybrid 资源管理 Hybrid 的资源需要 `增量更新` 需要拆分方便,所以一个 Hybrid 资源结构类似于下面的样子 @@ -738,7 +736,7 @@ WebApp -## 增量更新 +## 八、增量更新 每次业务开发完毕后都需要在打包分发平台进行部署上线,之后会生成一个版本号。 @@ -760,9 +758,9 @@ WebApp -## 一些零散的解决方案 +## 九、体验优化 -1. 静态直出 +### 1. 静态直出 “直出”这个概念对前端同学来说,并不陌生。为了优化首屏体验,大部分主流的页面都会在服务器端拉取首屏数据后通过 NodeJs 进行渲染,然后生成一个包含了首屏数据的 Html 文件,这样子展示首屏的时候,就可以解决内容转菊花的问题了。 当然这种页面“直出”的方式也会带来一个问题,服务器需要拉取首屏数据,意味着服务端处理耗时增加。 @@ -771,18 +769,16 @@ WebApp 我们可以做一个类似的事情,自动同步最新的代码和数据,然后生成新的含首屏 Html,并发布到 CDN 上面去 - -2. 离线预推 +### 2. 离线预推 页面发布到 CDN 上面去后,那么 WebView 需要发起网络请求去拉取。当用户在弱网络或者网速比较差的环境下,这个加载时间会很长。于是我们通过离线预推的方式,把页面的资源提前拉取到本地,当用户加载资源的时候,相当于从本地加载,即使没有网络,也能展示首屏页面。这个也就是大家熟悉的离线包。 手 Q 使用 7Z 生成离线包, 同时离线包服务器将新的离线包跟业务对应的历史离线包进行 BsDiff 做二进制差分,生成增量包,进一步降低下载离线包时的带宽成本,下载所消耗的流量从一个完整的离线包(253KB)降低为一个增量包(3KB)。 - -https://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247488218&idx=1&sn=21afe07eb642162111ee210e4a040db2&chksm=f951a799ce262e8f6c1f5bb85e84c2db49ae4ca0acb6df40d9c172fc0baaba58937cf9f0afe4&scene=27#wechat_redirect +[手Q开源Hybrid框架VasSonic介绍,极致的页面加载速度优化](https://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247488218&idx=1&sn=21afe07eb642162111ee210e4a040db2&chksm=f951a799ce262e8f6c1f5bb85e84c2db49ae4ca0acb6df40d9c172fc0baaba58937cf9f0afe4&scene=27#wechat_redirect) -3. 拦截加载 +### 3. 拦截加载 事实上,在高度定制的 wap 页面场景下,我们对于 webview 中可能出现的页面类型会进行严格控制。可以通过内容的控制,避免 wap 页中出现外部页面的跳转,也可以通过 webview 的对应代理方法,禁掉我们不希望出现的跳转类型,或者同时使用,双重保护来确保当前 webview 容器中只会出现我们定制过的内容。既然 wap 页的类型是有限的,自然想到,同类型页面大都由前端采用模板生成,页面所使用的 html、css、js 的资源很可能是同一份,或者是有限的几份,把它们直接随客户端打包在本地也就变得可行。加载对应的 url 时,直接 load 本地的资源。 对于 webview 中的网络请求,其实也可以交由客户端接管,比如在你所采用的 Hybrid 框架中,为前端注册一个发起网络请求的接口。wap 页中的所有网络请求,都通过这个接口来发送。这样客户端可以做的事情就非常多了,举个例子,NSURLProtocol 无法拦截 WKWebview 发起的网络请求,采用 Hybrid 方式交由客户端来发送,便可以实现对应的拦截。 @@ -792,25 +788,46 @@ https://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247488218&idx=1&sn=21afe0 NSURLProtocol能够让你去重新定义苹果的URL加载系统(URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等。当URL Loading System使用NSURLRequest去获取资源的时候,它会创建一个NSURLProtocol子类的实例,你不应该直接实例化一个NSURLProtocol,NSURLProtocol看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。                                        -4. WKWebView 网络请求拦截 -方法一(Native 侧): -原生 WKWebView 在独立于 app 进程之外的进程中执行网络请求,请求数据不经过主进程,因此在 WKWebView 上直接使用 NSURLProtocol 是无法拦截请求的。 -但是由于 mPaas 的离线包机制强依赖网络拦截,所以基于此,mPaaS 利用了 WKWebview 的隐藏 api,去注册拦截网络请求去满足离线包的业务场景需求,参考代码如下: +### 4. WKWebView 网络请求拦截 -```Objective-c -[WKBrowsingContextController registerSchemeForCustomProtocol:@"https"] -``` -但是因为出于性能的原因,WKWebView 的网络请求在给主进程传递数据的时候会把请求的 body 去掉,导致拦截后请求的 body 参数丢失。 +- 方法一(Native 侧): + 原生 WKWebView 在独立于 app 进程之外的进程中执行网络请求,请求数据不经过主进程,因此在 WKWebView 上直接使用 NSURLProtocol 是无法拦截请求的。 -在离线包场景,由于页面的资源不需要 body 数据,所以离线包可以正常使用不受影响。但是在 H5 页面内的其他 post 请求会丢失 data 参数。 + 但是由于 mPaas 的离线包机制强依赖网络拦截,所以基于此,mPaaS 利用了 WKWebview 的隐藏 api,去注册拦截网络请求去满足离线包的业务场景需求,参考代码如下: -为了解决 post 参数丢失的问题,mPaas 通过在 js 注入代码,hook 了 js 上下文里的 XMLHTTPRequest 对象解决。 + ```Objective-c + [WKBrowsingContextController registerSchemeForCustomProtocol:@"https"] + ``` -通过在 JS 层把方法内容组装好,然后通过 WKWebView 的 messageHandler 机制把内容传到主进程,把对应 HTTPBody 然后存起来,随后通知 JS 端继续这个请求,网络请求到主进程后,在将 post 请求对应的 HttpBody 添加上,这样就完成了一次 post 请求的处理。整体流程可以参考如下: -![ajax-时序图](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-05-28-WKWebViewRequestHook) -通过上面的机制,既满足了离线包的资源拦截诉求,也解决了 post 请求 body 丢失的问题。但是在一些场景还是存在一些问题,需要开发者进行适配。 + 但是因为出于性能的原因,WKWebView 的网络请求在给主进程传递数据的时候会把请求的 body 去掉,导致拦截后请求的 body 参数丢失。 -方法二(JS 侧): -通过 AJAX 请求的 hook 方式,将网络请求的信息代理到客户端本地。能拿到 WKWebView 里面的 post 请求信息,剩下的就不是问题啦。 -AJAX hook 的实现可以看这个 [Repo](https://github.com/wendux/Ajax-hook). \ No newline at end of file + 在离线包场景,由于页面的资源不需要 body 数据,所以离线包可以正常使用不受影响。但是在 H5 页面内的其他 post 请求会丢失 data 参数。 + + 为了解决 post 参数丢失的问题,mPaas 通过在 js 注入代码,hook 了 js 上下文里的 XMLHTTPRequest 对象解决。 + + 通过在 JS 层把方法内容组装好,然后通过 WKWebView 的 messageHandler 机制把内容传到主进程,把对应 HTTPBody 然后存起来,随后通知 JS 端继续这个请求,网络请求到主进程后,在将 post 请求对应的 HttpBody 添加上,这样就完成了一次 post 请求的处理。整体流程可以参考如下: + ![ajax-时序图](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2021-05-28-WKWebViewRequestHook) + 通过上面的机制,既满足了离线包的资源拦截诉求,也解决了 post 请求 body 丢失的问题。但是在一些场景还是存在一些问题,需要开发者进行适配。 + +- 方法二(JS 侧): + 通过 AJAX 请求的 hook 方式,将网络请求的信息代理到客户端本地。能拿到 WKWebView 里面的 post 请求信息,剩下的就不是问题啦。 + AJAX hook 的实现可以看这个 [Repo](https://github.com/wendux/Ajax-hook). + + + + +## 十、离线包 + +传统的 H5 技术容易受到网络环境影响,因而降低 H5 页面的性能。通过使用离线包,可以解决该问题,同时保留 H5 的优点。 + +**离线包** 是将包括 HTML、JavaScript、CSS 等页面内静态资源打包到一个压缩包内。预先下载该离线包到本地,然后通过客户端打开,直接从本地加载离线包,从而最大程度地摆脱网络环境对 H5 页面的影响。 + +使用 H5 离线包可以给您带来以下优势: + +- **提升用户体验**:通过离线包的方式把页面内静态资源嵌入到应用中并发布,当用户第一次开启应用的时候,就无需依赖网络环境下载该资源,而是马上开始使用该应用。 +- **实现动态更新**:在推出新版本或是紧急发布的时候,您可以把修改的资源放入离线包,通过更新配置让应用自动下载更新。因此,您无需通过应用商店审核,就能让用户及早接收更新。 + +![离线包下载流程](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Hybrid-OfflinePackageDownload.png) + +![离线包加载流程](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Hybrid-OfflinePackageLoad.png) \ No newline at end of file diff --git a/Chapter1 - iOS/1.74.md b/Chapter1 - iOS/1.74.md index 71013c0..a27d258 100644 --- a/Chapter1 - iOS/1.74.md +++ b/Chapter1 - iOS/1.74.md @@ -4,11 +4,11 @@ App 的性能问题是影响用户体验的重要因素之一。性能问题主要包含:Crash、网络请求错误或者超时、UI 响应速度慢、主线程卡顿、CPU 和内存使用率高、耗电量大等等。大多数的问题原因在于开发者错误地使用了线程锁、系统函数、编程规范问题、数据结构等等。解决问题的关键在于尽早的发现和定位问题。 -xf 本篇文章着重总结了 APM 的原因以及如何收集数据。APM 数据收集后结合数据上报机制,按照一定策略上传数据到服务端。服务端消费这些信息并产出报告。请结合[姊妹篇](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.80.md), 总结了如何打造一款灵活可配置、功能强大的数据上报组件。 +本篇文章着重总结了 APM 的原因以及如何收集数据。APM 数据收集后结合数据上报机制,按照一定策略上传数据到服务端。服务端消费这些信息并产出报告。请结合[姊妹篇](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.80.md), 总结了如何打造一款灵活可配置、功能强大的数据上报组件。 ## 一、卡顿监控 -卡顿问题,就是在主线程上无法响应用户交互的问题。影响着用户的直接体验,所以针对 App 的卡顿监控是 APM 里面重要的一环。 +卡顿问题,程度较低就是掉帧,比如用户在滑动某个列表的时候会有不流畅的体验,但是应用程序还是可以相应的。严重些就是 ANR,就是短时间在主线程上无法响应用户交互的问题。影响着用户的直接体验,所以针对 App 的卡顿监控是 APM 里面重要的一环。 FPS(frame per second)每秒钟的帧刷新次数,iPhone 手机以 60 为最佳,iPad 某些型号是 120,也是作为卡顿监控的一项参考参数,为什么说是参考参数?因为它不准确。先说说怎么获取到 FPS。CADisplayLink 是一个系统定时器,会以帧刷新频率一样的速率来刷新视图。 `[CADisplayLink displayLinkWithTarget:self selector:@selector(###:)]`。至于为什么不准我们来看看下面的示例代码 @@ -2697,6 +2697,7 @@ CFNetwork 使用 CFReadStreamRef 来传递数据,使用回调函数的形式 } @end + ``` @implementation NetworkDelegateProxy @@ -2713,31 +2714,31 @@ CFNetwork 使用 CFReadStreamRef 来传递数据,使用回调函数的形式 }); return _sharedInstance; - } + } #pragma mark - public Method + (instancetype)setProxyForObject:(id)originalTarget withNewDelegate:(id)newDelegate - { + { NetworkDelegateProxy *instance = [NetworkDelegateProxy sharedInstance]; instance->_originalTarget = originalTarget; instance->_NewDelegate = newDelegate; return instance; - } + } - (void)forwardInvocation:(NSInvocation *)invocation - { + { if ([_originalTarget respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:_originalTarget]; [((NSURLSessionAndConnectionImplementor *)_NewDelegate) invoke:invocation]; } - } + } - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel - { + { return [_originalTarget methodSignatureForSelector:sel]; - } + } @end ``` @@ -5538,12 +5539,13 @@ parseJSError(line, column); }); return _sharedManager; } + ``` #pragma mark - public Method - (void)startMonitor - { + { APMMLog(@"crash monitor started"); #ifdef DEBUG @@ -5569,14 +5571,14 @@ parseJSError(line, column); } - (void)installKSCrash - { + { [[APMCrashInstallation sharedInstance] install]; [[APMCrashInstallation sharedInstance] sendAllReportsWithCompletion:nil]; [APMCrashInstallation sharedInstance].onCrash = onCrash; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ _isCanAddCrashCount = NO; }); - } + } ``` 在 `installKSCrash` 方法中调用了 `[[APMCrashInstallation sharedInstance] sendAllReportsWithCompletion: nil]`,内部实现如下 diff --git a/Chapter2 - Web FrontEnd/2.18.md b/Chapter2 - Web FrontEnd/2.18.md index 8fd50f2..9ef75fb 100644 --- a/Chapter2 - Web FrontEnd/2.18.md +++ b/Chapter2 - Web FrontEnd/2.18.md @@ -603,3 +603,8 @@ $ npm install $ node app.js ``` + +## 提问 +1. 反爬技术方案本身会不会对盲人等特殊群体的视障模式有影响? +https://medium.com/frochu/回歸初心-一探web-accessibility-baaa4d22f4a7 +alt diff --git a/Chapter3 - Server/3.10.md b/Chapter3 - Server/3.10.md new file mode 100644 index 0000000..4aea693 --- /dev/null +++ b/Chapter3 - Server/3.10.md @@ -0,0 +1,11 @@ +# 领域驱动设计与中后台、BFF的关系 + + +1. DDD 将业务拆分为多个领域,比如订单、商品...。每个域的服务是单独可以运行、维护的。比如订单域有10台机器,1台负载均衡,9台真正做事情的机器。有任务过来调度器进行任务派发。 +2. 客户端或者大前端都存在模块的概念。比如商品、订单,也是以 Pods 的形式去维护,每个领域的代码都单独可以运行、维护。模块之间不存在耦合关系,通过接口的形式去能力发现、能力调用。比如订单域通过某个接口访问某个商品详情的能力 +3. DDD 的最佳实践是不是微服务。比如订单服务所在的工程,可以单独运行、维护。 +4. 基于微服务,肯定需要一个 BFF 层,扮演业务编排、字段转换。比如订单域的模型有100个字段。但是订单的接口为客户端服务,客户端(通过接口找2018~2020年的、待付款的订单),BFF 层就去扮演数据组装、字段筛选的作用。 + + +- https://tech.meituan.com/2017/12/22/ddd-in-practice.html +- https://juejin.cn/post/6997250621627858957#heading-3 \ No newline at end of file diff --git a/Chapter3 - Server/chapter3.md b/Chapter3 - Server/chapter3.md index 34368a6..8e8457a 100644 --- a/Chapter3 - Server/chapter3.md +++ b/Chapter3 - Server/chapter3.md @@ -11,4 +11,5 @@ * [6、YAML](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.6.md) * [7、Node单元测试](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.7.md) * [8、数据安全(反爬虫)之「防重放」策略](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.8.md) -* [9、爬取疫情数据并用 Markdown 预览](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.9.md) \ No newline at end of file +* [9、爬取疫情数据并用 Markdown 预览](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.9.md) +* [10、领域驱动设计与中后台、BFF的关系](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.10.md) \ No newline at end of file diff --git a/Chapter7 - Geek Talk/7.22.md b/Chapter7 - Geek Talk/7.22.md new file mode 100644 index 0000000..f0b457b --- /dev/null +++ b/Chapter7 - Geek Talk/7.22.md @@ -0,0 +1,22 @@ +# 项目管理案例分析 + + + +## 库存扣减项目 + +**背景**:原定于17号上车,上车过程中代码合并 master 分支。iOS 和网关代码均无冲突。Android 发现订单列表接口被替换,和同学 A chechk 核实原因后是因为 App 订单管理能力补齐,替换了订单列表接口,而库存扣减项目测试过程中一直走的是老接口,发现问题后与测试沟通,对合并后的代码再进行一轮回归,延期至18号上车 + +**影响**:额外的近2天时间,导致其他项目进度滞后 + +**复盘总结:** + +因为过程中没有及时合并主分支代码,导致 QA 测试完成后,项目上车之际,合并 master 后发现很多主要逻辑以及接口被修改了。这时候不可能直接上车的,必须为新增的每一行代码回归,不然质量没法确保。 +这种情况,可与举个例子,比如你的 Native 工程或者前端工程的 Package.json 中版本没有锁死,在打包平台出的 SDKA 1.0.0 版本,测试完成后在出市场包或者 Web 部署 CDN 的时候,因为没锁死,恰好 SDKA 刚好有 1.0.1 可用,这样子造成的三方库引发的“新功能”或者某某不兼容,导致发生了线上问题。 + + +**改进点:** +- 开发过程中需要及时合并主分支,给 QA 的交付物保持最新 +- 后端接口改变,尽量做到向前兼容,避免影响线上服务 +- 后端接口做不到向前兼容,则新开接口,避免影响线上业务。接口改动尽量同步给相关使用方,正确评估影响面 + +这个问题本质上也就是多版本并行问题。属于很常见的项目问题,没有版本根本上解决,但是采取👆上面3个措施,相信情况会好很多。 \ No newline at end of file diff --git a/Chapter7 - Geek Talk/chapter7.md b/Chapter7 - Geek Talk/chapter7.md index 40712d7..4676b5c 100644 --- a/Chapter7 - Geek Talk/chapter7.md +++ b/Chapter7 - Geek Talk/chapter7.md @@ -21,4 +21,5 @@ * [17、一套开发规范](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.18.md) * [18、云服务器靠谱推荐](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.19.md) * [19、规范化团队 git 提交信息](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.20.md) - * [20、如何画架构图](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.21.md) \ No newline at end of file + * [20、如何画架构图](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.21.md) + * [21、项目管理案例分析](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.22.md) \ No newline at end of file diff --git a/Chapter9 - Ragdoll/Chapter9.md b/Chapter9 - Ragdoll/Chapter9.md index 52bea63..5b41e3b 100644 --- a/Chapter9 - Ragdoll/Chapter9.md +++ b/Chapter9 - Ragdoll/Chapter9.md @@ -1,7 +1,106 @@ # 第九部分 -第九部分主要记录布偶猫饮食、吃饭、健康、玩具、洗护、社会化等方面的经验和心得,还有一部分晒猫的原因。 +> 主要记录猫咪饮食、吃饭、健康、玩具、洗护、社会化等方面的经验和心得,还有一部分晒猫的原因。 + + +## 基础信息 + +坐标 :杭州 + +猫咪:养了4只吞金兽-布偶猫,每个猫咪都有 CFA 证书,有些猫咪小时候拿过比赛大奖,赛级布偶。 + +- Bella 是一只波斯系蓝双布偶,妹妹 +- Simba 是一只海双布偶,弟弟 +- PiPi 是一只海双布偶,弟弟 +- 碎星 是一只海双布偶,妹妹 + +环境:家里一周一次紫外臭氧灯消毒 + +洗护:克里斯汀森赛级洗护 + +饮食:生骨肉、羊奶 + + + + + +## 猫咪 + +
PiPi:
+ + + + + +
碎星:
+ + + + + +
Bella:
+ + + + + + + + + +
Simba:
+ + + + + +
小猫:
+ +(写入2021-0)4周前拍的 + + + + + + + + + + + + + +(写入2021-07-11)现在 + + + + + + + + + +更多: +其他更多的猫咪的美照,可以访问[这里](./assets) + + + + + +## 交流 + +如果你是一名铲屎官,想进群晒猫或者是交流猫咪养护经验 + +如果没有养猫,想云吸猫 + +如果打算养一只可爱、高颜值的布偶猫 + +可以联系我微信:704568245 + + + +## 目录 * [1、"CFA 证书" 不再那么神秘](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter9%20-%20Ragdoll/9.1.md) * [2、猫咪饮食](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter9%20-%20Ragdoll/9.2.md) diff --git a/SUMMARY.md b/SUMMARY.md index c4bcfaa..870d8e3 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -98,6 +98,7 @@ * [93、flutter 新功能引导](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.93.md) * [94、APM-Wake Up](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.94.md) * [95、从 flutter 和前端角度出发,聊聊单线程模型下如何保证 UI 流畅性](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.95.md) + * [96、一个提高 App 运算性能的想法](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.96.md) * [Chapter2 - Web FrontEnd](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter2%20-%20Web%20FrontEnd/chapter2.md) * [1、-last-child与-last-of-type你只是会用,有研究过区别吗?](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter2%20-%20Web%20FrontEnd/2.1.md) @@ -152,6 +153,7 @@ * [7、Node单元测试](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.7.md) * [8、数据安全(反爬虫)之「防重放」策略](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.8.md) * [9、爬取疫情数据并用 Markdown 预览](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.9.md) + * [10、领域驱动设计与中后台、BFF的关系](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter3%20-%20Server/3.10.md) @@ -190,6 +192,7 @@ * [18、云服务器靠谱推荐](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.19.md) * [19、规范化团队 git 提交信息](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.20.md) * [20、如何画架构图](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.21.md) + * [21、项目管理案例分析](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter7%20-%20Geek%20Talk/7.22.md) * [Chapter8 - Finance](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter8%20-%20Finance/chapter8.md) @@ -216,7 +219,3 @@ * [5、猫粮对你猫咪的牙齿做了什么?](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter9%20-%20Ragdoll/9.5.md) * [6、新猫到家的注意事项](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter9%20-%20Ragdoll/9.6.md) * [7、猫咪健康](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter9%20-%20Ragdoll/9.7.md) - - - - \ No newline at end of file diff --git a/assets/Hybrid-OfflinePackageDownload.png b/assets/Hybrid-OfflinePackageDownload.png new file mode 100644 index 0000000000000000000000000000000000000000..2c0b3f0e6ff8bef104f488ff3002bca9e180b029 GIT binary patch literal 14958 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 z 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