亢奋猫 发布的文章

我们在使用 function base component 的时候可以使用 useParams 来获取参数, 类似这样:

const { id } = useParams()

当我们使用 class base component 的时候该如何写好类型呢?

先说结论

import { RouteComponentProps } from 'react-router';

// example route
<Route path="/products/:name" component={ProductContainer} />

interface MatchParams {
    name: string;
}

interface Props extends RouteComponentProps<MatchParams> {
}

查看源代码

// from typings
export interface RouteComponentProps<P> {
  match: match<P>;
  location: H.Location;
  history: H.History;
  staticContext?: any;
}

export interface match<P> {
  params: P;
  isExact: boolean;
  path: string;
  url: string;
}

当我们升级 package.json 包后,容易出现下面的错误:

npm WARN [email protected] requires a peer of [email protected]>= 4.12.1 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @typescript-eslint/[email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of @typescript-eslint/[email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]>=6.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected] - 6.x but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^3 || ^4 || ^5 || ^6 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of [email protected]^1.8.18 but none is installed. You must install peer dependencies yourself.

audited 2211 packages in 7.724s

69 packages are looking for funding
  run `npm fund` for details

found 4992 low severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

问题分析

package-lock.json 中锁定的包版本和新的包依赖的版本有冲突,所以 npm 不知道如何处理这些冲突。

解决办法

rm package-lock.json && rm -rf node_modules/ && npm install

注意⚠️

任何版本升级都可能产生新的问题,建议充分测试后才能上线运行

版本信息

react native: 0.62.2
react-native-apk-manager: ^1.1.0

错误摘要

java.lang.RuntimeException: Package manager has died at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:156)

错误信息

java.lang.RuntimeException: Package manager has died
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:139)
    at com.superhao.react_native_apk_manager.ApkManagerModule.isAppInstalled(ApkManagerModule.java:210)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
    at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:151)
    at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
    at android.os.Looper.loop(Looper.java:148)
    at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
    at java.lang.Thread.run(Thread.java:818)
Caused by: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:2272)
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:134)
    ... 11 more
android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:2272)
    at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:134)
    at com.superhao.react_native_apk_manager.ApkManagerModule.isAppInstalled(ApkManagerModule.java:210)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
    at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:151)
    at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
    at android.os.Looper.loop(Looper.java:148)
    at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
    at java.lang.Thread.run(Thread.java:818)

设备分布

image

问题解决

re: https://github.com/1556173267/react-native-apk-manager/issues/6

  1. 需要避免同时多个线程调用 getPackageInfo,这样容易导致内存溢出 (主要解决方案)
  2. 避免获取过多 package 信息,如下所示
pm.getPackageInfo("com.tencent.mm", PackageManager.GET_ACTIVITIES);
// 修改为 👇
pm.getApplicationInfo("com.tencent.mm", PackageManager.GET_META_DATA);

参考文档

Android 获取 PackageInfo 引发 Crash 填坑
Package Manager Died
Android Package manager has died with TransactionTooLargeException
分析 Package manager has died

最近遇到了很多停更的 github 仓库,作者已明显放弃了维护。当我们需要修改软件包源代码的时候,就麻烦了。如果自己 fork 后发布重新发布新包,维护成本比较高。对于这种情况,更高效的办法是通过打 patch 的方式来修正软件包的代码。

下面介绍一下具体的实现办法:

为单个文件生成补丁

复制源文件,并修改复制后的文件内容,然后运行 diff 命令:

diff -up path/to/source.ext path/to/source.copy.ext > filename.patch

这条命令会产生类似如下的输出, 你将它重定向到一个文件中, 这个文件就是patch.

patch.png

参数详解:
-u 显示有差异行的前后几行(上下文), 默认是前后各3行, 这样, patch中带有更多的信息
-p 显示代码所在的c函数的信息

为多个文件生成补丁

diff -uprN path/to/source/ path/to/source_copy/ > patch

这条命令对比了 path/to/source/ 和 path/to/source_copy/ 两个目录下的所有源码差异.

参数详解:

-r 递归地对比一个目录和它的所有子目录(即整个目录树).
-N 如果某个文件缺少了, 就当作是空文件来对比。如果不使用本选项, 当diff发现旧代码或者新代码缺少文件时, 只简单的提示缺少文件。如果使用本选项, 会将新添加的文件全新打印出来作为新增的部分。

打补丁

我们将所有生成的 patch 文件放到 patches 目录后就可以使用脚本批量打补丁了。

#/bin/bash

# patch all file in patches dir
for i in $(find ./patches -name '*.patch');
do
  patch -N -p0 < $i > /dev/null 2>&1 &
done

通过 proxy_pass 代理的时候,如果文件比较大就会出现文件还没有传输完毕就被关闭的情况,只需要在 nginx 站点配置增加这个就可以解决了:

server {
    ...

    location / {
        ...
        proxy_buffers 8 1024k;  
        proxy_buffer_size 1024k;
    }
}

该绑定到哪个端口

这对于每一个编写服务器的程序员而言都是一个非常重要的考量。应该选择随机端口吗?该如何知道是否已经有其他的程序将某个端口宣为己有?

任何在 0~65535 之间的端口都可以使用,但是在选用之前别忘了一些重要的约定。

规则1: 不要使用 0~1024 之间的端口。

这些端口是作为熟知 (well-known)端口并保留给系统使用的。例如HTTP默认使用端口80, SMTP默认使用端口25,rsync默认使用端口873。绑定到这些端口通常需要root权限。

规则2: 不要使用 49000~65535 之间的端口。

这些都是临时 (ephemeral) 端口 。通常是由那些不需要运行在预定义端口,而只是需要一些端口作为临时之需的服务使用。它们也是后面所要讲到的连接协商 (connection negotiation) 过程的一部分。选择该范围内的端口可能会对一些用户造成麻烦。除此之外,1025~48999 之间端口的使用是一视同仁的。如果你打算选用其中的一个作为服务器端口,那你应该看一下 IANA 的注册列表,确保你的选择不会和其他流行的服务器冲突。

require 'socket'

# 该套接字将会绑定在环回接口,只侦听来自本地主机的客户端。
local_socket = Socket.new(:INET, :STREAM)
local_addr = Socket.pack_sockaddr_in(4481, '127.0.0.1')
local_socket.bind(local_addr)

# 该套接字将会绑定在所有已知的接口,侦听所有向其发送信息的客户端。
any_socket = Socket.new(:INET, :STREAM)
any_addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
any_socket.bind(any_addr)

# 该套接字试图绑定到一个未知的接口,结果导致Errno::EADDRNOTAVAIL。
error_socket = Socket.new(:INET, :STREAM)
error_addr = Socket.pack_sockaddr_in(4481, '1.2.3.4')
error_socket.bind(error_addr)

influence.jpg

影响力的武器

动物可能会因为看到某种颜色的羽毛而变得具有攻击性或听到某种叫声就对自己的天敌呵护有加。动物这种愚蠢可笑的机械反应在人类身上也有,当某一个触发特征出现时,我们会不假思索的做出相应的反应。之所以会这样,就是因为我们被难以观察到的影响力武器摆布了。

互惠

互惠原理认为,我们应该尽量以类似的方式报答他人为我们所做的一切。简单地说,就是对他人的某种行为,我们要以一种类似的行为去加以回报。如果人家施恩于你,你就应该以恩情报之,而不能不理不睬,更不能以怨报德。于是,我们身边这一最有效的影响力武器,就被某些人利用了。

承诺和一致

承诺和一致原理认为,一旦做出了一个选择或采取了某种立场,我们就会立刻碰到来自内心和外部的压力,迫使我们的言行与它保持一致。在这样的压力之下,我们会想方设法地以行动证明自己先前的决定是正确的。

社会认同

社会认同原理认为,在判断何为正确时,我们会根据别人的意见行事,尤其是当我们在特定情形下判断某一行为是否正确时。如果看到别人在某种场合做某件事,我们就会断定这样做是有道理的。

喜好

我们大多数人总是更容易答应自己认识和喜爱的人所提出的要求,对于这一点,恐怕不会有人感到吃惊。令人吃惊的是,有些我们完全不认识的人却想出了上百种方法利用这条简单的原理,让我们顺从他们的要求。

权威

权威所具有的强大力量会影响我们的行为,即使是具有独立思考能力的成年人,也会为了服从权威的命令做出一些完全丧失理智的事情来。

稀缺

“机会越少见,价值似乎就越高“的稀缺原理会对我们行为的方方面面造成影响,对失去某种东西的恐惧似乎比对获得同一物品的渴望,更能激发人们的行动力。

即时影响力

正常情况下,促使我们做出顺从决策的几个最常用的信息,都可以引导我们做出正确的决策,这就是为什么我们在决策时频繁、机械地使用互惠、承诺和一致、社会认同、喜好、权威以及稀缺原理的原因。每个原理本身都能够极为可靠地提示我们,什么时候说“是”比说“不”更加有利。但现实中,大量的、极易伪造的信息被人利用,他们借此引诱我们做出机械的反应并从中获利,我们不得不防。

众所周知中文字体文件比较大,通常做法是将文字转换成图片来显示。但是当文案略微变换就必须生成新的图片。这样做不仅麻烦而且还很难自定义文字大小,通常伴随着图片压缩容易出现字体模糊的问题。

如果有一种方案既可以引用字体,又能使字体体积压缩,那无疑是最好的。那这就是本文所讲的字体压缩方案:

pip install fonttools
pyftsubset HanziPenSC-W3.ttf --text='abc这些文字可以用新字体' --output-file=HanziPenSC-W3-2.ttf

WPF和WinForm技术有什么区别?哪个更加有前景?

https://www.zhihu.com/question/36859063

wpf的底层是DirectX,意味着你的显示效果不仅可以更炫更酷,同时显卡(集显独显均可)提供的加速也不会拖累你的运行速度。

v2-d51859134e096e2ffa8bafede3d914c3_r.png

winform的底层是GDI/GDI+,除非你明确使用DX的接口,不然永远都是CPU在画图,效果没那么炫,而且无法显卡加速。

v2-f00831a14f767a26eb89e39da4e3e3c6_r.png

wpf的界面设计和逻辑设计可以分离,界面设计师可以利用blend自主设计好看的界面,而不是最终让程序员来实现那个复杂的动画或者设计。winform设计师最多拖一拖,而这往往不够用。

wpf对于数据逻辑、业务逻辑、显示逻辑进行了解耦和,可以让不同部门协同工作更舒服一些,winform多少有一些搅在一起。

目前做windows桌面应用程序,MFC、QT、C#哪个更好?

首先说Web,我们明确一点,当下的桌面软件项目,必须具备完整的Web能力(包括开发/部署/运行/测试等),直观的说就是你的软件中必须包含浏览器。尤其是企业软件,发展到后期,除了核心功能之外,必然附带大量的增删改查模块,这部分不用Web你会极其难受。有些人可能native用的挺熟练的,觉得不就是表格表单报表么?我用native一样堆出来——相信我,你在浪费生命。

Web必然入选,但是注意,Web入选不意味着electron入选。事实上如果不是互联网公司的项目,我不建议使用electron。一方面,传统公司不需要迭代那么快,他们前端力量也有限,出了问题解决不了;另一方面,哪怕是互联网项目,发展到后期,也不约而同地开始约束前端随意调用nodejs API的行为。

建议使用libcef提供Web能力,同时native封装有限的API供Web调用。这里我不推荐使用框架原生的webview,比如QtWebEngine,以及winform自带的WebBrowser组件,这些工具比较冷门,资料少,出了问题不好排查,而且浏览器内核版本也未必符合要求。

结论:libcef入选,electron淘汰,原生webview淘汰。

接下来考察C#和Qt,这两个技术各有支持者,不是非黑即白的关系。比如我看韦大的答案下面很多人在争论工控领域应该用Qt还是C#,其实国内工控领域的老大浙大中控,这两个技术都在使用。

我个人比较推荐Qt,极其强大,跨平台,可以用C++单一语言(调试成本低),还有一些很贴心的功能,比如基于qss的换肤。不要觉得换肤不重要,实际上做项目卖软件的公司经常遇到这样的需求,要么是甲方想用专有皮肤,要么是你接到的项目是OEM项目,中间商要求换肤。

但如果使用Qt,我不推荐使用Quick(Qml),太非主流,而且对比Web没什么优势。建议能用Web的模块就用Web,需要深度开发的模块使用QWidget配合OpenGL深度开发。

结论:Qt入选,但是Quick淘汰。

C#能有一席之地,主要是因为传统。有些领域长期以来就是使用C#开发,人才比较集中(C#人才确实比C++好招,而且便宜,也更不易跳槽),开发效率也确实高。如果没有跨平台诉求,也不是前瞻性很强的项目,可以考虑沿用C#(关于前瞻性,多说一句,新冷战都要来了,你确定你的项目不需要跨平台嘛)。

用了C#,还要选择是用winform还是用WPF,按理说这不该是个问题——无脑WPF就完事儿了,毕竟开发效率高,对于高分屏等新问题微软也会有相应的支持。但是什么问题只要涉及到“传统”,就说不清楚了,只能说如果是新产品,不考虑技术资产继承的话,建议WPF。

结论:WPF入选,winform你看着办。

综上,如果是我来作架构师,通常情况下我会选择Qt+libcef。兼顾强大功能与开发效率,同时Qt和Web前端都是前景光明的主流技术,社区力量强大,技术风险小。如果考虑到特定行业的技术积累(不光是你自己的积累,还有供应商等等)和人才招聘,可以考虑WPF+libcef。

作者:欲三更
链接:https://www.zhihu.com/question/402080800/answer/1308065143
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. r2 是比较早期的替代品,算是 request next 早期比较通用的产品,core 大约 3.17kb
  2. node-fetch 是仿造 fetch API 写的 NodeJS HTTP 客户端,如果你对 fetch 比较熟悉考虑这个,有点是一直在更新,启动堆栈差不多 20k 。大家比较熟就不多说了。
  3. axios 是浏览器与 NodeJS 兼容的,比较重,因为兼容了浏览器的代码。这部分代码在运行时也会进入堆栈,尽管不会执行,因为不管什么 module 都不能 tree shaking 编程式的分发的代码块。API 有些土里土气,属于简单易懂的状态型编程风格。
  4. bent 也是浏览器与 NodeJS 兼容的,但比较小巧 (意味着功能没有那么多)。API 只有一个函数,但是目前没有基线测试不知道性能如何。
  5. got 专业的 NodeJS HTTP 客户端。非常非常非常大。亮点之一就是支持 pagination 与一些编程式的 hook,社区中有非常非常非常多的示例教你如何使用它,毕竟用的人多。开发者也是知名的开源狂魔 sindresorhus (他维护了 1000+ 的开源仓库),算是比较值得信赖吧。
  6. superagent ,一个有意思的 HTTP 客户端库吧,用的链式 API 。也是兼容浏览器和 NodeJS 。优势是支持 HTTP2,具体可以看这个 PR。早期是你们熟知的 TJ 一个人在写,现在已经是组织在维护。(体积也很大)

总结一下,如果你喜欢小巧一些可以考虑 node-fetchbent,需要功能比较强大就是 gotsuperagent
另外给你们强烈推荐一个适用于微服务的 http-client: zeit-fetch,支持 DNS 缓存、重试和 keep-http-agent,如果你正在写微服务,可以试一试。

最后说一句题外话,现在 NodeJS 的 API 非常的友好,如果你只是一个简单的 request(特别是 get ) 不用库也就几行而已。