diff --git a/.github/workflows/generate-catalog.yml b/.github/workflows/generate-catalog.yml new file mode 100644 index 00000000000..a460d924532 --- /dev/null +++ b/.github/workflows/generate-catalog.yml @@ -0,0 +1,68 @@ +name: 生成文章目录 +on: + push: + paths: + - 'integrals.md' + workflow_dispatch: + +jobs: + generate: + runs-on: ubuntu-latest + strategy: + fail-fast: false + max-parallel: 1 + matrix: + include: + - label: '前端' + target: 'front-end.md' + - label: '后端' + target: 'backend.md' + - label: 'AI' + target: 'AI.md' + - label: '设计' + target: 'design.md' + - label: 'Android' + target: 'android.md' + - label: '算法' + target: 'algorithm.md' + - label: 'iOS' + target: 'ios.md' + - label: '其他' + target: 'others.md' + - label: '产品' + target: 'product.md' + steps: + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - run: | + python -m pip install lxml requests markdown + - uses: actions/checkout@master + with: + repository: xitu/juejin-integral-database + path: ./juejin-integral-database + - uses: actions/checkout@master + with: + path: ./gold-miner + token: ${{ secrets.LSVIH_PAT }} + + - name: Generate Catalog + env: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + LABEL: ${{ matrix.label }} + TARGET: ${{ matrix.target }} + run: | + cd juejin-integral-database + echo -n "$TOKEN" > secret + python script_generate_catalog.py --label "$LABEL" --target "$TARGET" + mv new_$TARGET ../gold-miner/$TARGET + - name: Commit Catalog + uses: EndBug/add-and-commit@v7 + with: + message: '更新${{ matrix.label }}文章目录' + author_name: 'lsvih' + author_email: 'lsvih@qq.com' + add: '*.md' + cwd: './gold-miner/' + push: true diff --git a/AI.md b/AI.md index 7d5cbc01a00..dbf0444ba2a 100644 --- a/AI.md +++ b/AI.md @@ -1,106 +1,132 @@ -* [时间序列数据间量化同步的四种方法](https://juejin.im/post/5d213c126fb9a07f091bc3f5) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [在 Python 中过度使用列表解析器和生成表达式](https://juejin.im/post/5d281b0ff265da1b8b2b8ae0) ([ccJia](https://github.com/ccJia) 翻译) -* [使用 What-If 工具来研究机器学习模型](https://juejin.im/post/5d143abff265da1bb80c4005) ([Starriers](https://github.com/Starriers) 翻译) -* [如何在 Keras 中用 YOLOv3 进行对象检测](https://juejin.im/post/5d12eef5e51d455a68490ba8) ([Daltan](https://github.com/Daltan) 翻译) -* [在机器学习中为什么要进行 One-Hot 编码?](https://juejin.im/post/5d15840e5188255c23553204) ([lsvih](https://github.com/lsvih) 翻译) -* [在 Keras 下使用自编码器分类极端稀有事件](https://juejin.im/post/5cff17296fb9a07ec63b0a7f) ([ccJia](https://github.com/ccJia) 翻译) -* [使用谷歌 FACETS 可视化机器学习数据集](https://juejin.im/post/5d0226986fb9a07ecb0ba33a) ([QiaoN](https://github.com/QiaoN) 翻译) -* [浅析深度学习神经网络的卷积层](https://juejin.im/post/5ceeef01518825351e354747) ([QiaoN](https://github.com/QiaoN) 翻译) -* [时间序列分析、可视化、和使用 LSTM 预测](https://juejin.im/post/5cecdbb75188252db706f4e9) ([Minghao23](https://github.com/Minghao23) 翻译) -* [用 Word2vec 表示音乐?](https://juejin.im/post/5cdcdd9ee51d456e8240ddc3) ([Minghao23](https://github.com/Minghao23) 翻译) -* [使用 Python Flask 框架发布机器学习 API](https://juejin.im/post/5cd7f862e51d453aa44ad6f3) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [使用 WFST 进行语音识别](https://juejin.im/post/5cd7f7c56fb9a03218556ea4) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [Keras 速查表:使用 Python 构建神经网络](https://juejin.im/post/5cd40d24f265da038412a8be) ([Minghao23](https://github.com/Minghao23) 翻译) -* [在数据可视化中,我们曾经“画”下的那些错误](https://juejin.im/post/5cd39e1de51d453a3a0acb7b) ([ccJia](https://github.com/ccJia) 翻译) -* [机器学习可以建模简单的数学函数吗?](https://juejin.im/post/5ccd6d30e51d453ae03507da) ([Minghao23](https://github.com/Minghao23) 翻译) -* [Python 架构相关:我们需要更多吗?](https://juejin.im/post/5cd1db8c51882535b323a3c7) ([QiaoN](https://github.com/QiaoN) 翻译) -* [深度学习能力的三个等级](https://juejin.im/post/5cce97ec6fb9a031fe3bd85d) ([HearFishle](https://github.com/HearFishle) 翻译) -* [在深度学习训练过程中如何设置数据增强?](https://juejin.im/post/5cc87ec8f265da03b446202b) ([ccJia](https://github.com/ccJia) 翻译) -* [使用 PyTorch 在 MNIST 数据集上进行逻辑回归](https://juejin.im/post/5cc66d946fb9a032286173a7) ([lsvih](https://github.com/lsvih) 翻译) -* [归一化和标准化 — 量化分析](https://juejin.im/post/5cc5c0a06fb9a0321b69740a) ([ccJia](https://github.com/ccJia) 翻译) -* [如何在远程服务器上运行 Jupyter Notebooks](https://juejin.im/post/5cb5e0a9f265da036c577f24) ([Daltan](https://github.com/Daltan) 翻译) -* [哪一个深度学习框架增长最迅猛?TensorFlow 还是 PyTorch?](https://juejin.im/post/5caefef45188251b070f7d70) ([ccJia](https://github.com/ccJia) 翻译) -* [如何在 Keras 中使用 LSTM 神经网络创作音乐](https://juejin.im/post/5c9c19d7e51d453e7d28a173) ([HearFishle](https://github.com/HearFishle) 翻译) -* [Chars2vec: 基于字符实现的可用于处理现实世界中包含拼写错误和俚语的语言模型](https://juejin.im/post/5c96fd46e51d4513e072c3ae) ([kasheemlew](https://github.com/kasheemlew) 翻译) -* [基于 Python 的图理论和网络分析](https://juejin.im/post/5c9066b3f265da612e6d5770) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [时间顺序的价格异常检测](https://juejin.im/post/5c998f8ae51d454e523b6ed5) ([kasheemlew](https://github.com/kasheemlew) 翻译) -* [用长短期记忆网络预测股票市场(使用 Tensorflow)](https://juejin.im/post/5c8114de51882540a830b910) ([Qiuk17](https://github.com/Qiuk17) 翻译) -* [2019 跟上 AI 的脚步:AI 和 ML 接下来会发生什么重要的事?](https://juejin.im/post/5c83c8ba5188250aa57a0e2f) ([TUARAN](https://github.com/TUARAN) 翻译) -* [数据科学领域十大必知机器学习算法](https://juejin.im/post/5c73bbfff265da2da771d42a) ([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) -* [如何用 Python 从零开始构建你自己的神经网络](https://juejin.im/post/5c7a478c518825787e6a0f67) ([JackEggie](https://github.com/JackEggie) 翻译) -* [提取图像中的文字、人脸或者条形码 — 形状检测 API](https://juejin.im/post/5c64026fe51d457f963d249c) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [Python 的时间序列分析:简介](https://juejin.im/post/5c6c12def265da2ddc3c70ce) ([ppp-man](https://github.com/ppp-man) 翻译) -* [从 Instagram 上的故事和反馈机器学习中收获的一些经验](https://juejin.im/post/5c683dfce51d45164c7599fb) ([TrWestdoor](https://github.com/TrWestdoor) 翻译) -* [利用 Python中的 Bokeh 实现数据可视化,第一部分:入门](https://juejin.im/post/5c3c83c7f265da612d197bf0) ([Starriers](https://github.com/Starriers) 翻译) -* [利用 Python中的 Bokeh 实现数据可视化,第二部分:交互](https://juejin.im/post/5c34a9dee51d4551d044efce) ([Starriers](https://github.com/Starriers) 翻译) -* [利用 Python中的 Bokeh 实现数据可视化,第三部分:制作一个完整的仪表盘](https://juejin.im/post/5c3ae4656fb9a049d9757021) ([YueYongDev](https://github.com/YueYongDev) 翻译) -* [降维技术中常用的几种降维方法](https://juejin.im/post/5c4513a06fb9a049dc028d0c) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [如何使用 Dask Dataframes 在 Python 中运行并行数据分析](https://juejin.im/post/5c1feeaf5188257f9242b65c) ([Starriers](https://github.com/Starriers) 翻译) -* [时间序列异常检测算法](https://juejin.im/post/5c19f4cb518825678a7bad4c) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [支持向量机(SVM) 教程](http://5a77c24cf265da4e747f92e8/) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [通过集成学习提高机器学习效果](https://juejin.im/post/5c0909d951882548e93806e0) ([Starriers](https://github.com/Starriers) 翻译) -* [Google Colab 免费 GPU 使用教程](https://juejin.im/post/5c05e1bc518825689f1b4948) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [鲜为人知的数据科学 Python 库](https://juejin.im/post/5c075e09518825159512715f) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [强化学习中的好奇心与拖延症](https://juejin.im/post/5bff316651882548e937ef20) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [使用递归神经网络(LSTMs)对时序数据进行预测](https://juejin.im/post/5bf8a70cf265da61776ba1dc) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [深度学习将会给我们所有人的生活一个教训:工作是为了机器准备的](https://juejin.im/post/5bd71fd6f265da0aa94a5bce) ([yuwhuawang](https://github.com/yuwhuawang) 翻译) -* [初创公司的数据科学:简介](https://juejin.im/post/5bd55b76f265da0ae472ce1b) ([tmpbook](https://github.com/tmpbook) 翻译) -* [在 Keras 中使用一维卷积神经网络处理时间序列数据](https://juejin.im/post/5beb7432f265da61524cf27c) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [使用 Python 的 Pandas 和 Seaborn 框架从 Kaggle 数据集中提取信息](https://juejin.im/post/5be8caf651882551cc25acf5) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [使用 Pandas 对 Kaggle 数据集进行统计数据分析](https://juejin.im/post/5be8c994f265da61461db107) ([haiyang-tju](https://github.com/haiyang-tju) 翻译) -* [如何使用 Python 格式化时间型数据](https://juejin.im/post/5be26d15f265da61776b720a) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [使用 Pandas 在 Python 中创建一个简单的推荐系统](https://juejin.im/post/5be958416fb9a049af6cc969) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [基于评论的机器学习在线课程排名](https://juejin.im/post/5bc997fd6fb9a05cdb106d7a) ([davelet](https://github.com/davelet) 翻译) -* [语义分割 — U-Net(第一部分)](https://juejin.im/post/5bc55ec8f265da0a8f35ef20) ([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) -* [TensorFlow 中的 RNN 串流](https://juejin.im/post/5bcb2975f265da0a8d36c7d8) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [使用 TensorFlow.js 进行无服务的机器学习](https://juejin.im/post/5bc13de2e51d450e827b88fc) ([wzasd](https://github.com/wzasd) 翻译) -* [数据科学和机器学习面试问题](https://juejin.im/post/5bbb104f5188255c960c4d7e) ([jianboy](https://github.com/jianboy) 翻译) -* [用 Python 实现马尔可夫链的初学者教程](https://juejin.im/post/5bb031d06fb9a05cdb104888) ([cdpath](https://github.com/cdpath) 翻译) -* [Python 中的无监督学习算法](https://juejin.im/post/5bab10ed6fb9a05d1f2211b6) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [用 Scikit-Learn 实现 SVM 和 Kernel SVM](https://juejin.im/post/5b7fd39af265da43831fa136) ([rockyzhengwu](https://github.com/rockyzhengwu) 翻译) -* [Sklearn 中的朴素贝叶斯分类器](https://juejin.im/post/5b8510be51882542d23a1d66) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [使用 Python 进行自动化特征工程](https://juejin.im/post/5b6ea0e4e51d4519044adff0) ([mingxing47](https://github.com/mingxing47) 翻译) -* [Python 与大数据:Airflow & Jupyter Notebook with Hadoop 3, Spark & Presto](https://juejin.im/post/5b5a7fdfe51d453526175687) ([cf020031308](https://github.com/cf020031308) 翻译) -* [自然语言处理真是有趣](https://juejin.im/post/5b6d08e2f265da0f9c67cf0b) ([lihanxiang](https://github.com/lihanxiang) 翻译) -* [给人类的机器学习指南🤖👶](https://juejin.im/post/5b136f12f265da6e5415114b) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [深度学习中所需的线性代数知识](https://juejin.im/post/5b19d99ae51d4506d81a7a2f) ([maoqyhz](https://github.com/maoqyhz) 翻译) -* [可微可塑性:一种学会学习的新方法](https://juejin.im/post/5b055308f265da0ba063879d) ([luochen1992](https://github.com/luochen1992) 翻译) -* [给初学者的 Jupyter Notebook 教程](https://juejin.im/post/5af8d3776fb9a07ab7744dd0) ([SergeyChang](https://github.com/SergeyChang) 翻译) -* [如何在安卓应用中使用 TensorFlow Mobile](https://juejin.im/post/5afb8dc5518825426c690236) ([luochen1992](https://github.com/luochen1992) 翻译) -* [在浏览器里使用 TenserFlow.js 实时估计人体姿态](https://juejin.im/post/5afd833b5188254270642ff3) ([NoName4Me](https://github.com/NoName4Me) 翻译) -* [Google 的 ML Kit 为 Android 和 iOS 提供了简单的机器学习 API](https://juejin.im/post/5af2942e51882567244df836) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [利用 Keras 深度学习库进行词性标注教程](https://juejin.im/post/5ae4613a5188256727742d7d) ([luochen1992](https://github.com/luochen1992) 翻译) -* [Facebook 的 AI 万金油:StarSpace 神经网络模型简介](https://juejin.im/post/5a83af7c6fb9a0633c661404) ([noahziheng](https://github.com/noahziheng) 翻译) -* [Facebook 开源了物体检测研究项目 Detectron](https://juejin.im/post/5a6c2ba56fb9a01cb64f0591) ([SeanW20](https://github.com/SeanW20) 翻译) -* [使用深度学习自动生成HTML代码 - 第 1 部分](https://juejin.im/post/5a72744e6fb9a01cb64f1d66) ([sakila1012](https://github.com/sakila1012) 翻译) -* [IBM 工程师的 TensorFlow 入门指北](https://juejin.im/post/5a3d1ecb518825256362de6a) ([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) -* [如何使用 Golang 中的 Go-Routines 写出高性能的代码](https://juejin.im/post/5a17c0f9f265da431a42e060) ([tmpbook](https://github.com/tmpbook) 翻译) -* [RNN 循环神经网络系列 4: 注意力机制](https://juejin.im/post/59f72f61f265da432002871c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([TobiasLee](https://github.com/TobiasLee) 翻译) -* [Keras 中构建神经网络的 5 个步骤](https://juejin.im/post/59e43b5b6fb9a0452a3b5f4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [RNN 循环神经网络系列 3:编码、解码器](https://juejin.im/post/59fc1616f265da432b4a2d44?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [RNN 循环神经网络系列 5: 自定义单元](https://juejin.im/post/59fbd28b6fb9a045204b91f2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [Spotify 每周推荐功能:基于机器学习的音乐推荐](https://juejin.im/post/59fbd0d9518825299a468a8b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [RNN 循环神经网络系列 1:基本 RNN 与 CHAR-RNN](https://juejin.im/post/59f0c5b0f265da43085d3e94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [RNN 循环神经网络系列 2:文本分类](https://juejin.im/post/59f0c6b3f265da4319557de4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [什么是蒙特卡洛树搜索](https://juejin.im/post/59f16e8c5188250385371302?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([CACppuccino](https://github.com/CACppuccino) 翻译) -* [搭建个人深度学习平台](https://juejin.im/post/59be8e2b5188252c24746e9c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([RichardLeeH](https://github.com/RichardLeeH) 翻译) -* [Uber 机器学习平台 — 米开朗基罗](https://juejin.im/post/59c8b4d56fb9a00a4843b2a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [基于 TensorFlow 的上下文聊天机器人](https://juejin.im/entry/5992cd385188252433704fa3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardHua](https://github.com/edvardHua) 翻译) -* [使用 AI 为 Web 网页增加无障碍功能](https://juejin.im/post/59a51e91f265da2499603c8c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [在 Airbnb 使用机器学习预测房源的价值](https://juejin.im/post/59acfc336fb9a0249471e47d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [为什么我们渴求女性来设计 AI ](https://juejin.im/post/599c1e45518825242a02596e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([TobiasLee](https://github.com/TobiasLee) 翻译) -* [巧用 ARKit 和 SpriteKit 从零开始做 AR 游戏](https://juejin.im/post/599aaf746fb9a02477072380?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny1451](https://github.com/Danny1451) 翻译) -* [深度学习系列4: 为什么你需要使用嵌入层](https://juejin.im/post/599183c6f265da3e2e5717d2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lileizhenshuai](https://github.com/lileizhenshuai) 翻译) -* [机器之魂:聊天机器人是怎么工作的](https://juejin.im/post/599155d86fb9a03c467c151d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [深度学习系列3 - CNNs 以及应对过拟合的详细探讨](https://juejin.im/post/598f25b15188257d8643173d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lj147](https://github.com/lj147) 翻译) -* [深度学习系列2:卷积神经网络](https://juejin.im/post/598ac6a55188257dd366367f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [如何将时间序列问题用 Python 转换成为监督学习问题](https://juejin.im/post/598ac4e651882548605ce4a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [深度学习系列1:设置 AWS & 图像识别](https://juejin.im/post/5987f5885188256dcf65d01e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lileizhenshuai](https://github.com/lileizhenshuai) 翻译) -* [深度学习的未来](https://juejin.im/post/597843506fb9a06ba4747db5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [论深度学习的局限性](https://juejin.im/post/5978352a6fb9a06bad6574a4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([CACppuccino](https://github.com/CACppuccino) 翻译) -* [使用 Python+spaCy 进行简易自然语言处理](https://juejin.im/post/5971a4b9f265da6c42353332?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [从金属巨人到深度学习](https://juejin.im/post/596f4cecf265da6c2f0adb04?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XatMassacrE](https://github.com/XatMassacrE) 翻译) -* [在使用过采样或欠采样处理类别不均衡的数据后,如何正确的做交叉验证?](https://juejin.im/entry/5976dde9f265da6c2e0fc2f9/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardHua](https://github.com/edvardHua) 翻译) -* [如何处理机器学习中的不平衡类别](https://juejin.im/post/596f150551882549980c5f56?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([RichardLeeH](https://github.com/RichardLeeH) 翻译) -* [Scratch 平台的神经网络实现(R 语言)](https://juejin.im/post/5965cf75f265da6c4741adc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([CACppuccino](https://github.com/CACppuccino) 翻译) -* [你会给想学习机器学习的软件工程师提出什么建议?](https://juejin.im/post/596323416fb9a06bae1dff63?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) +* [使用 Android 11 进行机器学习:新功能](https://juejin.cn/post/6933208209259757581)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [数据科学中的 9 种距离度量](https://juejin.cn/post/6935265008045686815)([chzh9311](https://github.com/chzh9311) 翻译) +* [如何利用隐语义模型在图数据库中构建推荐系统](https://juejin.cn/post/6925019556108828685)([stuchilde](https://github.com/stuchilde) 翻译) +* [为什么我的数据会漂移?](https://juejin.cn/post/6923824334188314638)([chzh9311](https://github.com/chzh9311) 翻译) +* [DeepSpeed:所有人都能用的超大规模模型训练工具](https://juejin.cn/post/6916500899577724942)([zhuzilin](https://github.com/zhuzilin) 翻译) +* [寻找最优化 AutoML 库](https://juejin.cn/post/6906859687682965517)([zhusimaji](https://github.com/zhusimaji) 翻译) +* [在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)([regon-cao](https://github.com/regon-cao) 翻译) +* [重现:多样化 Mini-Batch 主动学习](https://juejin.cn/post/6890560237091340302)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [知识的极限](https://juejin.im/post/6874475968325484552)([QinRoc](https://github.com/QinRoc) 翻译) +* [让神经网络变得更小巧以方便部署](https://juejin.im/post/6873068232505458701)([PingHGao](https://github.com/PingHGao) 翻译) +* [使用合成数据改善机器学习中的极度不平衡数据集](https://juejin.im/post/6872609287802388488)([PingHGao](https://github.com/PingHGao) 翻译) +* [使用 Chrome 的 Shape Detection API 检测人脸,文本甚至条形码](https://juejin.im/post/6864391729693491207)([rocwong-cn](https://github.com/rocwong-cn) 翻译) +* [机器学习中的主动学习](https://juejin.im/post/5eaa71435188256d6c594746)([PingHGao](https://github.com/PingHGao) 翻译) +* [目标检测评价标准](https://juejin.im/post/5eaa67f55188256d9c259bd0)([PingHGao](https://github.com/PingHGao) 翻译) +* [一份数据科学 A/B 测试的简单指南](https://juejin.im/post/5e61b88cf265da57602c5b95)([Amberlin1970](https://github.com/Amberlin1970) 翻译) +* [图像修复:人类和 AI 的对决](https://juejin.im/post/5e43b2edf265da576543a0bb)([Starry316](https://github.com/Starry316) 翻译) +* [使用 Python 进行边缘检测](https://juejin.im/post/5e3d4b53e51d4526c26fadd4)([lsvih](https://github.com/lsvih) 翻译) +* [如何用 Keras 从头搭建一维生成对抗网络](https://juejin.im/post/5dcf5aba6fb9a0203161f376)([TokenJan](https://github.com/TokenJan) 翻译) +* [数学编程  ——  一个为推进数据科学发展而培养的关键习惯](https://zhuanlan.zhihu.com/p/100212596)([Weirdochr](https://github.com/Weirdochr) 翻译) +* [如何使用 Keras 训练目标检测模型](https://juejin.im/post/5d4bb1db6fb9a06add4e18b6)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [XGBoost 算法万岁!](https://juejin.im/post/5d484040e51d4561f95ee9de)([lsvih](https://github.com/lsvih) 翻译) +* [由浅入深理解主成分分析](https://juejin.im/post/5d41321df265da03c926d65a)([Ultrasteve](https://github.com/Ultrasteve) 翻译) +* [人工智能何以留存](https://juejin.im/post/5d4c1155e51d4562061159d1)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [什么时候需要进行数据的标准化? 为什么?](https://juejin.im/post/5d41a46bf265da03d727f85d)([Ultrasteve](https://github.com/Ultrasteve) 翻译) +* [数据科学家需要掌握的十种统计技术](https://juejin.im/post/5d42340d6fb9a06ae61a95f5)([HearFishle](https://github.com/HearFishle) 翻译) +* [从著名数据数据可视化中我们可以学到什么](https://juejin.im/user/567e246a34f81a1d879e7a14)([aceleewinnie](https://github.com/AceLeeWinnie) 翻译) +* [时间序列数据间量化同步的四种方法](https://juejin.im/post/5d213c126fb9a07f091bc3f5)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [在 Python 中过度使用列表解析器和生成表达式](https://juejin.im/post/5d281b0ff265da1b8b2b8ae0)([ccJia](https://github.com/ccJia) 翻译) +* [使用 What-If 工具来研究机器学习模型](https://juejin.im/post/5d143abff265da1bb80c4005)([Starriers](https://github.com/Starriers) 翻译) +* [如何在 Keras 中用 YOLOv3 进行对象检测](https://juejin.im/post/5d12eef5e51d455a68490ba8)([Daltan](https://github.com/Daltan) 翻译) +* [在机器学习中为什么要进行 One-Hot 编码?](https://juejin.im/post/5d15840e5188255c23553204)([lsvih](https://github.com/lsvih) 翻译) +* [在 Keras 下使用自编码器分类极端稀有事件](https://juejin.im/post/5cff17296fb9a07ec63b0a7f)([ccJia](https://github.com/ccJia) 翻译) +* [使用谷歌 FACETS 可视化机器学习数据集](https://juejin.im/post/5d0226986fb9a07ecb0ba33a)([QiaoN](https://github.com/QiaoN) 翻译) +* [浅析深度学习神经网络的卷积层](https://juejin.im/post/5ceeef01518825351e354747)([QiaoN](https://github.com/QiaoN) 翻译) +* [时间序列分析、可视化、和使用 LSTM 预测](https://juejin.im/post/5cecdbb75188252db706f4e9)([Minghao23](https://github.com/Minghao23) 翻译) +* [用 Word2vec 表示音乐?](https://juejin.im/post/5cdcdd9ee51d456e8240ddc3)([Minghao23](https://github.com/Minghao23) 翻译) +* [使用 Python Flask 框架发布机器学习 API](https://juejin.im/post/5cd7f862e51d453aa44ad6f3)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [使用 WFST 进行语音识别](https://juejin.im/post/5cd7f7c56fb9a03218556ea4)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [Keras 速查表:使用 Python 构建神经网络](https://juejin.im/post/5cd40d24f265da038412a8be)([Minghao23](https://github.com/Minghao23) 翻译) +* [在数据可视化中,我们曾经“画”下的那些错误](https://juejin.im/post/5cd39e1de51d453a3a0acb7b)([ccJia](https://github.com/ccJia) 翻译) +* [机器学习可以建模简单的数学函数吗?](https://juejin.im/post/5ccd6d30e51d453ae03507da)([Minghao23](https://github.com/Minghao23) 翻译) +* [Python 架构相关:我们需要更多吗?](https://juejin.im/post/5cd1db8c51882535b323a3c7)([QiaoN](https://github.com/QiaoN) 翻译) +* [深度学习能力的三个等级](https://juejin.im/post/5cce97ec6fb9a031fe3bd85d)([HearFishle](https://github.com/HearFishle) 翻译) +* [在深度学习训练过程中如何设置数据增强?](https://juejin.im/post/5cc87ec8f265da03b446202b)([ccJia](https://github.com/ccJia) 翻译) +* [使用 PyTorch 在 MNIST 数据集上进行逻辑回归](https://juejin.im/post/5cc66d946fb9a032286173a7)([lsvih](https://github.com/lsvih) 翻译) +* [归一化和标准化 — 量化分析](https://juejin.im/post/5cc5c0a06fb9a0321b69740a)([ccJia](https://github.com/ccJia) 翻译) +* [如何在远程服务器上运行 Jupyter Notebooks](https://juejin.im/post/5cb5e0a9f265da036c577f24)([Daltan](https://github.com/Daltan) 翻译) +* [哪一个深度学习框架增长最迅猛?TensorFlow 还是 PyTorch?](https://juejin.im/post/5caefef45188251b070f7d70)([ccJia](https://github.com/ccJia) 翻译) +* [如何在 Keras 中使用 LSTM 神经网络创作音乐](https://juejin.im/post/5c9c19d7e51d453e7d28a173)([HearFishle](https://github.com/HearFishle) 翻译) +* [Chars2vec: 基于字符实现的可用于处理现实世界中包含拼写错误和俚语的语言模型](https://juejin.im/post/5c96fd46e51d4513e072c3ae)([kasheemlew](https://github.com/kasheemlew) 翻译) +* [基于 Python 的图理论和网络分析](https://juejin.im/post/5c9066b3f265da612e6d5770)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [时间顺序的价格异常检测](https://juejin.im/post/5c998f8ae51d454e523b6ed5)([kasheemlew](https://github.com/kasheemlew) 翻译) +* [用长短期记忆网络预测股票市场(使用 Tensorflow)](https://juejin.im/post/5c8114de51882540a830b910)([Qiuk17](https://github.com/Qiuk17) 翻译) +* [2019 跟上 AI 的脚步:AI 和 ML 接下来会发生什么重要的事?](https://juejin.im/post/5c83c8ba5188250aa57a0e2f)([TUARAN](https://github.com/TUARAN) 翻译) +* [数据科学领域十大必知机器学习算法](https://juejin.im/post/5c73bbfff265da2da771d42a)([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) +* [如何用 Python 从零开始构建你自己的神经网络](https://juejin.im/post/5c7a478c518825787e6a0f67)([JackEggie](https://github.com/JackEggie) 翻译) +* [提取图像中的文字、人脸或者条形码 — 形状检测 API](https://juejin.im/post/5c64026fe51d457f963d249c)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [Python 的时间序列分析:简介](https://juejin.im/post/5c6c12def265da2ddc3c70ce)([ppp-man](https://github.com/ppp-man) 翻译) +* [从 Instagram 上的故事和反馈机器学习中收获的一些经验](https://juejin.im/post/5c683dfce51d45164c7599fb)([TrWestdoor](https://github.com/TrWestdoor) 翻译) +* [利用 Python中的 Bokeh 实现数据可视化,第一部分:入门](https://juejin.im/post/5c3c83c7f265da612d197bf0)([Starriers](https://github.com/Starriers) 翻译) +* [利用 Python中的 Bokeh 实现数据可视化,第二部分:交互](https://juejin.im/post/5c34a9dee51d4551d044efce)([Starriers](https://github.com/Starriers) 翻译) +* [利用 Python中的 Bokeh 实现数据可视化,第三部分:制作一个完整的仪表盘](https://juejin.im/post/5c3ae4656fb9a049d9757021)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [降维技术中常用的几种降维方法](https://juejin.im/post/5c4513a06fb9a049dc028d0c)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [如何使用 Dask Dataframes 在 Python 中运行并行数据分析](https://juejin.im/post/5c1feeaf5188257f9242b65c)([Starriers](https://github.com/Starriers) 翻译) +* [时间序列异常检测算法](https://juejin.im/post/5c19f4cb518825678a7bad4c)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [支持向量机(SVM) 教程](http://5a77c24cf265da4e747f92e8/)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [通过集成学习提高机器学习效果](https://juejin.im/post/5c0909d951882548e93806e0)([Starriers](https://github.com/Starriers) 翻译) +* [Google Colab 免费 GPU 使用教程](https://juejin.im/post/5c05e1bc518825689f1b4948)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [鲜为人知的数据科学 Python 库](https://juejin.im/post/5c075e09518825159512715f)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [强化学习中的好奇心与拖延症](https://juejin.im/post/5bff316651882548e937ef20)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [使用递归神经网络(LSTMs)对时序数据进行预测](https://juejin.im/post/5bf8a70cf265da61776ba1dc)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [深度学习将会给我们所有人的生活一个教训:工作是为了机器准备的](https://juejin.im/post/5bd71fd6f265da0aa94a5bce)([yuwhuawang](https://github.com/yuwhuawang) 翻译) +* [初创公司的数据科学:简介](https://juejin.im/post/5bd55b76f265da0ae472ce1b)([tmpbook](https://github.com/tmpbook) 翻译) +* [在 Keras 中使用一维卷积神经网络处理时间序列数据](https://juejin.im/post/5beb7432f265da61524cf27c)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [使用 Python 的 Pandas 和 Seaborn 框架从 Kaggle 数据集中提取信息](https://juejin.im/post/5be8caf651882551cc25acf5)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [使用 Pandas 对 Kaggle 数据集进行统计数据分析](https://juejin.im/post/5be8c994f265da61461db107)([haiyang-tju](https://github.com/haiyang-tju) 翻译) +* [如何使用 Python 格式化时间型数据](https://juejin.im/post/5be26d15f265da61776b720a)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [使用 Pandas 在 Python 中创建一个简单的推荐系统](https://juejin.im/post/5be958416fb9a049af6cc969)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [基于评论的机器学习在线课程排名](https://juejin.im/post/5bc997fd6fb9a05cdb106d7a)([davelet](https://github.com/davelet) 翻译) +* [语义分割 — U-Net(第一部分)](https://juejin.im/post/5bc55ec8f265da0a8f35ef20)([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) +* [TensorFlow 中的 RNN 串流](https://juejin.im/post/5bcb2975f265da0a8d36c7d8)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [使用 TensorFlow.js 进行无服务的机器学习](https://juejin.im/post/5bc13de2e51d450e827b88fc)([wzasd](https://github.com/wzasd) 翻译) +* [数据科学和机器学习面试问题](https://juejin.im/post/5bbb104f5188255c960c4d7e)([jianboy](https://github.com/jianboy) 翻译) +* [用 Python 实现马尔可夫链的初学者教程](https://juejin.im/post/5bb031d06fb9a05cdb104888)([cdpath](https://github.com/cdpath) 翻译) +* [Python 中的无监督学习算法](https://juejin.im/post/5bab10ed6fb9a05d1f2211b6)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [用 Scikit-Learn 实现 SVM 和 Kernel SVM](https://juejin.im/post/5b7fd39af265da43831fa136)([rockyzhengwu](https://github.com/rockyzhengwu) 翻译) +* [Sklearn 中的朴素贝叶斯分类器](https://juejin.im/post/5b8510be51882542d23a1d66)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [使用 Python 进行自动化特征工程](https://juejin.im/post/5b6ea0e4e51d4519044adff0)([mingxing47](https://github.com/mingxing47) 翻译) +* [Python 与大数据:Airflow & Jupyter Notebook with Hadoop 3, Spark & Presto](https://juejin.im/post/5b5a7fdfe51d453526175687)([cf020031308](https://github.com/cf020031308) 翻译) +* [自然语言处理真是有趣](https://juejin.im/post/5b6d08e2f265da0f9c67cf0b)([lihanxiang](https://github.com/lihanxiang) 翻译) +* [给人类的机器学习指南🤖👶](https://juejin.im/post/5b136f12f265da6e5415114b)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [深度学习中所需的线性代数知识](https://juejin.im/post/5b19d99ae51d4506d81a7a2f)([maoqyhz](https://github.com/maoqyhz) 翻译) +* [可微可塑性:一种学会学习的新方法](https://juejin.im/post/5b055308f265da0ba063879d)([luochen1992](https://github.com/luochen1992) 翻译) +* [给初学者的 Jupyter Notebook 教程](https://juejin.im/post/5af8d3776fb9a07ab7744dd0)([SergeyChang](https://github.com/SergeyChang) 翻译) +* [如何在安卓应用中使用 TensorFlow Mobile](https://juejin.im/post/5afb8dc5518825426c690236)([luochen1992](https://github.com/luochen1992) 翻译) +* [在浏览器里使用 TenserFlow.js 实时估计人体姿态](https://juejin.im/post/5afd833b5188254270642ff3)([NoName4Me](https://github.com/NoName4Me) 翻译) +* [Google 的 ML Kit 为 Android 和 iOS 提供了简单的机器学习 API](https://juejin.im/post/5af2942e51882567244df836)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [利用 Keras 深度学习库进行词性标注教程](https://juejin.im/post/5ae4613a5188256727742d7d)([luochen1992](https://github.com/luochen1992) 翻译) +* [Facebook 的 AI 万金油:StarSpace 神经网络模型简介](https://juejin.im/post/5a83af7c6fb9a0633c661404)([noahziheng](https://github.com/noahziheng) 翻译) +* [Facebook 开源了物体检测研究项目 Detectron](https://juejin.im/post/5a6c2ba56fb9a01cb64f0591)([SeanW20](https://github.com/SeanW20) 翻译) +* [使用深度学习自动生成HTML代码 - 第 1 部分](https://juejin.im/post/5a72744e6fb9a01cb64f1d66)([sakila1012](https://github.com/sakila1012) 翻译) +* [IBM 工程师的 TensorFlow 入门指北](https://juejin.im/post/5a3d1ecb518825256362de6a)([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) +* [如何使用 Golang 中的 Go-Routines 写出高性能的代码](https://juejin.im/post/5a17c0f9f265da431a42e060)([tmpbook](https://github.com/tmpbook) 翻译) +* [RNN 循环神经网络系列 4: 注意力机制](https://juejin.im/post/59f72f61f265da432002871c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([TobiasLee](https://github.com/TobiasLee) 翻译) +* [Keras 中构建神经网络的 5 个步骤](https://juejin.im/post/59e43b5b6fb9a0452a3b5f4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [RNN 循环神经网络系列 3:编码、解码器](https://juejin.im/post/59fc1616f265da432b4a2d44?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [RNN 循环神经网络系列 5: 自定义单元](https://juejin.im/post/59fbd28b6fb9a045204b91f2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [Spotify 每周推荐功能:基于机器学习的音乐推荐](https://juejin.im/post/59fbd0d9518825299a468a8b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [RNN 循环神经网络系列 1:基本 RNN 与 CHAR-RNN](https://juejin.im/post/59f0c5b0f265da43085d3e94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [RNN 循环神经网络系列 2:文本分类](https://juejin.im/post/59f0c6b3f265da4319557de4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [什么是蒙特卡洛树搜索](https://juejin.im/post/59f16e8c5188250385371302?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([CACppuccino](https://github.com/CACppuccino) 翻译) +* [搭建个人深度学习平台](https://juejin.im/post/59be8e2b5188252c24746e9c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([RichardLeeH](https://github.com/RichardLeeH) 翻译) +* [Uber 机器学习平台 — 米开朗基罗](https://juejin.im/post/59c8b4d56fb9a00a4843b2a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [基于 TensorFlow 的上下文聊天机器人](https://juejin.im/entry/5992cd385188252433704fa3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardHua](https://github.com/edvardHua) 翻译) +* [使用 AI 为 Web 网页增加无障碍功能](https://juejin.im/post/59a51e91f265da2499603c8c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [在 Airbnb 使用机器学习预测房源的价值](https://juejin.im/post/59acfc336fb9a0249471e47d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [为什么我们渴求女性来设计 AI ](https://juejin.im/post/599c1e45518825242a02596e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([TobiasLee](https://github.com/TobiasLee) 翻译) +* [巧用 ARKit 和 SpriteKit 从零开始做 AR 游戏](https://juejin.im/post/599aaf746fb9a02477072380?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny1451](https://github.com/Danny1451) 翻译) +* [深度学习系列4: 为什么你需要使用嵌入层](https://juejin.im/post/599183c6f265da3e2e5717d2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lileizhenshuai](https://github.com/lileizhenshuai) 翻译) +* [机器之魂:聊天机器人是怎么工作的](https://juejin.im/post/599155d86fb9a03c467c151d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [深度学习系列3 - CNNs 以及应对过拟合的详细探讨](https://juejin.im/post/598f25b15188257d8643173d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lj147](https://github.com/lj147) 翻译) +* [深度学习系列2:卷积神经网络](https://juejin.im/post/598ac6a55188257dd366367f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [如何将时间序列问题用 Python 转换成为监督学习问题](https://juejin.im/post/598ac4e651882548605ce4a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [深度学习系列1:设置 AWS & 图像识别](https://juejin.im/post/5987f5885188256dcf65d01e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lileizhenshuai](https://github.com/lileizhenshuai) 翻译) +* [深度学习的未来](https://juejin.im/post/597843506fb9a06ba4747db5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [论深度学习的局限性](https://juejin.im/post/5978352a6fb9a06bad6574a4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([CACppuccino](https://github.com/CACppuccino) 翻译) +* [使用 Python+spaCy 进行简易自然语言处理](https://juejin.im/post/5971a4b9f265da6c42353332?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [从金属巨人到深度学习](https://juejin.im/post/596f4cecf265da6c2f0adb04?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XatMassacrE](https://github.com/XatMassacrE) 翻译) +* [在使用过采样或欠采样处理类别不均衡的数据后,如何正确的做交叉验证?](https://juejin.im/entry/5976dde9f265da6c2e0fc2f9/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardHua](https://github.com/edvardHua) 翻译) +* [如何处理机器学习中的不平衡类别](https://juejin.im/post/596f150551882549980c5f56?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([RichardLeeH](https://github.com/RichardLeeH) 翻译) +* [Scratch 平台的神经网络实现(R 语言)](https://juejin.im/post/5965cf75f265da6c4741adc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([CACppuccino](https://github.com/CACppuccino) 翻译) +* [你会给想学习机器学习的软件工程师提出什么建议?](https://juejin.im/post/596323416fb9a06bae1dff63?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) diff --git a/README.md b/README.md index eedff2376cd..e6a6723d823 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![](https://img.shields.io/badge/weibo-%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92-brightgreen.svg)](http://weibo.com/juejinfanyi) [![](https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F-%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92-blue.svg)](https://zhuanlan.zhihu.com/juejinfanyi) -[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖[区块链](#区块链)、[人工智能](#ai--deep-learning--machine-learning)、[Android](#android)、[iOS](#ios)、[前端](#前端)、[后端](#后端)、[设计](#设计)、[产品](#产品)和[其他](#其他) 等领域,以及各大型优质 [官方文档及手册](#官方文档及手册),读者为热爱新技术的新锐开发者。 +[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖[区块链](#区块链)、[人工智能](#ai--deep-learning--machine-learning)、[Android](#android)、[iOS](#ios)、[前端](#前端)、[后端](#后端)、[设计](#设计)、[产品](#产品)、[算法](https://github.com/xitu/gold-miner/blob/master/algorithm.md)和[其他](#其他)等领域,以及各大型优质 [官方文档及手册](#官方文档及手册),读者为热爱新技术的新锐开发者。 -掘金翻译计划目前翻译完成 [1726](#近期文章列表) 篇文章,官方文档及手册 [13](#官方文档及手册) 个,共有 [1000](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译和校对。 +掘金翻译计划目前翻译完成 [2027](#近期文章列表) 余篇文章,官方文档及手册 [13](#官方文档及手册) 个,共有 [1000](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译和校对。 > ## [🥇掘金翻译计划 — 区块链分舵](https://github.com/xitu/blockchain-miner) @@ -32,6 +32,7 @@ https://github.com/xitu/gold-miner/issues/new?title=推荐优秀英文文章&bod ## 官方文档及手册 +* [年度总结系列](https://github.com/xitu/Annual-Survey) * [TensorFlow 中文文档](https://github.com/xitu/tensorflow-docs) * [The JavaScript Tutorial](https://github.com/xitu/javascript-tutorial-zh) * [ML Kit 中文文档](https://github.com/Quorafind/MLkit-CN) diff --git a/TODO/11-top-designers-give-11-pieces-of-realistic-ux-advice.md b/TODO/11-top-designers-give-11-pieces-of-realistic-ux-advice.md index 8e90386b67d..17ce526bcfb 100644 --- a/TODO/11-top-designers-give-11-pieces-of-realistic-ux-advice.md +++ b/TODO/11-top-designers-give-11-pieces-of-realistic-ux-advice.md @@ -2,7 +2,7 @@ * 原文作者 : [Roger Huang] * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [Adam Shen](https://github.com/shenxn) -* 校对者: [iThreeKing](https://github.com/iThreeKing),[circlelove](https://github.com/circlelove) +* 校对者: [joyking7](https://github.com/joyking7),[circlelove](https://github.com/circlelove) # 11个顶级设计师分享他们的职业建议 diff --git a/TODO/Introducing-Swift 3.0.md b/TODO/Introducing-Swift 3.0.md index 5d7d232b2b0..4fafd28ff89 100644 --- a/TODO/Introducing-Swift 3.0.md +++ b/TODO/Introducing-Swift 3.0.md @@ -1,7 +1,7 @@ > * 原文链接: [Introducing Swift 3.0](http://dev.iachieved.it/iachievedit/) * 原文作者 : [ Joe](http://dev.iachieved.it/iachievedit/author/admin/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) -* 译者 : [iThreeKing](https://github.com/iThreeKing) +* 译者 : [joyking7](https://github.com/joyking7) * 校对者 : [CoderBOBO](https://github.com/CoderBOBO) [shenxn](https://github.com/shenxn) Linux 系统下 Swift 3.0 的介绍 diff --git a/TODO/OAuth2 Authentication with Lua.md b/TODO/OAuth2 Authentication with Lua.md index 20be74f93b3..30051cb2488 100644 --- a/TODO/OAuth2 Authentication with Lua.md +++ b/TODO/OAuth2 Authentication with Lua.md @@ -2,7 +2,7 @@ * 原文作者 : [Israel Sotomayor](https://github.com/zot24) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [BOBO](https://github.com/CoderBOBO) -* 校对者: [Adam Shen](https://github.com/shenxn) [iThreeKing](https://github.com/iThreeKing) +* 校对者: [Adam Shen](https://github.com/shenxn) [joyking7](https://github.com/joyking7) # 使用 Lua 完成 OAuth2 的身份验证 diff --git a/TODO/OptimizationTips.rst b/TODO/OptimizationTips.rst index 43ca04e5b54..59033b61582 100644 --- a/TODO/OptimizationTips.rst +++ b/TODO/OptimizationTips.rst @@ -1,7 +1,7 @@ - 原文链接: `Optimization Tips `_ - 原文作者 : `apple `_ - 译文出自 : `掘金翻译计划 `_ - - 译者 : `iThreeKing `_ + - 译者 : `joyking7 `_ - 校对者: `nathanwhy `_、`walkingway `_ - 状态 : 完成 diff --git a/TODO/designing-the-icons-for-flinto-s-ui.md b/TODO/designing-the-icons-for-flinto-s-ui.md index 2a2a8495b91..5b3f03ef957 100644 --- a/TODO/designing-the-icons-for-flinto-s-ui.md +++ b/TODO/designing-the-icons-for-flinto-s-ui.md @@ -36,7 +36,7 @@ ![](http://ww3.sinaimg.cn/large/a490147fjw1f2m0k0slikj20m807xjsz.jpg) -
对于使用retina显示屏的读者,我们显示**“一半尺寸”**的位图,如图1x的全像素图标。对于非retina显示屏的读者,则使用**“双倍尺寸”**的位图,如图2x的全像素图标。 请以横向模式显示上图来获得最好的显示效果。
+
对于使用retina显示屏的读者,我们显示**“一半尺寸”**的位图,如图 1x 的全像素图标。对于非retina显示屏的读者,则使用**“双倍尺寸”**的位图,如图 2x 的全像素图标。 请以横向模式显示上图来获得最好的显示效果。
在一个理想的世界中,一枚制作精良矢量图标可以轻易地适应各种像素密度的输出,并在所有对应尺寸中显示效果良好。但是大部分时候,使用一倍大小的图标并不能够处理得到更高尺寸的图标。你可能需要先做一个完美的两倍尺寸的图标,然后再调整成一倍尺寸来创建一个新的视觉满意的图标。在Flinto中至少一半的图标都有其对应1倍和2倍尺寸,譬如贯穿整个过渡动画设计面板的"概念图层"图标。 diff --git a/TODO/effective-okhttp.md b/TODO/effective-okhttp.md index 3f210223338..5fbf9c7dba6 100644 --- a/TODO/effective-okhttp.md +++ b/TODO/effective-okhttp.md @@ -2,7 +2,7 @@ * 原文作者 : [Michael Parker](http://omgitsmgp.com/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [Brucezz](https://github.com/brucezz) -* 校对者: [iThreeKing](https://github.com/iThreeKing), [Adam Shen](https://github.com/shenxn), [Jaeger](https://github.com/laobie) +* 校对者: [joyking7](https://github.com/joyking7), [Adam Shen](https://github.com/shenxn), [Jaeger](https://github.com/laobie) # 如何更高效地使用 okhttp diff --git a/TODO/freemium-conversion-rate/freemium-conversion-rate.md b/TODO/freemium-conversion-rate/freemium-conversion-rate.md index 7a50d609f67..74bc42a3a61 100644 --- a/TODO/freemium-conversion-rate/freemium-conversion-rate.md +++ b/TODO/freemium-conversion-rate/freemium-conversion-rate.md @@ -2,7 +2,7 @@ * 原文作者 : [Benjamin Brandall](https://www.process.st/author/ben/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [SatanWoo](https://github.com/satanwoo) -* 校对者: [iThreeKing](https://github.com/iThreeKing), [DeadLion](https://github.com/DeadLion) +* 校对者: [joyking7](https://github.com/joyking7), [DeadLion](https://github.com/DeadLion) # 为什么 Spotify 的付费转化率比 Dropbox 高了 667% diff --git a/TODO/guide-to-interviewing-for-product-design-internships.md b/TODO/guide-to-interviewing-for-product-design-internships.md index 41ff5f2a385..0930a93a9c8 100644 --- a/TODO/guide-to-interviewing-for-product-design-internships.md +++ b/TODO/guide-to-interviewing-for-product-design-internships.md @@ -1,7 +1,7 @@ >* 原文链接 : [A Guide to Interviewing for Product Design Internships](https://medium.com/facebook-design/a-guide-to-interviewing-for-product-design-internships-d719dd4c146c#.jhgjr12c) * 原文作者 : [Andrew Hwang](https://medium.com/@ahwng) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) -* 译者 : [iThreeKing](https://github.com/iThreeKing) +* 译者 : [joyking7](https://github.com/joyking7) * 校对者: [邵辉Vista](https://github.com/shaohui10086), [circlelove](https://github.com/circlelove) # 产品设计实习生面试指南 diff --git a/TODO/how-apple.md b/TODO/how-apple.md index 4270a83ec95..1e82cdbc4de 100644 --- a/TODO/how-apple.md +++ b/TODO/how-apple.md @@ -116,7 +116,7 @@ Tognazzini是我们当中的一人,在创业初期曾在苹果和 Steve Jobs ![](http://f.fastcompany.net/multisite_files/fastcompany/imagecache/inline-xlarge/inline/2015/11/3053406-inline-figure-1.jpg) -
[图 1\. 苹果用户界面指南随时间的变化.迈克尔·迈耶 +
[图 1\. 苹果用户界面指南随时间的变化.迈克尔·迈耶
该图表示了人机界面规范从1995到2015的发展。由于手势设备使用iOS操作系统,它的开发指南放到了2015开发指南的左侧,是更传统的操作系统(OS X)。 @@ -135,7 +135,7 @@ iOS中大部分或者全部丢失的重要原则是:可发现性,反馈, ### 可发现性 -可发现性,即看一眼系统立马发现所有可能操作的能力,一直是苹果设计成功的一个关键组成部分。在早期这个原则叫做“see and point”(在图1),因为所有可能的操作都由用户看得见的对象替代了,例如按钮,图标或菜单列表项:找到你想要的操作,把鼠标光标放上去,然后点击执行。简单地说,发现性意味着使操作视觉上可发现,这样就不用把这些操作记下来。传统电脑桌面的菜单很好地体现了这个目的,标记的图标同样是的。未标记的图标经常失败,但最糟糕的罪魁祸首是完全没有任何线索。请注意苹果的指导手册里再也没有可发现性了。 +可发现性,即看一眼系统立马发现所有可能操作的能力,一直是苹果设计成功的一个关键组成部分。在早期这个原则叫做“see and point”(在图 1),因为所有可能的操作都由用户看得见的对象替代了,例如按钮,图标或菜单列表项:找到你想要的操作,把鼠标光标放上去,然后点击执行。简单地说,发现性意味着使操作视觉上可发现,这样就不用把这些操作记下来。传统电脑桌面的菜单很好地体现了这个目的,标记的图标同样是的。未标记的图标经常失败,但最糟糕的罪魁祸首是完全没有任何线索。请注意苹果的指导手册里再也没有可发现性了。 ### 反馈 @@ -145,7 +145,7 @@ iOS中大部分或者全部丢失的重要原则是:可发现性,反馈, ### 可恢复性 -错误发生时,恢复不会比重做难。(在指南和图1中叫做“forgiveness”,这也从当前的指南中消失了。)恢复是用“撤销”命令来实现的。撤消起源于1974年(当时的)施乐公司的帕洛阿尔托研究中心(PARC),可能是由Warren Teitelman提出。众所周知的苹果Lisa和Macintosh,他们的基本机构是由在PARC(苹果从富士施乐购买的版权)的早期开发工作得来的。撤销命令可以通过“重做”命令撤销。撤消和重做提供了从错误中恢复的一个有效的方法,但是也可以用来尝试,知道测试的操作可以随时撤销或重做。 +错误发生时,恢复不会比重做难。(在指南和图 1 中叫做“forgiveness”,这也从当前的指南中消失了。)恢复是用“撤销”命令来实现的。撤消起源于1974年(当时的)施乐公司的帕洛阿尔托研究中心(PARC),可能是由Warren Teitelman提出。众所周知的苹果Lisa和Macintosh,他们的基本机构是由在PARC(苹果从富士施乐购买的版权)的早期开发工作得来的。撤销命令可以通过“重做”命令撤销。撤消和重做提供了从错误中恢复的一个有效的方法,但是也可以用来尝试,知道测试的操作可以随时撤销或重做。 撤销使用户能够恢复内容。返回是一个同伴命令,使用户返回到之前在导航系统中的位置。原始的图形用户界面通过关闭导航来结束,然后把文档和工具呈现给用户。浏览器和iOS是一个倒退到以前的导航界面,用户在迷宫一样的通向模态屏幕的通道中彷徨。 diff --git a/TODO/how-the-heck-does-async-await-work-in-python-3-5.md b/TODO/how-the-heck-does-async-await-work-in-python-3-5.md index 74a11bc0776..624c8eeae50 100644 --- a/TODO/how-the-heck-does-async-await-work-in-python-3-5.md +++ b/TODO/how-the-heck-does-async-await-work-in-python-3-5.md @@ -2,7 +2,7 @@ * 原文作者 : [Brett Cannon](http://www.snarky.ca/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [Yushneng](https://github.com/rainyear) -* 校对者: [L9m](https://github.com/L9m),[iThreeKing](https://github.com/iThreeKing) +* 校对者: [L9m](https://github.com/L9m),[joyking7](https://github.com/joyking7) # Python3.5 协程原理 diff --git a/TODO/i-m-a-web-developer-and-i-ve-been-stuck-with-the-simplest-app-for-the-last-10-days.md b/TODO/i-m-a-web-developer-and-i-ve-been-stuck-with-the-simplest-app-for-the-last-10-days.md index 9a0823aac17..82a0bdcb904 100644 --- a/TODO/i-m-a-web-developer-and-i-ve-been-stuck-with-the-simplest-app-for-the-last-10-days.md +++ b/TODO/i-m-a-web-developer-and-i-ve-been-stuck-with-the-simplest-app-for-the-last-10-days.md @@ -2,7 +2,7 @@ * 原文作者 : [pistacchio](https://medium.com/@pistacchio) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [woota](https://github.com/woota) -* 校对者: [iThreeKing](https://github.com/iThreeKing), [sqrthree](https://github.com/sqrthree) +* 校对者: [joyking7](https://github.com/joyking7), [sqrthree](https://github.com/sqrthree) # JavaScript 生态之乱象 diff --git a/TODO/lecture-1-what-is-product-design.md b/TODO/lecture-1-what-is-product-design.md index 8b3821fcc4a..9e54f554ccc 100644 --- a/TODO/lecture-1-what-is-product-design.md +++ b/TODO/lecture-1-what-is-product-design.md @@ -2,7 +2,7 @@ * 原文作者 : [Andrew Aquino](https://medium.com/@andrewaquino) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [Zhangjd](https://github.com/zhangjd) -* 校对者: [hikerpig](https://github.com/hikerpig), [iThreeKing](https://github.com/iThreeKing) +* 校对者: [hikerpig](https://github.com/hikerpig), [joyking7](https://github.com/joyking7) ![](https://cdn-images-1.medium.com/max/2000/1*kOx2oUFQrrXhbUF9CMQHog.jpeg) diff --git a/TODO/python-3-an-intro-to-encryption.md b/TODO/python-3-an-intro-to-encryption.md index 647401215b8..ff41e26ce63 100644 --- a/TODO/python-3-an-intro-to-encryption.md +++ b/TODO/python-3-an-intro-to-encryption.md @@ -2,7 +2,7 @@ * 原文作者 : [Mike](http://www.blog.pythonlibrary.org/author/mld/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [Yushneng](https://github.com/rainyear) -* 校对者: [Zheaoli](https://github.com/Zheaoli), [iThreeKing](https://github.com/iThreeKing) +* 校对者: [Zheaoli](https://github.com/Zheaoli), [joyking7](https://github.com/joyking7) # 探索 Python 3 加密技术 diff --git a/TODO/rxswift-at-first-sight.md b/TODO/rxswift-at-first-sight.md index 25161b765b4..88d6a32fdfb 100644 --- a/TODO/rxswift-at-first-sight.md +++ b/TODO/rxswift-at-first-sight.md @@ -2,7 +2,7 @@ * 原文作者 : [alltheflow](https://blog.alltheflow.com/) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) * 译者 : [SatanWoo](https://github.com/SatanWoo) -* 校对者 : [iThreeKing](https://github.com/iThreeKing), [davidear](https://github.com/davidear) +* 校对者 : [joyking7](https://github.com/joyking7), [davidear](https://github.com/davidear) * 状态 : 校对完成 # RxSwift 的第一印象 diff --git a/TODO/the-secret-to-writing-killer-product-copy.md b/TODO/the-secret-to-writing-killer-product-copy.md index e9424bf5c6b..efbab0f95d3 100644 --- a/TODO/the-secret-to-writing-killer-product-copy.md +++ b/TODO/the-secret-to-writing-killer-product-copy.md @@ -1,7 +1,7 @@ > * 原文链接 : [The Secret To Writing Killer Product Copy](https://mng.lincolnwdaniel.com/the-secret-to-writing-killer-product-copy-4f23b7d0c842#.cdbnonpna) * 原文作者 :[Dave Gerhardt](https://medium.com/@davegerhardt) * 译文出自 : [掘金翻译计划](https://github.com/xitu/gold-miner) -* 译者 : [iThreeKing](https://github.com/iThreeKing) +* 译者 : [joyking7](https://github.com/joyking7) * 校对者 : [devSC](https://github.com/devSC)、[L9m](https://github.com/L9m) diff --git a/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md b/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md index 0f1b1c71fcf..d607df97986 100644 --- a/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md +++ b/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md @@ -2,164 +2,164 @@ > * 原文作者:[Uday Hiwarale](https://medium.com/@thatisuday) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md](https://github.com/xitu/gold-miner/blob/master/TODO1/an-introduction-to-raspberry-pi-4-gpio-and-controlling-it-with-node-js.md) -> * 译者: -> * 校对者: +> * 译者:[Weirdochr](https://github.com/Weirdochr), [lsvih](https://github.com/lsvih) +> * 校对者:[xionglong58](https://github.com/xionglong58) -# An introduction to Raspberry Pi 4 GPIO and controlling it with Node.js +# 树莓派 4 GPIO 简介及使用 Node.js 控制树莓派 -> RASPBERRY PI + NODE.JS -> In this article, we will get familiar with the GPIO of Raspberry Pi and its technical specifications. We will also go through a simple example of Input and Output with a Led and a Switch. +> 树莓派 + NODE.JS +> 通过本文,我们将熟悉树莓派 GPIO 及其技术规范。并且,我们将通过了一个简单例子,说明如何使用树莓派的 I/O 控制 LED 和开关。 -![(Source: [**pexels.com**](https://www.pexels.com/photo/have-a-break-led-signage-2249342/))](https://cdn-images-1.medium.com/max/12000/1*t-dr_5CrKf45RE0Uuww2sg.jpeg) +![(文章来源:[**pexels.com**](https://www.pexels.com/photo/have-a-break-led-signage-2249342/))](https://cdn-images-1.medium.com/max/12000/1*t-dr_5CrKf45RE0Uuww2sg.jpeg) -You might have come across the term “**IoT**”, it is an acronym for the **Internet of Things**. This basically means that a device (**thing**) that can be controlled from the internet. An example of an IoT would be smart bulbs in your house which can be controlled from your smartphone. +你可能见过 “**IoT**” 这个术语,它是 **Internet of Things(物联网)** 的缩写。意思是,人们可以通过互联网控制一台设备(即“物” **thing**)。比如,用手机控制你房间内的智能电灯泡就是一种物联网的应用。 -Since an IoT can be controlled from the internet, it should always be connected with the internet. There are primarily two ways we can connect a device to the internet, either through an Ethernet cable or through WiFi. +由于物联网设备可通过互联网控制,所以 IoT 设备需要始终与互联网相连。我们主要有两种方式将设备连接至互联网:以太网网线和 WiFi。 -IoT devices can be used for various purposes. For example, you can use an IoT to control the temperature of your house, control lighting or turn on devices before you get home, right from your smartphone. +物联网设备可被用于各种目的。例如,你可以使用物联网来控制你家的室内温度、照明或者在回家前打开某些设备,所有这些操作都只需要通过你的手机便能实现。 -So what are the technical specifications of an IoT device? Well, in a nutshell, it should have the means to connect to the internet, have some input and output sockets to read/write analog or digital signals to and from a device, and bare minimal hardware to read and execute instructions from a program. +那么,物联网设备的技术规范有哪些?简言之,它应该包含连接到互联网的工具,有一些输入和输出接口来读写设备的模拟或数字信号,并且使用最少的硬件来读取和执行程序指令。 -An IoT device has a hardware component that provides an interface for external devices to read digital data or to get electricity. This is called **GPIO** or **General Purpose Input Output**. This hardware component is basically a series of pins that can be connected to external devices. +一个物联网设备配有一个硬件组件,为外部设备读取数字数据和取电提供接口。该接口就是 **GPIO** 或称作 **General Purpose Input Output(通用输入输出接口)** 。这种硬件组件基本上都是由一系列可以连接到外部设备的引脚(或管脚,pin)构成。 -These GPIO pins can be controlled by a program. For example, based on some conditions, we can turn on a GPIO pin which provides 5V electricity and any device which is connected to this pin will turn on. This program can listen to a message sent from the internet and control this pin. Hence the IoT. +这些 GPIO 引脚可以被程序控制。比如,在满足一些条件的情况下,我们可以给一个 GPIO 引脚施以 5V 的电压,任何连接到该引脚的设备都会被开启。程序也能够监听来自互联网的信号,并根据该信号对 GPIO 引脚进行控制。这就是物联网。 -Building such an IoT device from scratch can be tough since it has a lot of components to work with. Luckily, there are pre-built devices that you can purchase and they are extremely cheap. These devices come with GPIO hardware and means to connect to the internet. +从头开始构建这样一个物联网设备可能很困难,因为需要处理的组件有很多。幸运的是,我们可以购买售价低廉的现成的设备。这些设备配有 GPIO 硬件和连接互联网的工具。 -#### Arduino Microcontroller +#### Arduino 微控制器 -At the moment, if we are looking for simple automation, [**Arduino**](https://en.wikipedia.org/wiki/Arduino) is the best device to go for. It is a **micro-controller** that can be programmed using programming languages like C and C++. +目前,如果我们想要实现简单的自动化,那么 [**Arduino**](https://en.wikipedia.org/wiki/Arduino) 是最好的选择。它是一个 **微控制器(micro-controller)** ,可以用 C 和 C++ 这样的编程语言来编写 Arduino 程序。 -![(Source: [**Wikipedia**](https://en.wikipedia.org/wiki/File:Arduino_Uno_-_R3.jpg))](https://cdn-images-1.medium.com/max/2000/1*-Tmb_Q7yYmmtFGaUk6iv4A.jpeg) +![(来源:[**Wikipedia**](https://en.wikipedia.org/wiki/File:Arduino_Uno_-_R3.jpg))](https://cdn-images-1.medium.com/max/2000/1*-Tmb_Q7yYmmtFGaUk6iv4A.jpeg) -However, it does not come with the built-in WiFi or Ethernet jack and an external peripheral device (**called as a** shield) has to be connected to connect the Arduino to the internet. +然而,该控制器不配有内置 WiFi 或以太网插孔,并且必须连接外部外围设备(即**屏蔽**)才能将 Arduino 连接到互联网。 -Arduino is meant to be used as a controller for external devices and not a fully-fledged IoT device. Hence, they are extremely cheap. Some of the latest models can go as low as $18. +Arduino 旨在充当外部设备的控制器,而不是成熟的物联网设备。因此,该控制器价格非常便宜,某些最新款的售价可以低至 18 美元。 -#### Raspberry Pi Micro-computer +#### 树莓派微型电脑 -Compared to Arduino, [**Raspberry Pi**](https://en.wikipedia.org/wiki/Raspberry_Pi) is a **beast**. It was created to promote the teaching of basic computer science in schools and in developing countries, but it was picked up by nerds and hobbyists to create new shit. At the moment, it is one of the most popular **single-board computers** in the world. +相较于 Arduino,[**树莓派**](https://en.wikipedia.org/wiki/Raspberry_Pi) 更像是一只**野兽**。其发明之初的目的就是为了促进基础计算机科学教学在学校和发展中国家的进步。但它现在却被书呆子和业余爱好者们捡起来创造各种各样的小玩意儿。目前,它是世界上最受欢迎的**单板计算机**之一。 -Raspberry Pi (**latest Model 4B**) comes with an Ethernet connector, WiFi, Bluetooth, HDMI output, USB connectors, a 40-pin GPIO, and other essential features. It is powered by an **ARM** CPU, a **Broadcom** GPU and 1/2/4 GB of **RAM**. You can see these specifications from [**this**](https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications) Wikipedia table. +树莓派(**最新版 4B**)配有以太网连接器、WiFi、蓝牙、HDMI 输出、USB 连接器、 40 个 GPIO 引脚和其他基本功能。它由 **ARM** CPU、 **博通** GPU 和 1/2/4 GB 的 **RAM** 驱动。你可以在[**此维基百科**](https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications)的表格中查看这些规范。 -![(Source: [**Wikipedia**](https://en.wikipedia.org/wiki/File:Raspberry_Pi_4_Model_B_-_Side.jpg))](https://cdn-images-1.medium.com/max/2000/1*WE-9WUau6aQlMSHVLjq9KQ.jpeg) +![(来源:[**Wikipedia**](https://en.wikipedia.org/wiki/File:Raspberry_Pi_4_Model_B_-_Side.jpg))](https://cdn-images-1.medium.com/max/2000/1*WE-9WUau6aQlMSHVLjq9KQ.jpeg) -Despite this heavy hardware, the latest model costs between **$40** to **$80**. Don’t forget, this is a fully-fledged computer with a native operating system. This means we do not need to connect with an external computer to program it. +尽管树莓派的硬件很丰富,但它最新版的售价也仅在 \$40 到 \$80 间。别忘了,这可是一台拥有原生操作系统的成熟计算机。这意味着我们不需要连接外部计算机就能对其进行编程。 -However, unlike our day to day computers, Raspberry Pi provides a GPIO hardware component to control external devices. This makes the Raspberry Pi a device that can do just about anything. +与我们日常使用的电脑不同,树莓派提供了一个 GPIO 硬件组件来控制外部设备。这使得树莓派成为了一种几乎可以做任何事情的设备。 -Let’s understand the technical specifications of this GPIO. +让我们了解一下新版树莓派 GPIO 的技术规格。 --- -## Raspberry Pi - GPIO pinout +## 树莓派 - GPIO 引脚分配 -Raspberry Pi (**model 4B**) has **40 GPIO pins** in total, stacked in `20 x 2` array. As shown in the below diagram, each pin has a specific purpose. +树莓派(**4B 版**)总共 **40 个 GPIO 引脚**,分布在 `20 x 2` 的阵列当中。如下图所示,每个引脚都有特定的用途。 -![(Source: [**raspberrypi.org**](https://www.raspberrypi.org/documentation/usage/gpio/))](https://cdn-images-1.medium.com/max/4128/0*VsaGvGskvJa20hZa.png) +![(来源:[**raspberrypi.org**](https://www.raspberrypi.org/documentation/usage/gpio/))](https://cdn-images-1.medium.com/max/4128/0*VsaGvGskvJa20hZa.png) -Before we discuss the functionality of each pin, let’s understand some conventions first. Each pin has a specific number attached to it and that’s how we can control these pins from the software. +在讨论每个引脚的功能之前,让我们先了解一些协议。每个引脚都有特定的编号,我们就是通过这些编号从软件中控制这些引脚。 -The numbers you can see in the circle is physical pin numbers on the GPIO hardware. For example, **pin no. 1** provides a constant 3.3V power. This number system is called **Board Pin** or **Physical Pin** numbering system. +在圆圈中,你可以看到的数字是 GPIO 硬件上的物理引脚编号。例如:**1 号引脚** 提供 3.3V 的恒定电压。该编号系统称为 **Board pin** 或**物理引脚**编号系统。 -We also have another pin numbering system created by [**Broadcom**](https://en.wikipedia.org/wiki/Broadcom_Inc.) since Raspberry Pi 4B uses the [**BCM2711**](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md) processor chip. This pin numbering system is called **BCM** or **Broadcom Mode**. The label attached with each pin in the above diagram shows BCM pin numbers. For example, physical **pin no. 7** is **BCM pin no. 7** and labeled as **GPIO 4**. +由于树莓派 4B 使用 [**BCM2711**](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md) 处理器芯片,因此,我们还有另一个由[**博通**](https://en.wikipedia.org/wiki/Broadcom_Inc.)创建的引脚编号系统。此系统被称为 **BCM** 或 **博通模式**。上图中,每个引脚附带的标签都显示了 BCM 引脚编号。例如:物理 **7 号引脚**是 **BCM 7 号引脚**并被标记为 **GPIO 4**。 -We can choose to follow either the **Board** or **BCM** numbering system. However, depending on the programming library we use to access the GPIO, we could be stuck with one of them. However, most libraries out there prefer the BCM numbering system since it is referred by the Broadcom CPU chip. +我们既可以选择遵循 **Board pin** 编码,也可以用 **BCM** 编码系统。然而,由于我们用 GPIO 编程库的原因,同时使用该两种编码系统可能会遇到问题。大多数库都偏好于 BCM 编号系统,因为它引用于博通 CPU 芯片。 -> From here on, if I use **Pin no. x**, it means the **physical pin number** on the board. The BCM pin number will be mentioned with BCM. +> 从现在开始,如果文中出现 **x 号引脚**,就意味着这是引脚板上的**物理引脚编号**。如果提到了 BCM,则意味着我们在使用 BCM 引脚编号。 -#### 💡 Power and Group Pins +#### 💡 电源引脚和引脚分组 -Pin no. **1** and **17** provide **3.3V** power while pin no. **2** and **4** provide **5V** power. These pins provide **constant power** when you turn on the Raspberry Pi and these are **not programmable** by any means whatsoever. +**1 号**和 **17 号**引脚提供 **3.3V** 电源,而 **2 号**和 **4 号**引脚提供 **5V** 电源。当你打开树莓派时,这些引脚便会提供**恒定功率**,并且无论在何种条件下,这几个引脚都是**不可编程的**。 -Pin no. **6**, **9**, **14**, **20**, **25**, **30**, **34** and **39** provide the ground connection. This is where the **cathode** of a circuit should be attached. We can use a single ground pin for all ground connections in the circuit since they are connected to the same ground rail. +**6 号**、 **9 号**、 **14 号**、 **20 号**、 **25 号**、 **30 号**、 **34 号**和 **39 号**引脚支持接地。它们应该与电路的**阴极**相连。电路中所有的接地连接都可以用同一个接地引脚,因为它们都连接到同一根地线。 -> If you are wondering why so many ground pins, then you can follow [**this thread**](https://www.raspberrypi.org/forums/viewtopic.php?t=132851). +> 如果你想知道为什么有这么多接地引脚,可以查看[**这个帖子**](https://www.raspberrypi.org/forums/viewtopic.php?t=132851)。 -#### 🔌 GPIO Pins +#### 🔌 GPIO 引脚 -Except for **Power** and **Ground** Pins, rests are general-purpose input and output pins. When a GPIO pin is used in **output mode**, it provides 3.3V constant power when it is turned on. +除了**电源**和**接地**引脚外,其他引脚均为通用输入和输出引脚。当 GPIO 引脚用于**输出模式**时,它在开启时提供 3.3V 恒定功率。 -In the **input mode**, a GPIO pin can also be used to listen for external power. Technically, when a **3.3V** is supplied to a GPIO pin (**when it is in the input mode**), the pin will read as **logical high** or **1**. When the pin is grounded or supplied with **0V**, it will read as **logical low** or **0**. +在**输入模式**下,GPIO 引脚也可用于监听外部电源。从技术上看,当用 **3.3V** 电压供给处于输入模式的 GPIO 引脚时,该引脚将被读取为**逻辑高电平**或 **1**。当引脚接地或提供 **0V** 功率时,它会被读作**逻辑低电平**或 **0**。 -The output mode is fairly straightforward. In the output mode, we turn on a pin and it sends the 3.3V through the pin. However, in the input of a pin, we need to listen for voltage changes on the pin and when the pin is at the logical high or low, we can do other things like turn on an output GPIO pin. +而**输出模式**更加简单。在输出模式下,我们接通一个引脚,设备会通过该引脚提供 3.3V 的电压。而在引脚的输入端,我们需要监听引脚上的电压变化,当引脚处于逻辑高电平或低电平时,我们可以执行其他操作,如打开一个输出 GPIO 引脚。 -#### 🧙‍♀️ SPI, I²C, and UART Protocols +#### 🧙‍♀️ SPI、 I²C 和 UART 协议 -SPI ([**Serial Peripheral Interface**](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface)) is a synchronous serial communication interface used by devices to talk to each other. This interface needs 3 or more data lines to connect a master device to a slave device (**out of one or many**). +SPI([**Serial Peripheral Interface (串行外设接口)**](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface))是一种同步串行通信接口,设备可以使用它来实现相互间的通信。此接口需要 3 条或更多数据线将主设备连接到(**一个或多个**)从设备。 -I²C ([**Inter-Integrated Circuit**](http://C)) is also similar to SPI but it supports multiple master devices. Also, unlike SPI, it only requires two data lines for unlimited numbers of slaves. However, this makes I²C slower than SPI. +I²C([**Inter-Integrated Circuit (内置集成电路)**](http://C))类似于 SPI,但它支持多个主设备。此外,与 SPI 不同,它只需要两条数据线来容纳多个从机。不过这会让 I²C 比 SPI 慢。 -UART ([Universal asynchronous receiver-transmitter](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter)) is also a serial communication interface but data is sent [**asynchronously**](https://en.wikipedia.org/wiki/Asynchronous_serial_communication). +UART([Universal asynchronous receiver-transmitter (通用异步收发传输器)](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter))也是一个串行通信接口,但数据是[**异步**](https://en.wikipedia.org/wiki/Asynchronous_serial_communication)发送的。 -Raspberry Pi provides a low-level interface to enable these interfaces through GPIO pins just like input and output mode we discussed earlier. However, not all GPIO pins can be configured from these kinds of communications. +树莓派提供了一个底层接口用于通过 GPIO 引脚就像我们前文讨论过的输入输出模式一样启用这些接口。然而,并非所有的 GPIO 引脚都可以实现这些通信方式。 -In the below diagram, you can see which GPIO pins can be configured from SPI, I²C and UART protocols. You should visit **[pinout.xyz](https://pinout.xyz/).** This web application provides an interactive interface to see what each GPIO pin does. +在下图中,你可以看到哪些 GPIO 针脚是可以通过 SPI、I²C 和 UART 协议进行配置的。你可以访问 **[pinout.xyz](https://pinout.xyz/)**,这个网页提供了一个交互界面供用户查看每个 GPIO 引脚的功能。 -![(Source: [**pinout.xyz**](https://pinout.xyz/))](https://cdn-images-1.medium.com/max/2000/1*mpKa3QDHL6G5CmjmMWX3UQ.png) +![(来源:[**pinout.xyz**](https://pinout.xyz/))](https://cdn-images-1.medium.com/max/2000/1*mpKa3QDHL6G5CmjmMWX3UQ.png) -Besides in a simple input or output mode, a GPIO pin can work in **6 modes** but only one at a time. When you click on a GPIO pin (**in the above website**), you would be able to see its modes on the right side. These are mentioned with ALT0 to ALT5 in the right table. +除了简单的输入或输出模式,GPIO 引脚有 **6 种模式**,但每次只能在一种模式下工作。当你在上面那个网页中点击 GPIO 引脚时,你可以在屏幕右侧看到它的工作模式。右表中的 ALT0 至 ALT5 描述了这些模式。 -> You can learn about the specifications of these communication protocols from [**this video**](https://www.youtube.com/watch?v=IyGwvGzrqp8). We won’t be working with these communication protocols in this tutorial, however, I will be covering these topics in the upcoming articles. +> 你还可以通过[**这个视频**](https://www.youtube.com/watch?v=IyGwvGzrqp8)来了解这些通信协议的规范。在本教程中,我们不会涉及这些通信协议,但是,我将在接下来的文章中讨论相关主题。 -#### ⚡ Current Specifications +#### ⚡ 现行规范 -We have talked about the voltage specifications of the power and GPIO pins. The current specifications are little foggy because they are not mentioned in the Raspberry Pi official documentation. +我们已经讨论过电源和 GPIO 引脚的电压规格。因为树莓派官方文件中未曾提及具体规范,所以现行规范还不太明确。 -However, we follow a safety precaution while handling the current. The maximum current that can be drawn from any pin should be less than or equal to **16mA**. Hence, we must adjust our load to meet this requirement. +不过可以确定的是,我们在处理电流时,必须要遵循安全措施:从任何引脚获取的最大电流应小于或等于 **16mA**。因此,我们必须调整负载以满足这一要求。 -If we have connected multiple devices to the Raspberry Pi GPIO and other ports like USB, then we must ensure that the maximum current drawn from the circuit is less than **50mA**. +如果我们已经将多个设备连接到树莓派 GPIO 和其他端口(如 USB),那么我们必须确保从电路获取的最大电流小于 **50mA**。 -To limit the current, we can add resistors to the circuit so that the maximum current drawn does not cross these limits. When a device needs more power than Raspberry Pi can provide, we should be using relay switches instead. +为了限制电流,我们可以在电路中增加电阻,使得最大电流不会超过这些限制。当一个设备需要的电流比树莓派的最大限制还要大时,应当使用继电器开关。 -When it comes to the **input**, these same specifications are used. When a GPIO pin is used as a **drain** (**instead of a** source **of the current**), we should not supply more than **16mA**. Also when multiple GPIO pins are used as input, no more than **50mA** current should be applied in total. +**输入**模式使用的也是相同的规范。当 GPIO 引脚被用作**漏极**(**而非** 源 **电流**)时,我们不应该供应超过 **16mA** 的电流。此外,当多个 GPIO 引脚用作输入时,总共不应施加超过 **50mA** 的电流。 --- -## Prerequisites +## 前提条件 -I believe that you have gone through the setup of the Raspberry Pi. This means you have installed an operating system like [**Raspbian**](https://www.raspberrypi.org/downloads/raspbian/) or your personal favorite and you can access it through SSH or HDMI. +我相信你已经走过一遍树莓派的设置流程。这意味着你已经安装了一个 [**Raspbian**](https://www.raspberrypi.org/downloads/raspbian/) 之类的或是你个人偏好的操作系统,并且可以通过 SSH 或 HDMI 访问它。 -The first thing we need to do is create a project directory. I have created the project directory at `/home/pi/Programs/io-examples` where all our programs will live for these tutorial examples. +我们需要做的第一件事就是创建项目目录。我已经在 `/home/pi/Programs/io-examples` 这个路径下创建了项目目录,我们所有的程序都将作为教程示例保存在该路径下。 -Since we want to control the GPIO pins using Node.js, we need to install Node first. You can choose your favorite method but I personally use **[NVM](https://github.com/nvm-sh/nvm)** (**node version manager**). You can follow [**these recommended steps**](https://github.com/nvm-sh/nvm#install--update-script) to install it. +由于我们想通过 Node.js 来控制 GPIO 引脚,首先我们必须安装 Node。你可以选择你最喜欢的方法,但我个人会使用 **[NVM](https://github.com/nvm-sh/nvm)**(Node 版本管理器)来安装。你可以遵循[**该建议步骤**](https://github.com/nvm-sh/nvm#install--update-script)安装 NVM。 -Once you have NVM installed, we can proceed further to install a specific version of Node. I will be using Node v12 since it is the latest stable version. To install Node v12, use the below commands. +一旦装好了 NVM,我们就可以安装特定版本的 Node。我将使用 Node v12,因为它是最新的稳定版本。要安装 Node v12,请输入以下命令行: -``` -$ nvm install 12 -$ nvm use 12 +```bash +nvm install 12 +nvm use 12 ``` -Once Node.js is installed on the Raspberry Pi, we can move ahead with the project creation. Since we want to control the GPIO pins, we need a library that can provide an easy API to do that for us. +一旦树莓派安装了 Node.js,我们就可以继续创建项目了。因为我们想要控制 GPIO 引脚,所以我们需要一个库来为我们提供一个简单的应用编程接口。 -One great library to control GPIO on Raspberry Pi is [**onoff**](https://www.npmjs.com/package/onoff). From the project directory, first, create the package.json and then install `onoff` package. +[**onoff**](https://www.npmjs.com/package/onoff) 是一个知名的用树莓派控制 GPIO 的库。首先,在项目目录中创建 package.json,然后安装 `onoff` 包。 -``` -$ cd /home/pi/Programs/io-examples -$ npm init -y -$ npm i -S onoff +```bash +cd /home/pi/Programs/io-examples +npm init -y +npm i -S onoff ``` -Now that we have everything we need, we can process with the circuit design and write our first program to test the power of GPIO. +现在一切准备就绪,我们可以开始电路设计并编写第一个程序来测试 GPIO 的能力。 --- -## Output example with LED +## LED 输出示例 -In this example, we will turn on a Red LED programmatically. Let’s take a look at the below circuit diagram. +在本例中,我们将以编程方式打开红色 LED。让我们先看看下面的电路图: -![(Simple LED Output)](https://cdn-images-1.medium.com/max/3126/1*aarORNzRCTnQlSL-F6pe5Q.png) +![(简单 LED 输出)](https://cdn-images-1.medium.com/max/3126/1*aarORNzRCTnQlSL-F6pe5Q.png) -From the above circuit diagram, we have connected **Pin no. 6** (**ground pin**) to the negative (**ground**) rail of the breadboard and **BCM 4** to the one end of a **1k ohm** resistor. The other end of the resistor is connected to the input of a Red LED and the output of the LED drains to the ground. +从上图可以看出,我们已经将 **6 号引脚**(**接地引脚**)连接到了线路板的负极(**地线**)上,并将 **BCM 4** 连接到了 **1k ohm** 电阻的一端。电阻器的另一端连接到红色 LED 的输入端上,LED 的输出端接地。 -There is nothing interesting about this circuit except the resistor. The resistor is needed because Red LED operates at **2.4V** and a GPIO pin provides **3.3V** which can damage the LED. Also, the LED draws **20mA** which is above the safe limit of Raspberry Pi, hence resistor will also prevent the excess current. +除了有个电阻,这个电路没什么特别的。需要这个额外的电阻是因为红色 LED 在 **2.4V** 电压下工作,而提供 **3.3V** 电压的 GPIO 会损坏 LED。此外,LED 采用的 **20mA** 超过了树莓派的安全阈值,因此,也需要这个电阻来防止电流过大。 -> We can choose between 330 ohms to 1k ohm resistance. This will impact the current flow but won’t damage the LED. +> 我们可以选择 330 ohms 到 1k ohms 的电阻。这个数值范围的电阻会影响电流大小,但都不会损坏 LED。 -From the above circuit, the only variable in the circuit is BCM 4 pin output. If the pin is on (**3.3V**), the circuit will close and LED will glow. If the pin is off (**0V**), the circuit is open and LED won’t glow. +从上述电路来看,电路中唯一的变量是 BCM 4 引脚输出。如果引脚打开(**3.3V**),电路将闭合,LED 将发光。如果引脚关闭(**0V**),电路断开,LED 不会发光。 -Let’s write a program that can programmatically turn on the BCM 4 pin. +让我们编写一个程序,实现以编程方式打开 BCM 4 引脚。 ```JavaScript const { Gpio } = require( 'onoff' ); @@ -177,41 +177,41 @@ setInterval( () => { }, 3000 ); // 3s ``` -In the above program, we are importing `onoff` package and extracting `Gpio` constructor. The `Gpio` class configures a GPIO with a certain configuration. In the above example, we have set **BCM 4** in the **output mode**. +在上述程序中, 我们导入 `onoff` 包并引入 `Gpio` 构造函数。用设定好的配置创建 `Gpio` 类来配置一个 GPIO。上面的例子中,我们将 **BCM 4** 设置成了**输出模式**。 -> You can follow [**this API documentation**](https://github.com/fivdi/onoff#api) of the `onoff` module to understand various configurations options and API methods. +> 你可以参考该 `onoff` 模块的 [**API 文档**](https://github.com/fivdi/onoff#api)来了解各种配置选项和 API。 -An instance of `Gpio` class provides high-level API to interact with that pin. The `writeSync` method writes either **1** or **0** to the pin which enables or disables it. When a pin is set to **1**, it turns **on** and outputs the **3.3V** power. When it is set to **0**, it turns **off** and does not provide any power (**0V**). +`Gpio` 类创建的实例提供了与该引脚交互的高阶 API。`writeSync` 方法会将 **1** 或 **0** 写入引脚,以实现开启或关闭引脚。当引脚设为 **1** 时,引脚**开启**并输入 **3.3V** 电源。当它设为 **0** 时,引脚会**关闭**且不再提供任何电源电压(**0V**)。 -Using `setInterval`, we are running an endless loop that writes either 0 or 1 to the `ledOut` pin using `ledOut.writeSync(val)` method call. Let’s run this program using Node.js. +使用 `setInterval` 时,我们就是在运行一个无限循环,不断地调用 `ledOut.writeSync(val)` 方法在 `ledOut` 引脚中写入 0 或 1。让我们使用 Node.js 来运行这个程序: -``` -$ node rpi-led-out.js +```bash +node rpi-led-out.js ``` -Since this is an endless loop, once we start the program, it will not terminate unless we interrupt it forcefull using `ctrl + c`. During the lifetime of this program, it will toggle the **BCM 4** pin every **3 seconds**. +由于这是一个无限循环的程序,一旦启动,它就不会终止,除非我们使用 `ctrl + c` 强制终止程序。在该程序的生命周期内,它将每隔 **3 秒**切换一次 **BCM 4** 引脚的状态。 -One interesting thing about the Raspberry Pi GPIO, once a GPIO pin is set to **1** or **0**, it will stay like that until we override the value again or turn off the power supply to the Raspberry Pi. When when you start the program, the LED is off but when you stop it, the LED might remain on. +树莓派 GPIO 有意思的一点是,一旦 GPIO 引脚被设为 **1** 或 **0**,它将一直保持不变, 除非我们覆盖该值或关闭树莓派的电源。比如,当你启动程序时,LED 处于熄灭状态,但当你终止程序时,LED 可能会保持亮起状态。 -## Input example with Switch +## 开关输入示例 -As we know, when a GPIO is used as an input, we need to supply a voltage close to **3.3V**. We can hook up a switch (**push button**) that supplies a voltage directly from **3.3V** pin as shown in the circuit diagram below. +众所周知,当把 GPIO 用作输入时,我们需要提供接近 **3.3V** 的电压。我们可以连接一个开关(**按钮**)直接从 **3.3V** 引脚提供电压,如下图所示: -![(Simple Button Input)](https://cdn-images-1.medium.com/max/3126/1*8TUu5IGDaYm0movHCM9hww.png) +![(简单按钮输入)](https://cdn-images-1.medium.com/max/3126/1*8TUu5IGDaYm0movHCM9hww.png) -We have used a **1K ohm** resistor before the input of the switch to provide some resistance in the circuit. This will prevent too much current drawn from the **3.3V** supply and prevent our switch from getting fried. +在输入开关之前,我们已经在电路中使用了一个 **1K ohm** 的电阻。它能防止 **3.3V** 电源产生过大的电流,避免开关熔断。 -We have also attached a **10K ohm** resistor that also draws the current from the output of the button and drains to the ground. These types of resistors (**because of their position in the circuit**) are called **pull-down** resistors since they drain the current (**or atmospheric charge build-up**) to the ground. +我们还连接了一个 **10K ohm** 电阻,该电阻也从按钮的输出端汲取电流并接地。这类电阻被称为**下拉**电阻(**因为它们在电路中的位置**),它们会将电流(**或大气中电荷聚集产生的电流**)导向地面。 -> We can alternatively add a **pull-up register** which pulls the current from **3.3V** pin and provides to the input GPIO pin. In this configuration, the input pin always reads **high** or **1**. When the button is pressed, the switch creates a short circuit between the resistor and the ground draining all the current to the ground and no current is passed through the switch to the input pin and it reads **0**. [**Here is a great video**](https://www.youtube.com/watch?v=5vnW4U5Vj0k) demonstrating the pull-up and pull-down resistors. +> 我们也可以增加一个**上拉电阻**,从 **3.3V** 引脚导出电流,供给给 GPIO 的输入引脚。在这种配置下,输入引脚会始终读取 **高** 或 **1**。按下按钮时,开关在电阻和地面之间产生短路,将所有电流导向地面,并且没有电流通过开关到达输入引脚,读数为 **0**。[**此处有一段很棒的视频**](https://www.youtube.com/watch?v=5vnW4U5Vj0k)演示了上拉和下拉电阻。 -The output of the switch is connected to the **BCM 17** pin. When the button (**switch**) is pressed, the current will flow through the switch into the BCM 17 pin. However, since the 10K ohm resistor provides a greater obstacle to the current flow, most current flow through the loop represented by the **red dotted line**. +开关的输出连接到 **BCM 17** 引脚。当按下按钮(**开关**)时,电流将通过开关流入 BCM 17 引脚。然而,由于 10K ohm 电阻给电流提供了更大的障碍,大多数电流会流向由**红色虚线**表示的回路。 -When the button is not pressed, the loop represented by the red dotted line is closed and no current will flow through it. However, the loop represented by the **grey dotted line** is closed, and the BCM 17 pin is grounded (**0V**). +未按下按钮时,由红色虚线表示的回路闭合,没有电流流过。然而,由**灰色虚线**表示的环路是闭合的,BCM 17 引脚接地(**0V**)。 -> The main reason to add a 10k ohm resistor is to connect BCM 17 pin to the ground so that it can not read any atmospheric disturbance as input high. By not connecting a input pin to the ground, we keep the input pin in **floating state**. In that state the input pin can read either 0 or 1 due to atmospheric disturbances. +> 增加一个 10k ohm 电阻是为了让 BCM 17 引脚接地,这样它就不会将任何大气干扰读取为高输入。如果不将输入引脚接地,输入引脚会保持在**浮动状态**。在这种状态下,由于大气干扰,输入引脚可能读取为 0 或 1。 -Now that our circuit is ready, let’s write a program to read input value. +既然电路已经准备好了,让我们编写一个程序来读取输入值: ```JavaScript const { Gpio } = require( 'onoff' ); @@ -230,41 +230,41 @@ switchIn.watch( ( err, value ) => { } ); ``` -In the above program, we have set **BCM 17** pin in the input mode. The third argument of the `Gpio` constructor configures when we want to get notified of the pin input voltage change. This is labeled as the **`edge`** argument since we are reading the value at the edge of voltage rise and drop cycle. +在上面的程序中,我们将 **BCM 17** 引脚设置为输入模式。`Gpio` 构造函数的第三个参数配置了我们何时需要引脚输入电压变化的通知。该参数名为 **`edge`**,因为我们读取的是电压上升和下降周期的边缘电压值。 -The `edge` argument can have the following values. +`edge` 参数可以有以下值: -When the `rising` value is used, we will get notified when the input voltage to a GPIO pin is **rising from 0V** (**to 3.3V**). At this position, the pin will read **logical high** or **1** because it is getting positive voltage. +当使用 `rising` 值时,如果 GPIO 引脚的输入电压**从 0V 上升**(**至 3.3V**),我们将收到通知。位于此位置时,引脚将读取**逻辑高位**或 **1**,因为该引脚获得了更高的电压。 -When the `falling` value is used, we will get notified when the input voltage is **falling to 0V** (**from 3.3V**). At this position, the pin will read **logical low** or **0** because it is losing voltage. +当使用 `falling` 值时,如果输入电压(**从 3.3V**) **降至 0V**,我们将收到通知。位于此位置时,引脚将读取**逻辑低位**或 **0**,因为它正在失去电压。 -When `both` value is used, we will get notified of the above two events. When the voltage is rising from 0V (**input high or 1**) or falling from 3.3V (**input low or 0**), we can listen to these events at once. +当使用 `both` 值时,我们将收到上述两个事件的通知。当电压从 0V 上升(**至输入高电平或 1**)或从 3.3V 下降(**至输入低电平或 0**)时,我们都会收到到这些事件的通知。 -> The `none` value is not discussed here, read the [**documentation**](https://github.com/fivdi/onoff#gpiogpio-direction--edge--options) to know more. +> 此处不讨论 `none` 值,请阅读[**文档**](https://github.com/fivdi/onoff#gpiogpio-direction--edge--options)了解更多信息。 -The `watch` method on a GPIO pin in the input mode watches for the above events. This is an asynchronous method, hence we need to pass a callback function which receives the input high (1) or input low (0) value. +输入模式下 GPIO 引脚上的 `watch` 方法监视上述事件。这是一个异步方法,因此我们需要传递一个回调函数,该函数接收输入高(1)或输入低(0)值。 -Since we are using `both` value, the `watch` method will execute the callback when the input voltage is rising as well as when the input voltage is falling. Based on the button press, you should get the below values in the console. +由于我们使用的是 `both` 值,所以 `watch` 方法将在输入电压上升时以及输入电压下降时都执行回调。按下按钮,你应该会在控制台中看到下面的值: ``` -Pin value 1 (when button is pressed) -Pin value 0 (when button is released) -Pin value 1 (when button is pressed) -Pin value 1 (repeat value) -Pin value 0 (when button is pressed) +Pin value 1 (按下按钮) +Pin value 0 (释放按钮) +Pin value 1 (按下按钮) +Pin value 1 (重复值) +Pin value 0 (按下按钮) ``` -If you inspect the above output carefully, we sometimes get duplicate values when the button is pressed or released. Since the physical connection between two connectors of the switch mechanism is not always smooth, it can connect and disconnect many times when a switch is not pressed carefully. +如果仔细检查以上输出就能发现,我们有时会在按下或释放按钮时得到重复的值。由于开关机制的两个连接器之间的物理连接并不总那么顺畅,所以,不小心按下开关时,它可以多次连接和断开。 -To avoid this, we can add capacity in the switch circuit which charges before the actually current flows in the GPIO pin and discharges smoothly when the button is released. You should give this a try since this is fairly simple. +为了避免这种情况,我们可以在开关电路中增加电容,在实际电流流入 GPIO 引脚之前充电,并在按钮释放时平稳放电。这种方法非常简单,你可以试一试。 -## Combined I/O example +## 组合 I/O 示例 -Now that we have a good understanding of how GPIO pin works and how we can configure them, let’s combine our last two examples. The bigger picture is to turn on the LED when the button is pressed and turn it off when the button is released. Let’s first look at the circuit diagram. +现在我们已经充分理解了 GPIO 引脚的工作原理以及配置方法,让我们结合最后两个例子进行讲解。更重要的是,按下按钮时,打开 LED 而释放按钮时关闭 LED。让我们先看看电路图: -![(Simple I/O Example)](https://cdn-images-1.medium.com/max/3126/1*c0iV6t3t2yPUVyT0mhU3OA.png) +![(简单 I/O 示例)](https://cdn-images-1.medium.com/max/3126/1*c0iV6t3t2yPUVyT0mhU3OA.png) -As you can see from the above example, we haven’t changed a thing from the above two examples. Also, both LED and Switch circuits are independent. Which means our earlier program should work just fine with this circuit. +从以上例子可以看出,我们没有从上面的两个例子中改变任何东西。另外,LED 和开关电路都是独立的。这意味着我们之前的程序在这条线路上应该可以正常工作。 ```JavaScript const { Gpio } = require( 'onoff' ); @@ -286,23 +286,19 @@ switchIn.watch( ( err, value ) => { } ); ``` -In the above program, we have GPIO pins configured in the input and output mode individually. Since the value provided by the `watch` method on an input pin is **0** or **1**, we can use the same value to write to an output pin. +在上述程序中,我们将 GPIO 引脚分别配置为输入和输出模式。由于输入引脚上的 `watch` 方法提供的值是 **0** 或 **1**,因此,我们直接把这些值写入输出引脚。 -Since we are watching `switchIn` input pin in `both` mode, the `watch` will get triggered when the button is pressed sending the `value` **1** and also when the button is released sending the `value` **0**. +因为我们在 `both` 模式下用 `watch` 方法监视输入引脚,当按下按钮发送 **1** 或者释放按钮发送 **0** 时,`watch` 方法的回调将被触发。 -We can use this value directly to write to the `ledOut` pin. Hence, when the button is pressed, `value` is `1` and `ledOut.writeSync(1)` will turn on the LED. the reserve will happen when the button is pressed. +我们可以直接使用该值写入 `ledOut` 引脚。因此,按下按钮时,`value` 为 `1` 并执行 `ledOut.writeSync(1)`,会打开 LED。松开按钮时则反之。 --- -![(Demonstration)](https://cdn-images-1.medium.com/max/2000/1*a35VFbnt_AUM0ch8ftCxMA.gif) +![(演示)](https://cdn-images-1.medium.com/max/2000/1*a35VFbnt_AUM0ch8ftCxMA.gif) -Here is the demonstration of the complete input/output circuit we have just created. For your and safety of your Raspberry Pi, I would recommend you to purchase a good case and 40 pin GPIO extension ribbon cable. - -I hope you have learned something today. In upcoming tutorials, we will build some complex circuits and learn to connect some fancy devices like character LCD screens and numeric input pad. - ---- +以上是我们刚才创建的完整输入/输出电路的演示。为了你本人和树莓派的安全,建议买一个好的外壳和 40 针 GPIO 扩展带状电缆。 -![([**GitHub**](https://github.com/thatisuday) / [**Twitter**](https://twitter.com/thatisuday))](https://cdn-images-1.medium.com/max/7898/1*waznApGKL0XENm0UbkCo_A.png) +希望你今天能学到一点东西。在接下来的教程中,我们将构建一些复杂的电路并学习连接一些有意思的设备,如字符 LCD 显示屏和数字输入板。 > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/TODO1/differentiable-plasticity.md b/TODO1/differentiable-plasticity.md index fbd596691f2..7e0e4f1b1f1 100644 --- a/TODO1/differentiable-plasticity.md +++ b/TODO1/differentiable-plasticity.md @@ -29,7 +29,7 @@ 为了展示可微可塑性的潜力,我们将其应用于一些需要从不可预知刺激中快速学习具有挑战性的任务。 -在图像重建任务中(图1)网络存储一组从未见过的自然图像;然后显示这些图像中的一张,但其中一半被擦除,并且网络必须从记忆中重建缺失的一半。我们展示了可微可塑性能有效地训练具有数百万参数的大型网络来解决这个任务。重要的是,具有非塑性连接的传统网络(包括 [LSTMs](https://en.wikipedia.org/wiki/Long_short-term_memory) 等最先进的循环结构)无法解决此任务,并且花费相当多的时间来学习它极大简化的版本。 +在图像重建任务中(图 1)网络存储一组从未见过的自然图像;然后显示这些图像中的一张,但其中一半被擦除,并且网络必须从记忆中重建缺失的一半。我们展示了可微可塑性能有效地训练具有数百万参数的大型网络来解决这个任务。重要的是,具有非塑性连接的传统网络(包括 [LSTMs](https://en.wikipedia.org/wiki/Long_short-term_memory) 等最先进的循环结构)无法解决此任务,并且花费相当多的时间来学习它极大简化的版本。 [![图像重建任务](https://eng.uber.com/wp-content/uploads/2018/04/image2.jpg)](https://www.cs.toronto.edu/~kriz/cifar.html) diff --git a/TODO1/gentle-introduction-multithreading.md b/TODO1/gentle-introduction-multithreading.md index b0a5eb04020..813ee7b9714 100644 --- a/TODO1/gentle-introduction-multithreading.md +++ b/TODO1/gentle-introduction-multithreading.md @@ -25,7 +25,7 @@ ![进程 vs 线程](https://raw.githubusercontent.com/monocasual/internalpointers-files/master/2019/02/processes-threads.png) -图1:操作系统可以被看作一个包含进程的盒子,进程又可以被看作包含一个或多个线程的盒子。 +图 1:操作系统可以被看作一个包含进程的盒子,进程又可以被看作包含一个或多个线程的盒子。 ### 进程和线程之间的区别 diff --git a/TODO1/how-to-generate-music-using-a-lstm-neural-network-in-keras.md b/TODO1/how-to-generate-music-using-a-lstm-neural-network-in-keras.md index 078a913fbe6..d5e9dbffff8 100644 --- a/TODO1/how-to-generate-music-using-a-lstm-neural-network-in-keras.md +++ b/TODO1/how-to-generate-music-using-a-lstm-neural-network-in-keras.md @@ -374,7 +374,7 @@ midi_stream.write('midi', fp='test_output.mid') 图 4:通过 LSTM 网络生成的乐谱 -这个相对较浅的网络的结果仍然令人印象深刻,从示例音乐中可以听到。对于那些感兴趣的人来说,图4中的乐谱代表了神经网络创作音乐迈出了一大步。 +这个相对较浅的网络的结果仍然令人印象深刻,从示例音乐中可以听到。对于那些感兴趣的人来说,图 4 中的乐谱代表了神经网络创作音乐迈出了一大步。 [https://w.soundcloud.com/player/?referrer=https%3A%2F%2Ftowardsdatascience.com%2Fmedia%2Fd721bab5c62c8061387ced1869dcdf5b%3FpostId%3D68786834d4c5&show_artwork=true&url=http%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F362886486](https://w.soundcloud.com/player/?referrer=https%3A%2F%2Ftowardsdatascience.com%2Fmedia%2Fd721bab5c62c8061387ced1869dcdf5b%3FpostId%3D68786834d4c5&show_artwork=true&url=http%3A%2F%2Fapi.soundcloud.com%2Fplaylists%2F362886486) diff --git a/TODO1/how-you-can-use-simple-trigonometry-to-create-better-loaders.md b/TODO1/how-you-can-use-simple-trigonometry-to-create-better-loaders.md index ec0116a0074..703a4838499 100644 --- a/TODO1/how-you-can-use-simple-trigonometry-to-create-better-loaders.md +++ b/TODO1/how-you-can-use-simple-trigonometry-to-create-better-loaders.md @@ -39,7 +39,7 @@ Nooooo! ![](https://cdn-images-1.medium.com/max/800/1*lcafSsoXqgg7mmAhB6jG9g.png) -图1:SVG 输出的非实际示意图 +图 1:SVG 输出的非实际示意图 让我们理解一下它是怎么实现的。 diff --git a/TODO1/inside-browser-part3.md b/TODO1/inside-browser-part3.md index 6379e77d4b7..26f6b13a389 100644 --- a/TODO1/inside-browser-part3.md +++ b/TODO1/inside-browser-part3.md @@ -165,7 +165,7 @@ CSS 可以使元素浮动到一侧、隐藏溢出的元素、更改书写方向 ![raster](https://developers.google.com/web/updates/images/inside-browser/part3/raster.png) -图17:光栅线程创建分块的位图并发送到 GPU +图 17:光栅线程创建分块的位图并发送到 GPU 合成线程会给不同的光栅线程设置优先级,以便视窗(或附近)内的画面可以先被光栅化。图层还具有多个不同分辨率的块,可以处理放大操作等动作。 diff --git a/TODO1/inside-look-at-modern-web-browser-part1.md b/TODO1/inside-look-at-modern-web-browser-part1.md index 2231bbc2799..faa793a46f7 100644 --- a/TODO1/inside-look-at-modern-web-browser-part1.md +++ b/TODO1/inside-look-at-modern-web-browser-part1.md @@ -106,7 +106,7 @@ 把浏览器工作分成多个进程的另一好处是安全性与沙箱化。由于操作系统提供了限制进程权限的方法,浏览器就可以用沙箱保护某些特定功能的进程。例如,Chrome 浏览器限制处理任意用户输入的进程(如渲染器进程)对任意文件的访问。 -由于进程有自己的私有内存空间,所以它们通常包含公共基础设施的拷贝(如 V8,它是 Chrome 的 JavaScript 引擎)。这意味着使用了更多的内存,如果它们是同一进程中的线程,就无法共享这些拷贝。为了节省内存,Chrome 对可加速的内存数量进行了限制。具体限制数值依设备可提供的内存与 CPU 能力而定,但是当 Chrome 运行时达到限制时,会开始在同一站点的不同标签页上运行同一进程。 +由于进程有自己的私有内存空间,所以它们通常包含公共基础设施的拷贝(如 V8,它是 Chrome 的 JavaScript 引擎)。这意味着使用了更多的内存,如果它们是同一进程中的线程,就无法共享这些拷贝。为了节省内存,Chrome 对可启动的进程数量有所限制。具体限制数值依设备可提供的内存与 CPU 能力而定,但是当 Chrome 运行时达到限制时,会开始在同一站点的不同标签页上运行同一进程。 ## 节省更多内存 —— Chrome 中的服务化 diff --git a/TODO1/interpreting-predictive-models-with-skater-unboxing-model-opacity.md b/TODO1/interpreting-predictive-models-with-skater-unboxing-model-opacity.md index 3529048c8b7..f75d8a09e61 100644 --- a/TODO1/interpreting-predictive-models-with-skater-unboxing-model-opacity.md +++ b/TODO1/interpreting-predictive-models-with-skater-unboxing-model-opacity.md @@ -64,7 +64,7 @@ 除了数据探索技术外,还可以使用[模型评估技术](https://sebastianraschka.com/blog/2016/model-evaluation-selection-part1.html)进行简单的模型解释。分析师和数据科学家可能会使用模型比较和评估方法来评估模型的准确性。例如,使用交叉验证和评估指标进行分类和回归,您可以衡量预测模型的[性能](https://www.cs.cornell.edu/courses/cs578/2003fa/performance_measures.pdf)。您可以通过优化超参数调整偏差与方差之间的平衡(请参阅文章[“了解偏差 - 方差取舍”](http://scott.fortmann-roe.com/docs/BiasVariance.html))。 -* **分类:**如 F1-scores,AUC-ROC,brier-score 等。如图3,该图显示了 AUC-ROC 如何帮助衡量流行虹膜数据集的分类模型的模型性能。ROC AUC 是一种广泛使用的指标,有助于在真阳性率(TPR)和假阳性率(FPR)之间进行平衡。它在处理偏斜类问题上也非常强大。如图 3 所示,86%的 ROC AUC( 2 类)意味着训练的分类器向正例(属于 2 类)分配较高分数的概率与负例(不属于 2 类)相比约为 86%。这种汇总的性能指标有助于阐明模型的整体性能。但是,如果分类错误,它并不能给出关于错误分类原因的详细信息 —— 为什么属于 0 类的例子被分类为 2 类,属于 2 类的例子却被分为 1 类?不能忽略的事实是,每个错误分类都可能造成不同程度的潜在业务影响。 +* **分类:**如 F1-scores,AUC-ROC,brier-score 等。如图 3,该图显示了 AUC-ROC 如何帮助衡量流行虹膜数据集的分类模型的模型性能。ROC AUC 是一种广泛使用的指标,有助于在真阳性率(TPR)和假阳性率(FPR)之间进行平衡。它在处理偏斜类问题上也非常强大。如图 3 所示,86%的 ROC AUC( 2 类)意味着训练的分类器向正例(属于 2 类)分配较高分数的概率与负例(不属于 2 类)相比约为 86%。这种汇总的性能指标有助于阐明模型的整体性能。但是,如果分类错误,它并不能给出关于错误分类原因的详细信息 —— 为什么属于 0 类的例子被分类为 2 类,属于 2 类的例子却被分为 1 类?不能忽略的事实是,每个错误分类都可能造成不同程度的潜在业务影响。 * **回归:**例如,r-square 值([决定系数](http://itfeature.com/correlation-and-regression-analysis/coefficient-of-determination)),均方误差等。 ![使用 ROC 曲线衡量模型性能](https://d3ansictanv2wj.cloudfront.net/Figure3-ed3699bfaad2cc688ba68e0c0bf1dea5.png) diff --git a/TODO1/magic-numbers-are-not-that-magic.md b/TODO1/magic-numbers-are-not-that-magic.md index 6d31a829276..b7f69d8e909 100644 --- a/TODO1/magic-numbers-are-not-that-magic.md +++ b/TODO1/magic-numbers-are-not-that-magic.md @@ -2,24 +2,24 @@ > * 原文作者:[Steven Popovich](https://medium.com/@steven.popovich) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/magic-numbers-are-not-that-magic.md](https://github.com/xitu/gold-miner/blob/master/TODO1/magic-numbers-are-not-that-magic.md) -> * 译者: -> * 校对者: +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[fltenwall](https://github.com/fltenwall)、[HumanBeingXenon](https://github.com/HumanBeingXenon) -# Magic Numbers Are Not That Magic +# 幻数并没有我们想象中的那么奇幻 > A better solution for hardcoded numbers -![Photo by [Maail](https://unsplash.com/@maail?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/feathers?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/9562/1*fzMDTQAsZ8D9O3YXJwLW5A.jpeg) +![图自 [Maail](https://unsplash.com/@maail?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 源 [Unsplash](https://unsplash.com/s/photos/feathers?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/9562/1*fzMDTQAsZ8D9O3YXJwLW5A.jpeg) -I really dislike the phrase **magic number**. I see so many people get it wrong. I have seen and had multiple code reviews where someone sees any digits in code and comments, “Oh this is a magic number, make sure you put it up top with a name.” +我真的不喜欢幻数这个词 —— 我看到太多人都理解错了。我见过这么一种代码审查,一看见代码中或者注释中有数字就评论:“哦,这是个幻数呢,请您务必给它取个名并放在代码头部”,我好多的代码里也会有这样的评论。 -(I also really dislike the fact that we feel the need to put all the variables to the top of a file, but that’s for another day.) +(我也很不喜欢有的时候我们会有应该要把所有的变量放在一个文件的顶部的想法,但这是另一个故事。) -Developers, you are allowed to use your numpad in your code. Just be careful of how you do. +亲爱的开发人员们啊,您可以在代码中大量使用纯数字,只是请务必注意自己在干什么啊。 -## What Is a Magic Number? +## 什么是幻数? -I mean, you can google it and get a bunch of lame definitions, but the bottom line is that a magic number is a number in your code that is hard to reason about. +我的意思是,您可以在 Google 上搜索它,并获得一堆如金银绸缎但却又站不住脚的定义。但实际上,幻数其实就是代码中难以理解的数字。 ```kotlin fun generate() { @@ -29,9 +29,9 @@ fun generate() { } ``` -Where does 52 come from? +这个 52 从哪来的? -Well, it turns out that this is code to generate a deck of cards because 52 is the number of cards in a deck. Let’s give the number a name. +好吧,事实证明这是生成纸牌组的代码,而 52 恰好是纸牌组中的纸牌总数。不妨让我们给数字起个名字。 ```kotlin const val numberOfCardsInADeck = 52 @@ -43,11 +43,11 @@ fun generate() { } ``` -This is code that’s more readable, more maintainable, and better. Great, you have mastered clean code. +这样,代码就会更具可读性、可维护性。太好了,您已经掌握了如何编写干净的代码的不二法门。 -No, this is just the tip of the iceberg. The thing with this example (and this is a very common example) is that a developer probably could have easily figured out what the hell 52 was from the rest of the code. This is a pretty tame magic number. +嘿嘿,不,这只是冰山一角。这个示例(这是一个非常常见的示例)告诉我们一个非常深奥的道理 —— 开发人员可能很容易地从其余的代码中明白 52 究竟是什么 —— 这是一只非常温顺的幻数怪。 -Where magic numbers really bite you is when they come from nowhere. Take this code for tuning a search algorithm: +当幻数怪突然冒出来的时候,那才是它们展示真实面孔的时间嗷。例如使用以下代码调整搜索算法: ```kotlin fun search(query: String) { @@ -55,52 +55,48 @@ fun search(query: String) { } ``` -What the heck do these numbers mean? It’s not easy to understand what these numbers are for and what they do. +噢这奇怪的数字到底意味着什么?看来想要弄清楚这些数字的用途和作用并不容易。 -## What’s the Problem With Magic Numbers? +## 为什么使用幻数是个问题? -Let’s say your app grows in size and has a bunch more things to search through, and all of a sudden your search results are not exactly yielding what you want. +假设您的应用规模不断扩大,需要搜索的内容还很多,突然之间,您的搜索结果并没有完全满足您的需求。 -We have the bug “when I search for ‘frosted flakes’, the cereal doesn’t come up in the results, even though I know it’s in there.” +我们有一个错误:"当我搜索"麦片"时,即使我知道谷物一定是它的成分,谷物也不会出现在结果中。" -So you, Joe Schmo, four years after this algorithm was originally tuned, need to change these values around to fix this bug. What do you change first? +在本算法四年前那最后一次被修改以后,我的 Joe Schmo 啊,您现在需要更改这些值以解决此错误,而您首先需要改变什么? -This is the problem with magic numbers. These numbers would have been much better off grouped together with long, descriptive names, along with in-code documentation about how changing them affects the results. - -Bonus points for explaining the algorithm, too. - -Let’s fix this: +—— 幻数。如果您将这些幻数怪与一个描述性名称或者注释文档组合在一起,那么就可以杀害幻数怪。当然,幻数怪那么可爱,杀害它们会让我们更容易理解这个算法!让我们一起来解决这个问题: ```kotlin -const val searchWeight = 2.4f // How specific your query must be. Increase this number to get more fuzzy results -const val searchSpread = 10.234f // How spread the result are. Selects more words in a row in the database -const val searchPageSize = 999 // The number of results we want per search page -const val searchMaxResults = Int.MAX_VALUE // We want every possible result from the search -const val shouldSearchIndex = false // We don't want to search indicies +const val searchWeight = 2.4f // 查询结果的具体程度,增加此数字以获得更多模糊的结果 +const val searchSpread = 10.234f // 结果的连续程度。在数据库中连续选择更多单词 +const val searchPageSize = 999 // 每个搜索页面所需的结果数 +const val searchMaxResults = Int.MAX_VALUE // 我们希望的能从搜索中获得所有可能的结果 +const val shouldSearchIndex = false // 我们不想搜索索引 fun search(query: String) { find(query, searchWeight, searchSpread, searchPageSize, searchMaxResults, shouldSearchIndex) } -// Calls our weighted search algorithim. Read the docs about this alogirthim at foo.bar.com +// 调用我们的加权搜索算法。在foo.bar.com上阅读有关此算法的文档 fun find(query: String, weight: Float, spread: Float, pageSize: Int, maxResults: Int, index: Boolean) {} ``` -Wouldn’t you feel more comfortable working on code like this? You might even have an idea of what to change to get started. Tuning search can be difficult, but someone would be much more well-equipped to tackle this bug with this documentation. +处理这样的代码,您会不会感觉舒服多了?您甚至可能对如何进行更改有所了解。优化搜索可能很困难,但是接手的人凭着这份文档,就能更好地解决这个漏洞 -## What Isn’t a Magic Number? +## 什么不能称之为幻数? -In reality, numbers that are hard to reason about don’t come up as often as numbers that are easy to reason about. Take these hardcoded numbers +实际上,难以推理的数字不会像容易推理的数字那样频繁出现。例如这个数据: ```kotlin view.height = 42 ``` -This is not a magic number. I repeat: This is not a magic number. +这可不是一个幻数,我再强调一遍:这不是一个幻数! -I know. I am giving some Java purists and clean freaks an aneurysm. +我知道。我给一些 Java 代码纯粹主义者和洁癖一个暴击。 -But this number is not hard to reason about. Its idea is entirely self-contained. The height of this view is 42**.** It just is. What value is added by giving it a name, like this? +但是这个数字并不难推论 —— 它的意义是完全独立的 —— 该视图的高度为 42!最多的翻译就是这样,但是像这样数据,即使我们给它取一个名称,又会增加什么价值? ```kotlin const val viewHeight = 42 @@ -110,19 +106,19 @@ fun buildView() { } ``` -This is just code bloat. It may seem like a small example, but this idea of needlessly naming numbers quickly puffs up the size of UI code and only serves to increase the number of lines of code. +以上做法只会导致冗杂代码。而这似乎是一个很小的例子,但是这种不必要地命名数字的想法会迅速增加 UI 代码的大小 —— 增加代码行数,完成绩效。 -## Wait, So Can I Use Numbers in My Code or Not? +## 所以我们是否可以在代码中使用数字? -Of course. There is plenty of good code in the world with numbers in it. You just need to keep in mind a few things: +这是当然的!世界上有很多不错的代码里面使用了数字。要做到不出现幻数,您只需要记住以下几点: -* Make sure your numbers are easily understandable — like, a child could figure out where the number comes from. -* If you are changing a number around, tuning something, or doing some calculation on paper to get a hardcoded number, explain it. In the code. Next to the number. Or at least in the commit. Changes of hardcoded numbers should be explained. -* Bonus: Make sure your hardcoded numbers are DRY. +* 确保您的数字易于理解 —— 就算是孩子也能指出数字是哪里来的 +* 如果您要更改数字,调整某些内容,或在纸上进行一些计算才能得到的硬编码数字,请务必进行解释。在代码中,在数字旁边,或至少在更改的提交中,应当提出并解释硬编码数字发生的变更。 +* 额外一招:请确保您的硬编码数字是干净的 -It’s not rocket science, but there is a lot of subtlety in using your number row. +相信我,使用注释解释或使用变量名解释数字是很有用的! -You’ll be fine. Thanks for reading! +祝你好运,感谢你的阅读! > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/TODO1/the-many-ways-to-include-css-in-javascript-applications.md b/TODO1/the-many-ways-to-include-css-in-javascript-applications.md index e03ab1bb0c2..165f629d743 100644 --- a/TODO1/the-many-ways-to-include-css-in-javascript-applications.md +++ b/TODO1/the-many-ways-to-include-css-in-javascript-applications.md @@ -1,55 +1,55 @@ -> * 原文地址:[The Many Ways to Include CSS in JavaScript Applications](https://css-tricks.com/the-many-ways-to-include-css-in-javascript-applications/) +> * 原文地址:[The Many Ways to Include CSS in JavaScript Applications](https://css-tricks.com/the-many-ways-to-include-css-in-javascript-applications/) > * 原文作者:[Dominic Magnifico](https://css-tricks.com/author/dominicmagnifico/) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/the-many-ways-to-include-css-in-javascript-applications.md](https://github.com/xitu/gold-miner/blob/master/TODO1/the-many-ways-to-include-css-in-javascript-applications.md) -> * 译者: -> * 校对者: +> * 译者:[逆。寒](https://github.com/thisisandy)、[lsvih](https://github.com/lsvih) +> * 校对者:[HeroXiaozheng](https://github.com/HeroXiaozheng)、[Chorer](https://github.com/Chorer) -# The Many Ways to Include CSS in JavaScript Applications +# Javascript 应用中引入 CSS 的几种方式 -![](https://res.cloudinary.com/css-tricks/image/fetch/w_1200,q_auto,f_auto/https://css-tricks.com/wp-content/uploads/2017/06/css-vs-js.png) +![](https://res.cloudinary.com/css-tricks/image/fetch/w_1200,q_auto,f_auto/https://css-tricks.com/wp-content/uploads/2017/06/css-vs-js.png) -Welcome to an incredibly controversial topic in the land of front-end development! I’m sure that a majority of you reading this have encountered your fair share of #hotdrama surrounding how [CSS should be handled within a JavaScript application](https://css-tricks.com/tag/css-in-js/). +欢迎你踏上了一条在前端世界中饱含争议的道路!相信大部分读者会在关于如何[在 JavaScript 应用中处理 CSS](https://css-tricks.com/tag/css-in-js/) 这一话题上产生共鸣。 -I want to preface this post with a disclaimer: **There is no hard and fast rule that establishes one method of handling CSS in a React, or Vue, or Angular application as superior.** Every project is different, and every method has its merits! That may seem ambiguous, but what I do know is that the development community we exist in is full of people who are continuously seeking new information, and looking to push the web forward in meaningful ways. +文章伊始,先声明一句:**无论是在基于 Vue、Angular 还是 React 构建的应用,针对如何处理 CSS,世界上并没有任何放之四海而皆准的方法。**各个项目皆有不同,每种方式也有可取之处!可能这么说显得含糊其辞,但就我所知,在我们的开发社区内,那些追寻新知识,推动网页开发向前发展的人举目皆是。 -Preconceived notions about this topic aside, let’s take a look at the fascinating world of CSS architecture! +让我们放下对本文话题的感性认知,先领会下 CSS 世界架构的奇妙之处。 -### Let us count the ways +### 让我们盘点一番引入 CSS 的方式 -Simply Googling "How to add CSS to \[insert framework here\]" yields a flurry of strongly held beliefs and opinions about how styles should be applied to a project. To try to help cut through some of the noise, let’s examine a few of the more commonly utilized methods at a high level, along with their purpose. +单单谷歌一下“如何在框架内加入 CSS”,各种言辞凿凿的关于如何在项目中应用样式的观点和看法便映入眼帘。排除一些无关紧要的信息,我们可以先宏观上挑选出更通用的方法和目的检验一番。 -#### Option 1: A dang ol’ stylesheet +#### 选项 1: 传统样式表 -We’ll start off with what is a familiar approach: a dang ol’ stylesheet. We absolutely are able to `` to an external stylesheet within our application and call it a day. +先从我们最熟悉的方式开始:老掉牙的样式表。我们自然可以在应用中 `` 一个外部样式表,活儿就完了。 ```html - + ``` -We can write normal CSS that we’re used to and move on with our lives. Nothing wrong with that at all, but as an application gets larger, and more complex, it becomes harder and harder to maintain a single stylesheet. Parsing thousands of lines of CSS that are responsible for styling your entire application becomes a pain for any developer working on the project. The cascade is also a beautiful thing, but it also becomes tough to manage in the sense that some styles you — or other devs on the project — write will introduce regressions into other parts of the application. We’ve experienced these issues before, and things like [Sass](https://sass-lang.com/) (and [PostCSS](https://github.com/postcss/postcss) more recently) have been introduced to help us handle these issues +我们可以一如往常地写熟悉的 CSS。这样做在一般情况下倒没什么问题,然而,当应用逐渐臃肿、越来越复杂时,维护一个样式表就变成了难题。上千行的 CSS 对应整个应用的样式,开发者要维护这样的样式表将痛苦不堪。样式级联看着很美好,但控制样式也同样困难,比如某个开发改动了一部分样式,会导致其它部分也因此需要跑回归测试。这些问题似曾相识,也因此 [Sass](https://sass-lang.com/)(和更新的 [PostCSS](https://github.com/postcss/postcss))悉数登出救场。 -We could continue down this path and utilize the awesome power of PostCSS to write very modular CSS partials that are strung together via `@import` rules. This requires a little bit of work within a webpack config to be properly set up, but something you can handle for sure! +顺着这个思路,我们用 PostCSS 来攥写模块化的 CSS 片段,并通过 `@import` 将这些模块组合起来。虽然这需要花点精力配置 webpack,但这对你来说不成问题! -No matter what compiler you decide to use (or not use) at the end of the day, you’ll be serving one CSS file that houses all of the styles for your application via a `` tag in the header. Depending on the complexity of that application, this file has the potential to get pretty bloated, hard to load asynchronously, and render-blocking for the rest of your application. (Sure, render-blocking isn’t **always** a bad thing, but for all intents and purposes, we’ll generalize a bit here and avoid render blocking scripts and styles wherever we can.) +无论你最终选择了哪种编译器,它们最终都会通过一个头部的 `` 标签,把所有的样式扔在一个 CSS 文件内。随着应用日益复杂,这个文件将更加臃肿,异步加载将变得缓慢,从而阻塞了应用的其余部分的渲染(当然,阻塞渲染不**总是**是件坏事,但总体来说,我们还是会尽量避免使用会阻塞渲染的样式和脚本)。 -That’s not to say that this method doesn’t have its merits. For a small application, or an application built by a team with less of a focus on the front end, a single stylesheet may be a good call. It provides clear separation between business logic and application styles, and because it’s not generated by our application, is fully within our control to ensure exactly what we write is exactly what is output. Additionally, a single CSS file is fairly easy for the browser to cache, so that returning users don’t have to re-download the entire file on their next visit. +我并不是说这种方式毫无可取之处。对于小应用来说,抑或对前端开发并不重视的团队们来讲,一张样式表足以满足需求了。它清晰地分离了业务逻辑和样式,而且它不是生成的,对开发者而言所写即所得,随心所欲。此外,浏览器也可以轻松缓存这张样式表,所以那些回头客们也就不用重新下载了。 -But let’s say that we’re looking for a bit more of a robust CSS architecture that allows us to leverage the power of tooling. Something to help us manage an application that requires a bit more of a nuanced approach. Enter CSS Modules. +而我们现在所寻找的,是一种能够完全发挥工具优势、稳健的 CSS 架构。这种架构需要能通过一种精细的方式,管理整个应用:CSS 模块化呼之欲出。 -#### Option 2: CSS Modules +#### 选项 2:CSS 模块化 -One fairly large problem within a single stylesheet is the risk of regression. Writing CSS that utilizes a fairly non-specific selector could end up altering another component in a completely different area of your application. This is where an approach called "scoped styles" comes in handy. +单张样式表一个严峻的问题是回归的风险。样式表内写一个模糊选择器样式可能会改动到另一个无关组件的样式。带作用域的样式此刻就发挥了其作用。 -Scoped styles allow us to programmatically generate class names specific to a component. Thus scoping those styles to that specific component, ensuring that their class names will be unique. This leads to auto-generated class names like `header__2lexd`. The bit at the end is a hashed selector that is unique, so even if you had another component named header, you could apply a header class to it, and our scoped styles would generate a new hashed suffix like so: `header__15qy_`. +带作用域的样式可以程序化的生成对应组件的明确类名,以确保它们的类名唯一。自动生成的类名例如 `header__2lexd`,后面那小部分是选择器唯一的哈希值。当一个组件叫 header 时,你可以给它的类名取名为 header,程序将自动生成类似 `header__15qy_` 的新哈希后缀。 -CSS Modules offer ways, depending on implementation, to control the generated class name, but I’ll leave that up to [the CSS Modules documentation](https://github.com/css-modules/css-modules/tree/master/docs) to cover that. +基于不同的实现方式,CSS 模块生成类名的方式不尽相同,这部分我就不赘述了,请参考 [CSS 模块化文档](https://github.com/css-modules/css-modules/tree/master/docs)。 -**Once all is said and done, we are still generating a single CSS file that is delivered to the browser via a `` tag in the header.** This comes with the same potential drawbacks (render blocking, file size bloat, etc.) and some of the benefits (caching, mostly) that we covered above. But this method, because of its purpose of scoping styles, comes with another caveat: the removal of the global scope — at least initially. +**到头来,在浏览器内我们仍然是用头部的 `` 标签来加载使用生成的单个 CSS 文件。**伴随而来的有潜在问题(诸如阻塞渲染、文件大小膨胀等),和上文提到的些许好处(缓存是主要优势)。一个需要注意的点是:这种方法移除了全局作用域 —— 起码一开始没有,而这正是其样式作用域所致。 -Imagine you want to employ the use of a `.screen-reader-text` global class that can be applied to any component within your application. If using CSS Modules, you’d have to reach for the `:global` pseudo selector that explicitly defines the CSS within it as something that is allowed to be globally accessed by other components in the app. As long as you import the stylesheet that includes your `:global` declaration block into your component’s stylesheet, you’ll have the use of that global selector. Not a huge drawback, but something that takes getting used to. +比如在一个应用内,你想将一个全局的类名 `.screen-reader-text` 应用在任何一个组件上,当你使用 CSS 模块化时,你得在 `:global` 伪选择器内定义样式,才能使得这个类样式能被其它组件引用到;接着你需要把这个带有全局选择器的文件导入到各个组件的样式表内,才能生效。这样做虽然不算麻烦,但还是得花点力气习惯这种做法。 -Here’s an example of the `:global` pseudo selector in action: +这是一个使用 `:global` 伪选择器的范例: ```css // typography.css @@ -66,7 +66,7 @@ Here’s an example of the `:global` pseudo selector in action: } ``` -You may run the risk of dropping a whole bunch of global selectors for typography, forms, and just general elements that most sites have into one single `:global` selector. Luckily, through the magic of things like [PostCSS Nested](https://github.com/postcss/postcss-nested) or Sass, you can import partials directly into the selector to make things a bit more clean: +你可能得冒险把一大摞的字体、表格和大部分页面都有的通用元素样式扔进这一个 `:global` 选择器。幸好 [PostCSS Nested](https://github.com/postcss/postcss-nested) 或者 Sass 可以帮你导入样式表,让代码看着更加清爽。 ```scss // main.scss @@ -76,9 +76,9 @@ You may run the risk of dropping a whole bunch of global selectors for typograph } ``` -This way, you can write your partials without the `:global` selector, and just import them directly into your main stylesheet. +像这样,把部分样式抽离出来,不再需要用 `:global` 伪选择器包装,只需要在主样式表中导入即可。 -Another bit that takes some getting used to is how class names are referenced within DOM nodes. I’ll let the individual docs for [Vue](https://vue-loader.vuejs.org/guide/css-modules.html#usage), [React](https://github.com/css-modules/css-modules/blob/master/docs/css-modules-with-react.md), and [Angular](https://github.com/css-modules/css-modules/blob/master/docs/css-modules-with-angular.js.md) speak for themselves there. I’ll also leave you with a little example of what those class references look like utilized within a React component: +还有一点需要适应的是,在 DOM 节点中引用类名的方式。这点 [Vue](https://vue-loader.vuejs.org/guide/css-modules.html#usage)、[React](https://github.com/css-modules/css-modules/blob/master/docs/css-modules-with-react.md) 和 [Angular](https://github.com/css-modules/css-modules/blob/master/docs/css-modules-with-angular.js.md) 在它们的文档中都有说明。我这里也有一些例子,可以说明在 React 组件内,这些类是如何被引用的。 ```javascript // ./css/Button.css @@ -109,38 +109,38 @@ const Button = () => ( export default Button; ``` -The CSS Modules method, again, has some great use cases. For applications looking to take advantage of scoped styles while maintaining the performance benefits of a static, but compiled stylesheet, then CSS Modules may be the right fit for you! +CSS 模块化有诸多精彩的用例。如果你在寻找一种带作用域的样式,又希望保留静态样式的优势,那么 CSS 模块化正适合你。 -It’s worth noting here as well that CSS Modules can be combined with your favorite flavor of CSS preprocessing. Sass, Less, PostCSS, etc. are all able to be integrated into the build process utilizing CSS Modules. +同样值得注意的是,CSS 模块化可以和你喜爱的 CSS 预处理器相结合。通过 CSS 模块化,诸如 Sass、Less、PostCSS 等 CSS 预处理工具与插件都可以结合进项目构建过程中。 -But let’s say your application could benefit from being included within your JavaScript. Perhaps gaining access to the various states of your components, and reacting based off of the changing state, would be beneficial as well. Let’s say you want to easily incorporate critical CSS into your application as well! Enter CSS-in-JS. +但是,假如你的应用程序是基于 JavaScript 开发的,那么如果 CSS 样式也可以访问组件的各种状态,并根据状态的变化做出反应,也会是不错的路子。假设你希望轻松地将关键 CSS 加入到应用程序中,有请 CSS-in-JS! -#### Option 3: CSS-in-JS +#### 选项 3:CSS-in-JS -CSS-in-JS is a fairly broad topic. There are several packages that work to make writing CSS-in-JS as painless as possible. Frameworks like [JSS](https://cssinjs.org/?v=v10.0.0-alpha.16), [Emotion](https://emotion.sh/docs/introduction), and [Styled Components](https://www.styled-components.com/) are just a few of the many packages that comprise this topic. +CSS-in-JS 这个话题颇为宽泛。也有一些库致力于轻松书写 CSS-in-JS。像 [JSS](https://cssinjs.org/?v=v10.0.0-alpha.16)、[Emotion](https://emotion.sh/docs/introduction) 和 [Styled Components](https://www.styled-components.com/) 这类框架扛起了 CSS-in-JS 的大旗。 -As a broad strokes explanation for most of these frameworks, CSS-in-JS is largely operates the same way. You write CSS associated with your individual component and your build process compiles the application. When this happens, most CSS-in-JS frameworks will output the associated CSS of **only the components that are rendered on the page at any given time**. CSS-in-JS frameworks do this by outputting that CSS within a ` +

Styled paragraph!

+``` + + + +在 React 中,必须扩展组件类,然后获得渲染并返回,在项目文件中得到一个构造函数以及其它要处理的内容。Vue 更好一点,但仍然存在所有这些必须直观的东西。Svelte 完全是直观的,如果已经了解 HTML,那么它的代码行就更少了,显然很容易使用。 + +## 结论 + +以上就是本文主要介绍使用 Svelte 开发前端应用的五个理由。未来它会变得越来越流行,将被更多地开发团队采用。Svelte 是一个很棒的编译器框架,非常有用。 + +可以使用下面的链接来练习并更好地了解 Svelte。 + +[Svelte 示例](https://svelte.dev/examples#hello-world) + +感谢阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/5-tips-for-better-typescript-code.md b/article/2020/5-tips-for-better-typescript-code.md new file mode 100644 index 00000000000..b42fd1dd2ff --- /dev/null +++ b/article/2020/5-tips-for-better-typescript-code.md @@ -0,0 +1,142 @@ +> * 原文地址:[5 Tips for Better TypeScript Code](https://levelup.gitconnected.com/5-tips-for-better-typescript-code-5603c26206ef) +> * 原文作者:[Anthony Oleinik](https://medium.com/@anth-oleinik) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/5-tips-for-better-typescript-code.md](https://github.com/xitu/gold-miner/blob/master/article/2020/5-tips-for-better-typescript-code.md) +> * 译者:[Zavier](https://github.com/zaviertang) +> * 校对者:[regonCao](https://github.com/regon-cao)、[niayyy](https://github.com/nia3y) + +# TypeScript 的 5 个建议 + +![5 Tips for Better TypeScript](https://cdn-images-1.medium.com/max/2000/1*VGWjFbzekvE7WD3e5fGQHQ.png) + +原生的 JavaScript 存在不少的问题,TypeScript 对此也有许多解决方案,其中一些需要我们稍微挖掘以一下才能发现。 + +在我刚开始学习前端的时候,我了解到 TypeScript 是用来解决 JavaScript 存在的各种问题的。比如:传递错误的参数、杂乱的类型互换、访问空值等日常开发经常遇到的问题。 + +使用 TypeScript 让我的开发效率大大提高。同时,我也一直在学习和研究 TypeScript 的细节,这里和大家分享我所学到的一些内容。 + +## 1. 空值合并运算符 + +有时,在访问属性时 TypeScript 会自动帮你插入可选链操作符。类似 `let t = myObj?.property `,这样的话变量 `t` 将被赋值为 `property` 或 `undefined`。这样做非常棒,但重要的是我们要确切地知道这里发生了什么,这样你就可以得心应手的使用它,而不只是把它当作是 TypeScript 自动完成的功能。 + +如果我们使用常规的方式访问属性,像这样:`myObj.property`,如果 `myObj` 是`undefined`,将会报错:“Cannot access property 'property' of undefined”。这显然不是我们预期的,所以使用 `?.` 意思是如果 `myObj` 是 `undefined`,我们就停止访问属性并把 `t` 赋值为 `undefined`。 + +这对于避免错误是非常有用,但有时我们需要一个默认的值。例如,如果我们有一个用户从未访问的文本域,这样内部的值是 `undefined`,该怎么办?我们预期不是传送 `undefined` 给后端。我们可以使用**可选链操作符**(我们刚刚提及的 `?.` )配合**空值合并运算符**。如下: + +```ts +sendFieldToServer(textField?.text ?? '') +``` + +这是非常优雅的方式,可以很安全地处理很多边界情况。也就是说,它保证了 `undefined` 不可能传递给函数,TypeScript 会将一个字符串传递给 `sendFieldToServer` 函数。 + +这是因为当左边的值是 `undefined` 时空值合并运算符会将右边的值传递给函数,也就是一个空字符串。 + +在 JavaScript 中,很容易忽略代码中所有可能是 `undefined` 的地方。幸运的是,TS 会帮我们发现错误,并警告你 `sendFieldToServer` 不能接受 `undefined` 作为参数。同时我们使用可选链操作符和空值合并运算符来保证代码的严谨性。 + +## 2. 不要使用默认导出 + +TypeScript 优于 JavaScript 的一个原因是代码的自动补全能力。因为在 TypeScript 中,编辑器能够确切地知道你正在访问的对象以及哪些属性是可以访问的。比如你有一个 `dog` 对象,编辑器将提示你可以访问它的 `bark` 方法。 + +也就是说,如果 `dog` 在作用域内。 + +如果我们在 `dog.ts` 中默认导出 `Dog`,如下: + +```ts +default export interface Dog { + bark: () => void, +} +``` + +然后,我们导入时可以给它任意命名。比如可以从其他文件中导入 dog 命名为 cat,如下: + +```ts +import cat from 'dog.ts' + +cat.bark() +``` + +这是正确的 TypeScript 代码。这意味着如果我们这样: + +```ts +let t: dog = { + bark: () => console.log('woof!') +} +``` + +TypeScript 不知道 `dog` 是什么。在 `dog` 下面会有一条红线表示 `dog` 没有定义。你需要找到定义 `dog` 的位置,然后手动导入,并确保将其命名为 `dog`。 + +这就是默认导出的后果。导出 `dog` 要像下面这样: + +```ts +export interface dog {..} //export without 'default' +``` + +这意味着现在,在我们的另一个文件中,当我们键入 `let t: dog` 时,TypeScript 知道去哪寻找一个叫做 `dog` 的接口。编辑器将自动为你导入,TypeScript 也能够知道你可以访问 `bark` 方法。 + +代码补全是一个很好的特性。我发现没有理由选择默认的导出方式,因为常规导出实际上更有用。即使你只需导出一个,常规导出仍然可以轻松地处理。 + +eslint 有一个 `no default export` 规则,它可以发现任何的默认导出。 + +## 3. 限制字符串的可选值 + +枚举算是编程语言中非常棒的能力了,当 JavaScript 决定不包含枚举时,可以说它的优越性大大下降。 + +虽然 TypeScript 本身就有枚举类型,但你并不是一定需要使用它们。定义枚举类型也要一定的开销。TypeScript 还有更好的方式。 + +```ts +t: "left" | "right" | "middle" = "middle" +``` + +这样做也算是枚举。这里,你只能给 `t` 赋值给限定的这 3 个值。这里我们在一行代码中定义了它,TypeScript 会限制不能给 `t` 赋值其他任何值。如果我们尝试 `t="center"`, TypeScript 会报错。我们可以 100% 确定 `t` 的值是这三个值中的一个,所以当我们在访问 `t` 时,可以推断 `t` 的值是什么。 + +同时,`t` 仍然是一个普通的字符串。我们可以正常的将它和其他字符串拼接,显示到界面上。 + +## 4. 使用 Map\ + +JavaScript 的一个优点是它有一个灵活的原型机制。你可以在任何对象上添加任何属性。`myObj.nonExistantField = "Is This" + 12312 + "A string or a number? Who Cares!" * 4`,但是,我们忽略了一些,比如: + +1. 原型访问相对较慢; +2. 不容易遍历(你需要使用 `Object.keys(myOjb)` 或其他方式); +3. 如果每个程序员只是直接向对象中添加属性,将很难处理; +4. 可能存在未定义的属性。 + +你也可以在 TypeScript 中做同样类似的事情,比如允许值的类型为 any,但不推荐这么做。 + +反而,我们可以使用 `Map`。它也存在于原生 JS 中,但在 JS 中它没有类型限制,所以它没有那么有用。如下: + +```ts +let myMap: Map = new Map() +``` + +这将创建一个映射,可以解决我提到的基于原型的 key-value 映射所存在的问题。 + +1. 它访问非常快:HashMap 只需要 O(1) 的时间复杂度,添加也是; +2. 使用 `map.forEach()`,可以很方便地进行遍历; +3. 只要键和值的类型正确,你可以将任何内容放入其中; +4. 可以避免 undefined(只要限制类型不包括 undefined 即可)。 + +Map 很有用,在面试中它也是最常被问及的数据结构的问题。在我看来,它们比基于原型的映射要好得多。如果你试图允许随意定义对象的键,那么可能使用了错误的数据结构。 + +## 5. 配置 eslint config / tsconfig + +一般来说,使用 eslint 或 tsconfig 配置代码格式是很有必要的。例如,我之前使用的是 python,我比较喜欢行末无分号的风格。我进行了 eslint 的相关配置,所以当我不小心输入了分号时,编辑器将会立刻警告我。 + +在我看来,保持双引号的一致性可以让代码看起来更漂亮,所以我也在 eslint 中添加了双引号的配置。 + +我是模式匹配的超级粉丝,因此我在我的 tsconfig 配置它为强制的。 + +我更喜欢 no-default-export,所以我也把它设置为强制的。 + +我强烈地建议你花些时间来检查一下 `.tsconfig` 或者 `.eslintrc` 中所有的配置,并进行个性化地设置。然后,将这些文件备份,当你开始一个新项目时,就可以轻松地粘贴到那里。 + +有时,当我看到我的代码都保持着统一的风格时,我会感到非常的欣慰。同时还有另一个好处,就是当有其他人参与到这个项目时,他也要遵循在 `.tsconfig` 和 `.eslintrc` 约定的规则,这样我们就可以保证整个项目代码风格的一致性。 + +--- + +好了!这就是我对 TypeScript 编码的 5 个建议。同时我也一直在寻找更多的建议,所以如果你有任何你认为值得关注的点,可以给我留言! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/5-types-of-arguments-in-python-function-definition.md b/article/2020/5-types-of-arguments-in-python-function-definition.md new file mode 100644 index 00000000000..2b7fef190dd --- /dev/null +++ b/article/2020/5-types-of-arguments-in-python-function-definition.md @@ -0,0 +1,364 @@ +> * 原文地址:[5 Types of Arguments in Python Function Definition](https://levelup.gitconnected.com/5-types-of-arguments-in-python-function-definition-e0e2a2cafd29) +> * 原文作者:[Indhumathy Chelliah](https://medium.com/@IndhumathyChelliah) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/5-types-of-arguments-in-python-function-definition.md](https://github.com/xitu/gold-miner/blob/master/article/2020/5-types-of-arguments-in-python-function-definition.md) +> * 译者:[Zhengjian-L](https://github.com/Zhengjian-L) +> * 校对者:[z0gSh1u](https://github.com/z0gSh1u),[JalanJiang](https://github.com/JalanJiang) + +# 定义 Python 函数时的 5 种参数 + +![Photo by [Sharon McCutcheon](https://www.pexels.com/@mccutcheon?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels) from [Pexels](https://www.pexels.com/photo/person-s-hand-with-paints-1174932/?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels)](https://cdn-images-1.medium.com/max/11232/1*TqNYpk6OZ6qBS8CNPWz1tQ.jpeg) + +#### Python 定义函数的5种参数: + +1. `缺省参数` +2. `关键字参数` +3. `位置参数` +4. `任意位置参数` +5. `任意关键字参数` + +#### Python 函数定义: + +关键字 `def` 引入一个函数定义。它后面必须跟着函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。 + +![](https://cdn-images-1.medium.com/max/2000/1*DhAUznkbAFfBUvMqF8rFuw.png) + +在定义的函数中需要提及**形式参数**。**实际参数**在函数调用时传递。 + +我们可以用各种参数来定义函数。 + +#### 1. 缺省参数: + +* 缺省参数是在定义函数时提供的值。 +* 赋值符号`=`用于声明参数的默认值。 +* 在调用函数时,参数默认值是可变更项。 +* 如果在调用函数时提供缺省参数的值,这个值会替代默认值。 +* 一个函数可以有任意数量的缺省参数。 +* 缺省参数要在非缺省参数之后。 + +**例:** + +`b`,`c`在下面的例子中,参数`b`,`c`指定了默认值。 + +```py +def add(a,b=5,c=10): + return (a+b+c) +``` + +这个函数有三种调用方式 + +**1. 只给出必需参数** + +```py +print(add(3)) +#Output:18 +``` + +**2. 给出一个可选的参数** +3 赋值给 a, 4 赋值给 b。 + +```py +print(add(3,4)) +#Output:14 +``` + +**3.给出所有参数** + +```py +print(add(2,3,4)) +#Output:9 +``` + +**注意:** 默认值在函数定义处的定义过程中只会计算一次。因此,在把如列表、字典等可变对象作为默认值时会有些许不同。 + +#### 2. 关键字参数: + +也可以使用形如`kwarg=value`的关键字参数来调用函数。 + +在调用函数时,参数值并不需要与函数定义中的参数顺序相同。这可以通过关键字参数实现。但所有的关键字参数必须与函数定义中的参数一一对应。 + +**例:** + +```py +def add(a,b=5,c=10): + return (a+b+c) +``` + +调用函数 `function add` 时提供关键字参数 + +1. 所有的参数都是关键字参数,因此不需要固定顺序。 + +```py +print (add(b=10,c=15,a=20)) +#Output:45 +``` + +2. 调用函数时,只给出必要参数作为关键字参数,可选缺省参数就会跳过。 + +```py +print (add(a=10)) +#Output:25 +``` + +#### 3. 位置参数 + +调用函数时,参数传递的值的顺序和形式参数的顺序需要对应。这称之为**位置参数**。 + +位置参数之后只能是关键字参数。 + +**例:** + +```py +def add(a,b,c): + return (a+b+c) +``` + +上面的函数有两种调用的方式: + +1. 调用函数时,参数均为位置参数。参数传递的值会通过位置传递到对应参数。`10` 赋值给` a`,`20`赋值给` b` 和 `30` 赋值给 `c`。 + +```py +print (add(10,20,30)) +#Output:60 +``` + +2. 在混合使用位置参数和关键字参数时,关键字参数总是在位置参数之后。 + +```py +print (add(10,c=30,b=20)) +#Output:60 +``` + +**缺省参数、位置参数 、关键字参数三者对比:** + +![](https://cdn-images-1.medium.com/max/2000/1*fobgfbPcgmE29Oviud5vWw.png) + +--- + +**关键要点:** + +**1. 缺省参数需要在非缺省参数之后** + +```py +def add(a=5,b,c): + return (a+b+c) + +#Output:SyntaxError: non-default argument follows default argument +``` + +**2. 关键字参数需要在位置参数之后** + +```py +def add(a,b,c): + return (a+b+c) + +print (add(a=10,3,4)) +#Output:SyntaxError: positional argument follows keyword argument +``` + +**3. 所有传递的关键字参数必须有对应参数,并且顺序不重要。** + +```py +def add(a,b,c): + return (a+b+c) + +print (add(a=10,b1=5,c=12)) +#Output:TypeError: add() got an unexpected keyword argument 'b1' +``` + +**4. 参数只能赋值一次** + +```py +def add(a,b,c): + return (a+b+c) + +print (add(a=10,b=5,b=10,c=12)) +#Output:SyntaxError: keyword argument repeated +``` + +**5. 缺省参数是可选参数** + +**例 1:** 只给必要参数 + +```py +def add(a,b=5,c=10): + return (a+b+c) + +print (add(2)) +#Output:17 +``` + +**例 2:** 给出所有参数(必要参数和可选参数) + +```py +def add(a,b=5,c=10): + return (a+b+c) + +print (add(2,3,4)) +#Output:9 +``` + +#### 可变长度参数 + +可变长度参数也称为**任意参数**。如果我们事先不知道函数的参数数量,可以使用任意参数。 + +**两种任意参数** + +1. 任意位置参数 +2. 任意关键字参数 + +#### 4. 任意位置参数: + +对于任意位置参数,函数定义的参数前会有一个**星号(`*`)**,该参数可以包含非关键字可变长度参数。这些参数将包含在一个**元组**中。在可变数量的参数之前,可能会出现零个或多个普通参数。 + +```py +def add(*b): + result=0 + for i in b: + result=result+i + return result + +print (add(1,2,3,4,5)) +#Output:15 + +print (add(10,20)) +#Output:30 +``` + +#### 5.任意关键字参数: + +对于任意关键字参数,函数定义的参数前会有**双星号(`*`)**,该参数可以包含非关键字可变长度参数。 + +**例:** + +```py +def fn(**a): + for i in a.items(): + print (i) +fn(numbers=5,colors="blue",fruits="apple") +''' +Output: +('numbers', 5) +('colors', 'blue') +('fruits', 'apple') +''' +``` + +#### 特殊参数: + +根据 [Python 手册](https://docs.python.org/3/tutorial/controlflow.html#special-parameters) + +> 默认情况下,函数的参数传递形式可以是位置参数或是显式的关键字参数。 为了确保可读性和运行效率,限制允许的参数传递形式是有意义的,这样开发者只需查看函数定义即可确定参数项是仅按位置、按位置也按关键字,还是仅按关键字传递。 + +函数的定义看起来可以像是这样: + +![Photo by author](https://cdn-images-1.medium.com/max/2000/1*u2CocaIDBg1ctQBeP_-H6A.png) + +在这里` /` 和 `*` 是可选的。 如果使用这些符号则表明可以通过何种形参将参数值传递给函数:仅限位置、位置或关键字,以及仅限关键字。 + +1. 位置或关键字参数 +2. 仅限位置参数 +3. 仅限关键字参数 + +#### 1. 位置或关键字参数 + +如果函数定义中未使用 `/` 和 `*`,则参数可以按位置或按关键字传递给函数。 + +```py +def add(a,b,c): + return a+b+c + +print (add(3,4,5)) +#Output:12 + +print (add(3,c=1,b=2)) +#Output:6 +``` + +**2. 仅限位置参数** + +在定义的函数中,仅限位置参数要放在`/`(正斜杠)之前。这个`/`被用来从逻辑上分隔仅限位置形参和其他形参。在`/`之后的形参可以为**位置或关键字**或者**仅限关键字**。 + +```py +def add(a,b,/,c,d): + return a+b+c+d + +print (add(3,4,5,6)) +#Output:18 + +print (add(3,4,c=1,d=2)) +#Output:10 +``` + +如果将关键字参数规定为仅限位置参数,则会导致**TypeError**。 + +```py +def add(a,b,/,c,d): + return a+b+c+d + +print (add(3,b=4,c=1,d=2)) +#Output:TypeError: add() got some positional-only arguments passed as keyword arguments: 'b' +``` + +#### 3. 仅限关键字参数 + +要将形参标记为**仅限关键字**,应在参数列表的第一个**仅限关键字**形参前放置一个 `*`。 + +```py +def add(a,b,*,c,d): + return a+b+c+d + +print (add(3,4,c=1,d=2)) +#Output:10 +``` + +如果将位置参数规定为仅限关键字参数,则会导致**TypeError**。 + +```py +def add(a,b,*,c,d): + return a+b+c+d + +print (add(3,4,1,d=2)) +#Output:TypeError: add() takes 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given +``` + +**在同一个函数中的拥有三种参数的调用规则** + +在下面的例子中,`function add` 拥有所有三种参数 + +`a`,`b` — 仅限位置参数 +`c` - 位置或关键字参数 +`d` - 仅限关键字参数 + +```py +def add(a,b,/,c,*,d): + return a+b+c+d + +print (add(3,4,1,d=2)) +#Output:10 +``` + +**注意事项:** + +1. 当你希望参数的名称对用户不可用时,则使用**仅限位置**。当参数名称没有实际意义时,这很有用。 +2. 如果你想规定调用函数的参数数据时,则使用**仅限位置**。 +3. 当名称有意义且定义的函数通过名称变得更易于理解时,则使用**仅限关键字**。 +4. 当你想要避免用户依赖传递的参数的位置时,则使用**仅限关键字**。 + +#### 资料来源(Python手册): + +[定义函数](https://docs.python.org/3/tutorial/controlflow.html#defining-functions) + +[默认参数](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values) + +[关键字参数](https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments) + +[特殊参数](https://docs.python.org/3/tutorial/controlflow.html#special-parameters) + +[任意参数列表](https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/5-useful-things-the-spread-operator-can-do-in-javascript.md b/article/2020/5-useful-things-the-spread-operator-can-do-in-javascript.md new file mode 100644 index 00000000000..e0dceaa5509 --- /dev/null +++ b/article/2020/5-useful-things-the-spread-operator-can-do-in-javascript.md @@ -0,0 +1,100 @@ +> * 原文地址:[5 Useful Things The Spread Operator Can Do in JavaScript](https://medium.com/javascript-in-plain-english/5-useful-things-the-spread-operator-can-do-in-javascript-f0306358bc9c) +> * 原文作者:[Mehdi Aoussiad](https://medium.com/@mehdiouss315) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/5-useful-things-the-spread-operator-can-do-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/article/2020/5-useful-things-the-spread-operator-can-do-in-javascript.md) +> * 译者:[Alfxjx](https://github.com/Alfxjx) +> * 校对者:[HayleyLL](https://github.com/HayleyLL) + +# 对象展开运算符在 JavaScript 中的 5 大应用 + +![Image Created with ❤️️ By Mehdi Aoussiad.](https://cdn-images-1.medium.com/max/3980/1*IhLMLpHPrIWgtsBuh5Tueg.jpeg) + +## 简介 + +对象展开运算符是最近 JavaScript 添加的一个很重要也很有用的新功能。对象展开运算符能够将一个可迭代的 JavaScript 的对象的值进行展开与扩展,它也可以在需要多重参数的时候让我们能够把数组和其他的表达式进行扩展。在多种情况下,对象展开运算符对于以简单的方式编写更好且干净的JavaScript代码非常有用。 + +在这篇简短的文章中,我们将探讨JavaScript中对象展开运算符`** {…} **`的一些用例。 + +## 1. 合并两个对象 + +我们可以在 JavaScript 中使用对象展开运算符来合并两个对象,看一看下面这个例子: + +```JavaScript +let employee = { name:'Jhon',lastname:'Doe'}; +const salary = { grade: 'A', basic: '$3000' }; +const summary = {...employee, ...salary}; +console.log(summary); +// Prints: {name: "Jhon", lastname: "Doe", grade: "A", basic: "$3000"} +``` + +这里的 `**employee**` 和 `**salary**` 对象被合并成了一个,并生成了一个包含了原来两个对象的键值对的新对象。 + +## 2. 合并数组 + +对象展开运算符的另一个优点是可以合并数组,或在一个数组的任意索引处插入另一个数组的所有元素。 + +对象展开的语法使得下面的操作变得异常的简单: + +```JavaScript +let thisArray = ['sage', 'rosemary', 'parsley', 'thyme']; + +let thatArray = ['basil', 'cilantro', ...thisArray, 'coriander']; +// thatArray now equals ['basil', 'cilantro', 'sage', 'rosemary', 'parsley', 'thyme', 'coriander'] +``` + +通过使用对象展开运算符 `**{…}**` ,我们就能很容易的得到想要的数组。如果使用传统的方法,那么步骤将会变得更加的冗长与复杂。 + +## 3. 使用对象展开运算符复制数组 + +我们也可以使用对象展开运算符在 JavaScript 中将一个数组的内容复制到另外一个数组中。看一看下面的这个例子: + +```JavaScript +const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY']; +let arr2; +arr2 = [...arr1]; +console.log(arr2); // Prints:[ 'JAN', 'FEB', 'MAR', 'APR', 'MAY' ] +``` + +如你所见,我们使用对象展开运算符将 `**arr1**` 的全部元素都复制到了另外的一个数组 `**arr2**` 中。 + +## 4. 计算数组中的最大值 + +下面的一段 ES5 代码使用 `**apply()**` 来计算得到了数组中的最大值: + +```JavaScript +var arr = [6, 89, 3, 45]; +var maximus = Math.max.apply(null, arr); // returns 89 +``` + +使用对象展开运算符让这一段代码更易读且更容易维护。看一下下面这个例子: + +```JavaScript +const arr = [6, 89, 3, 45]; +const maximus = Math.max(...arr); // returns 89 +``` + +`**...arr**` 返回了一个数组元素的集合,也就是说它**展开**了这个数组。 + +## 5. 将字符串转换成数组 + +我们可以使用对象展开运算符在 JavScript 中将一个英文单词(字符串)分割成数组,下面的例子展示了它是如何将一个英文单词转化成字母组成的数组的: + +```JavaScript +const string = 'word'; +const arr = [...string]; +console.log(arr); // Prints: ["w", "o", "r", "d"] +``` + +有很多方法来实现这个功能,但是使用对象展开运算符,更容易写出干净的 JavaScript 代码。 + +## 结论 + +对象展开运算符是 JavaScript 中一种很有用的功能。它使用起来很方便,并且能够保持代码的整洁度,便于维护。 + +感谢阅读这篇文章,希望对您有所帮助。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/6-things-to-know-to-get-started-with-python-data-classes.md b/article/2020/6-things-to-know-to-get-started-with-python-data-classes.md new file mode 100644 index 00000000000..2e9e5f61eae --- /dev/null +++ b/article/2020/6-things-to-know-to-get-started-with-python-data-classes.md @@ -0,0 +1,252 @@ +> * 原文地址:[6 Things to Know to Get Started With Python Data Classes](https://medium.com/better-programming/6-things-to-know-to-get-started-with-python-data-classes-c795bf7e0a74) +> * 原文作者:[Yong Cui, Ph.D.](https://medium.com/@yong.cui01) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/6-things-to-know-to-get-started-with-python-data-classes.md](https://github.com/xitu/gold-miner/blob/master/article/2020/6-things-to-know-to-get-started-with-python-data-classes.md) +> * 译者:[JalanJiang](http://jalan.space/) +> * 校对者:[jiapengwen](https://github.com/jiapengwen),[chzh9311](https://github.com/chzh9311) + +# 上手 Python 数据类前需要知道的 6 件事 + +![图源 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral),摄影者 [Philipp Katzenberger](https://unsplash.com/@fantasyflip?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/12000/0*p3gDT4yY_Ej-8fyA) + +在任何程序项目中,数据都是最重要的元素。所有的程序都必然会与数据进行某些互动。例如,你的项目是一个 Web 站点,你就需要以一个用户友好的方式展现数据(文本或图片)。如果你的项目使用机器学习来预测经济趋势,你就需要用模型可以学习的方式来准备数据。 + +作为一个多用途的编程语言,Python 已发展出多种工具,以便于支持你项目中的数据管理。在这些工具中,数据类是一种有用且易于掌握的技术。在这篇文章中,我想向你介绍数据类模型,并突出重点,让你能够上手这一数据管理工具。 + +## 1. 定义一个数据类 + +Python 的标准库 `dataclasses` 模块定义了数据与类关联的功能。这个模块最重要的元素是 `dataclass` 装饰器。下面的代码向你展示了如何使用 `dataclass` 装饰器来定义一个用于管理餐厅账单的自定义类。 + +```Python +from dataclasses import dataclass + + +@dataclass +class Bill: + table_number: int + meal_amount: float + served_by: str + tip_amount: float = 0.0 +``` + +具体而言,我们使用 `dataclass` 装饰器装饰了自定义类。在被定义的类中,我们指定了类的属性(数据类的术语)。 + +你可能会问,为什么我们要如此麻烦地使用 `dataclass` 装饰器?这是因为 `dataclass` 装饰器可以帮助我们摆脱一些样板代码,例如 `__init__` 和 `__repr__`。换句话说,在我们的自定义类上使用该装饰器,我们就不再需要实现这些函数 —— 取而代之的是,装饰器会帮助我们实现它们,就像下面这样。 + +```Python +>>> bill0 = Bill(table_number=5, meal_amount=50.5, served_by="John", tip_amount=7.5) +>>> print(f"Today's first bill: {bill0!r}") +Today's first bill: Bill(table_number=5, meal_amount=50.5, served_by='John', tip_amount=7.5) +``` + +就像上面展示的那样,无需明确定义构造与展示方法,两种方法都按惯例被实现了。是不是很酷? + +## 2. 类型注释与默认字段值 + +在上面所展示的数据类中,所有字段都拥有类型注释,清晰地表明了它们的类型。毕竟数据类主要用于数据处理,我们明确地标出数据类所包含的数据类型是有意义的。 + +请容我机械地重复一遍,数据类的字段必须有类型注释。否则,我们的代码将无法执行。`dataclass` 装饰器在幕后根据类中的注释生成字段,这些字段可以使用 `__annotations__` 特殊方法进行检索。 + +```Python +>>> Bill.__annotations__ +{'table_number': , 'meal_amount': , 'served_by': , 'tip_amount': } +``` + +另一件值得注意的事情是,你在数据类中定义的字段可以拥有默认值。你可能注意到了,`tip_amount` 字段的默认值是 0.0。需要重点关注的是,当你没有为所有字段指定默认值时,有默认值的字段应当放在在没有默认值的字段之后。你必然不想看到以下错误。 + +```Python +@dataclass +... class SpecialBill: +... table_number: int = 888 +... meal_amount: float +... served_by: str +... tip_amount: float = 0.0 +... +Traceback (most recent call last): + ...some traceback info omitted +TypeError: non-default argument 'meal_amount' follows default argument +``` + +## 3. 相等/不相等的比较 + +除了构造与展示方法,`dataclass` 装饰器还为我们实现了与比较相关的功能。我们知道,对自定义类而言,如果没有定义用于比较的方法,我们不能在实例之间进行有意义的比较。思考以下没有使用 `dataclass` 装饰器的自定义类。 + +```Python +>>> old_bill0 = OldBill(table_number=3, meal_amount=20.5, served_by="Dan", tip_amount=5) +... old_bill1 = OldBill(table_number=3, meal_amount=20.5, served_by="Dan", tip_amount=5) +... print("Comparison Between Regular Instances:", old_bill0 == old_bill1) +... +Comparison Between Regular Instances: False +>>> bill0 = Bill(table_number=5, meal_amount=50.5, served_by="John", tip_amount=7.5) +... bill1 = Bill(table_number=5, meal_amount=50.5, served_by="John", tip_amount=7.5) +... print("Comparison Between Data Class Instances:", bill0 == bill1) +... +Comparison Between Data Class Instances: True +``` + +如上所示,在常规的类中,两个所有属性值都相等的实例会被评估为不相等。因为在默认情况下,自定义类的实例是根据其标识进行比较的。在这种情况下,这两个实例是两个截然不同的对象,因此它们被认为是不相等的。 + +然而,在数据类中,同等的比较将被判定为 `True`。这是因为 `dataclass` 装饰器会为我们自动生成特殊方法 `__eq__`。准确地说,进行相等比较时,视每个实例为一个元组,元组内包含按顺序定义的字段。因为这两个数据类的字段拥有相同值,所以它们被认为是相等的。 + +那么不相等的比较,例如大于和小于,又应当如何呢?我们也可以使用 `dataclass` 装饰器,在使用装饰器时指定 `order` 参数,如下面的第 1 行所示。 + +```Python +>>> @dataclass(order=True) +... class ComparableBill: +... meal_amount: float +... tip_amount: float +... +... +... bill1 = ComparableBill(meal_amount=50.5, tip_amount=7.5) +... bill2 = ComparableBill(meal_amount=50.5, tip_amount=8.0) +... bill3 = ComparableBill(meal_amount=60, tip_amount=10) +... print("Is bill1 less than bill2?", bill1 < bill2) +... print("Is bill2 less than bill3?", bill2 < bill3) +... +Is bill1 less than bill2? True +Is bill2 less than bill3? True +``` + +与相等比较类似,数据类实例被当作这些字段的元组,并按字典顺序进行比较。为了验证这一概念,上面的代码只包含两个字段,如你所见,比较结果基于元组的顺序。 + +## 4. 仔细考虑可变性 + +默认情况下,数据类的字段可以被修改,因此我们可以说数据类实例是可变的。这也是为什么有些人将数据类称为**可变的具名元组**。考虑以下具名元组和数据类之间关于可变性的对比。 + +```Python +>>> from collections import namedtuple +>>> NamedTupleBill = namedtuple("NamedBill", "meal_amount tip_amount") +>>> +>>> @dataclass +... class DataClassBill: +... meal_amount: float +... tip_amount: float +... +>>> namedtuple_bill = NamedTupleBill(20, 5) +>>> dataclass_bill = DataClassBill(20, 5) +>>> namedtuple_bill.tip_amount = 6 +Traceback (most recent call last): + File "", line 1, in +AttributeError: can't set attribute +>>> dataclass_bill.tip_amount = 6 +``` + +就像上面展示的那样,你不能设置具名元组的属性。然而,我们可以对数据类实例执行以上操作,这突出了数据类支持数据可变性的优点。 + +然而,数据可变性并非总是理想的。在一些场景中,你不希望数据可以被改变。在这种情况下,可以考虑在使用 `dataclass` 装饰器时将 `frozen` 参数设置为 `True`。下面是一个简单的例子: + +```Python +>>> @dataclass(frozen=True) +... class ImmutableBill: +... meal_amount: float +... tip_amount: float +... +>>> immutable_bill = ImmutableBill(20, 5) +>>> immutable_bill.tip_amount = 7 +Traceback (most recent call last): + File "", line 1, in + File "", line 4, in __setattr__ +dataclasses.FrozenInstanceError: cannot assign to field 'tip_amount' +``` + +## 5. 继承的注意事项 + +究其核心,数据类和其他常规自定义类一样,具有相同的可扩展性。因此,如果有需要,我们可以继承数据类。 + +```Python +>>> @dataclass +... class BaseBill: +... meal_amount: float +... +>>> +>>> @dataclass +... class TippedBill(BaseBill): +... tip_amount: float +... +>>> tipped_bill = TippedBill(meal_amount=20, tip_amount=5) +``` + +如上面的代码段所示,`dataclass` 装饰器将为子类考虑基类的字段。换而言之,在子类的初始化中可以看出,它自动拥有来自基类的字段和它本身的字段。值得注意的是,字段的顺序基于它们定义的顺序 —— 基类的字段排在第一位,子类的字段紧随其后,如果你有多代子类则依此类推。 + +由于这些字段在子类中的顺序,以及数据类要求有默认值的字段应在没有默认值的字段之后。这意味着如果基类包含具有默认值的字段,则子类所添加的字段也应具有默认值。否则,你可能会看到如下错误 —— 与我们之前看到的错误相同。 + +```Python +@dataclass +... class BaseBill: +... meal_amount: float = 20 +... +@dataclass +... class TippedBill(BaseBill): +... tip_amount: float +... +Traceback (most recent call last): + ... some traceback info omitted +TypeError: non-default argument 'tip_amount' follows default argument +``` + +## 6. 具有默认值的可变字段 + +在上面的例子中,字段都是不可变的数据类型,例如浮点数和字符串。如果我们需要使用可变数据作为数据类的字段,我们应当怎么做呢?思考下面的代码片段,这其中包括一些 Python 程序员可能会犯的错误。 + +```Python +>>> class IncorrectBill: +... def __init__(self, costs_by_dish=[]): +... self.costs_by_dish = costs_by_dish +... +>>> bill0 = IncorrectBill() +>>> bill1 = IncorrectBill() +>>> bill0.costs_by_dish.append(5) +>>> bill1.costs_by_dish.append(7) +>>> print("Bill 0 costs:", bill0.costs_by_dish) +Bill 0 costs: [5, 7] +>>> print("Bill 1 costs:", bill1.costs_by_dish) +Bill 1 costs: [5, 7] +>>> bill0.costs_by_dish is bill1.costs_by_dish +True +``` + +由上面的代码可知,当你的函数使用了可变默认值时,你实际上并不能给可变实例设置默认值,因为这个可变对象被所有未指定参数的调用者共享。在上面的示例中,如你所见,两个实例共享底层的列表对象,这导致了我们不愿看到的结果。 + +问题是我们要如何在数据类的上下文中为可变字段指定默认值。我们不应该执行以下操作,这会引发 `ValueError` 异常。 + +```Python +@dataclass +class IncorrectBill: + costs_by_dish: list = [] + +ValueError: mutable default for field costs_by_dish is not allowed: use default_factory +``` + +错误信息告诉了我们解决方案,方案包括在指定字段时使用 `default_factory` 方法。下面的代码向你展示了它是如何工作的。 + +```Python +>>> from dataclasses import field +... @dataclass +... class CorrectBill: +... costs_by_dish: list = field(default_factory=list) +... +>>> bill0 = CorrectBill() +>>> bill0.costs_by_dish.append(5) +>>> bill1 = CorrectBill() +>>> bill1.costs_by_dish.append(7) +>>> print("Bill 0 costs:", bill0.costs_by_dish) +Bill 0 costs: [5] +>>> print("Bill 1 costs:", bill1.costs_by_dish) +Bill 1 costs: [7] +>>> bill0.costs_by_dish is bill1.costs_by_dish +False +``` + +* 我们从 `dataclasses` 模块中引入 `field` 函数。 +* 在 `field` 函数中,我们将 `list` 指定为 `default_factory` 参数的取值。实际上,这个参数设置了默认的工厂函数,这是要在创建实例的时使用的零参数函数。在本例中,`list` 函数是列表对象的构造方法,当我们调用 `list()` 时会创建一个新的列表对象。 +* 如你所见,在这两个实例中,它们的 `costs_by_dish` 属性都具有不同的列表对象,这和预期的结果一样。 + +## 总结 + +在这篇文章中,我们回顾了在开始使用 Python 数据类时应该知道的 6 个基本事项。从大体上看,它们对数据存储非常有用,并且 `dataclass` 装饰器为我们提供了许多代码样板。与具名元组相比,`dataclass` 装饰器允许改变字段,这使得它更加灵活。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/6-ways-to-speed-up-your-vue-js-application.md b/article/2020/6-ways-to-speed-up-your-vue-js-application.md new file mode 100644 index 00000000000..98cae8f0294 --- /dev/null +++ b/article/2020/6-ways-to-speed-up-your-vue-js-application.md @@ -0,0 +1,177 @@ +> * 原文地址:[6 Ways to Speed Up Your Vue.js Application](https://medium.com/better-programming/6-ways-to-speed-up-your-vue-js-application-2673a6f1cde4) +> * 原文作者:[Aris Pattakos](https://medium.com/@aris.pattakos) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/6-ways-to-speed-up-your-vue-js-application.md](https://github.com/xitu/gold-miner/blob/master/article/2020/6-ways-to-speed-up-your-vue-js-application.md) +> * 译者:[黄梵高](https://github.com/MangoTsing) +> * 校对者:[Chorer](https://github.com/Chorer) + +# 加速 Vue.js 应用的六种绝技 + +![](https://cdn-images-1.medium.com/max/2400/1*aW-r70mA9ByajQQfiFh5hQ.png) + +如果你曾经使用过谷歌的 Pagespeed Insights 或者 Google Lighthouse,那你肯定也见过如下图的网页性能评估: + +![](https://cdn-images-1.medium.com/max/2000/1*UzMBfW8YlXv39Mc9vfKt6Q.png) + +你会收到一组统计数据,还有一些针对你的网站运行速度快慢的诊断。 + +有些诊断非常实用,帮你指出了一些简单的修改意见、未使用的文件,以及速度过慢或资源过大的一些请求。 + +至于其它的诊断,比如针对主线程的运行情况和 JavaScript 执行代码的时长,它们会提示可能存在的问题,但并不会真正的帮你去修复。 + +在本文中,你可以通过遵循下面这些步骤,确保你的 Vue 应用尽可能快地运行。并且通过这些步骤,你也可以准确定位到需要修复的地方,而不是仅仅靠猜测。 + +## 1. 只更新需要更新的内容 + +在使用 VueJS 时,你可能会遇到的最麻烦的问题之一就是,渲染相同的元素或元素列表的次数,超过实际需要的次数。为了理解其中的原因,我们不得不先理解一下 Vue 中的响应式。 + +下面这个例子出自 Vue.js 官方文档,它展示了哪些属性是响应式的,哪些属性不是。Vue 中有许多的响应式元素:挂载在 data 对象上的属性、计算属性,以及依赖响应式属性的方法。 + +```JavaScript +var vm = new Vue({ + data: { + a: 1 + } +}) +// `vm.a` 现在是响应式的了 + +vm.b = 2 +// `vm.b` 并不是响应式的 +``` + +但是一段普通的 JavaScript 代码,例如 `{{ 'value' }}` 或 `{{ new Date() }}`,是不会作为响应式属性被 Vue 监测的。 + +那么响应式是怎么样去进行重复渲染的呢? + +让我们假设在你的 `data` 对象中,有一个如下的对象数组: + +``` +values: [{id: 1, t: 'a'}, {id: 2, t: 'b'}] +``` + +并且你使用 `v-for` 指令来渲染它: + +```vue +
{{ value.t }}
+``` + +当一个新的元素被添加到这个列表时,Vue 将会重新渲染整个列表。难以置信吗?试一试就知道了: + +```vue +
+ {{ value.t }} + {{ new Date() }} +
+``` + +因为 JavaScript 的 `Date` 对象并不是响应式的,因此它不会影响渲染。只有在必须再次渲染的时候才会调用它。在这个例子中你可以看到,每次在 `values` 中添加或删除值时,所有渲染完成的元素上都会弹出一个新的日期。 + +在这个优化后的页面里你期待看到的结果是什么?你应该只希望新的或者发生变化的元素展示一个新的 `Date`,而不是重新渲染所有元素。 + +所以,`key` 是做什么的?我们为什么要传这个值?其实 `key` 这个属性可以作为唯一标识帮助 Vue 去定位某个元素。如果数组的顺序发生变化,`key` 可以帮助 Vue 将元素无序地排列到适当的位置,而不是逐个去重复遍历。 + +指定一个 `key` 很重要,但这还不够。为了确保能获得最佳的性能,你还需要创建子组件。没错,解决办法很简单,你需要把你的 Vue 应用拆分成几个小组件。 + +```vue + +``` + +item 组件只会在具有明确的响应式数据变化时才会更新(举个例子 [Vue.set](https://vuejs.org/v2/api/#Vue-set)) + +使用组件来渲染列表可以让性能得到巨大提升。如果从数组中添加或删除元素,Vue 将不会再次逐个渲染所有的组件。如果这个数组重新排序,Vue 只需要根据元素依赖的 `key` 来重新排序并渲染。 + +如果是轻量级的组件,你还可以做另一个优化。可以传入一个类似 `value.t` 这样的私有属性(字符串或数字),而不是传入一个类似 `value` 这样的完整对象。这么做的话,只有当传入的值发生更改时,`` 组件才会被重新渲染。这一点也告诉我们,即使我们不需要更新,但响应式对象发生变化也会导致重复渲染。 + +## 2. 消除重复渲染 + +渲染完整的列表或复杂的元素时,超过预计渲染次数是一个很难发现的问题,但它非常容易发生。 + +让我们假设一个组件在它的 data 对象内有一个 `entities` 属性。 + +如果你按照上面的步骤进行,那大概会有一个子组件来渲染每一块内容。 + +```vue + +``` + +这个 entity 组件的模版如下所示: + +```Vue + +``` + +它输出 `entity.value`,同时也使用了来自 `vuex` 中 state 的 `user` 对象。现在我们假设有一个 `auth` 方法可以刷新用户的 token,或者有任意的方式导致全局的 user 对象属性发生了改变。这将导致整个 entire 的视图在每次 user 对象发生改变都会重新渲染,即使 `user.status` 保持不变! + +有几种方法可以解决这个问题。一种简单的办法就是将 `user.status` 的值作为父组件的一个 `userStatus` 属性传进来。如果这个值保持不变,那么 Vue 就不会也没必要将它重复渲染。 + +这里的关键是要注意渲染的依赖关系。更改任何 prop 属性,data 中的值,或者计算属性的值都有可能会造成重复渲染。 + +那我们怎么样才能识别出来重复渲染呢? + +首先让我们下载官方的 [Vue.js dev tools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=en)! + +然后进入 Performance 选项来测试你的 Vue 应用的性能。按下 start 和 stop 运行性能检查,当然最好是在这个 app 加载的期间。 + +![Vue.js dev tools 截图](https://cdn-images-1.medium.com/max/3710/1*uRo4r7Rbncqnrx8dbhVCtw.png) + +然后我们切换到 Component Render 选项。如果你的页面渲染了 100 个组件,那你应该看见 100 个 `created` 事件。 + +这里需要注意的是 `updated` 事件。如果 `updated` 事件的数量超过 `created` 事件,但实际上值并没有更新,那有可能存在重复的数据更改,导致重复渲染。 + +如果代码多次更改 `entities` 的值而不是批处理更新,则很有可能出现这个问题。或者,如果你在使用某种实时数据库,类似 Firestore,并且你每次获得的快照都比预期的多,也有可能会出现这个问题。(Firestore 可以在每次更新时发送许多快照,特别是当你设置了频繁更新相关文本的 Firestore 触发器时) + +这个问题的解决方案是避免更改内容的次数超过必要的次数。对于 Firestore 快照,你可以使用节流或者防抖函数去避免过于频繁地更改 `entities` 对象的属性。 + +## 3. 优化事件监听 + +并非所有的事件生而平等,因此你不得不确认是否合理优化了每一个事件。 + +有两个很好的例子是 `@mouseover` 和 `window.scroll` 事件。这两种类型事件即使在正常情况下也会多次触发。如果你的事件监听函数进行了很复杂的计算,这些计算每一秒都会运行很多次,结果就是导致应用程序出现延迟。解决方案之一就是使用防抖函数来限制这些事件的处理次数。 + +## 4. 删除或减少过慢的组件 + +当你自己创建新的组件,尤其是引入第三方组件时,你需要确保它们的性能良好。 + +你可以使用 Vue.js 开发工具的 performance 选项来预估每个组件的渲染时间。当增加一个新组件时,你可以将它渲染所需要的时间与自己的组件对比。 + +如果这个新组件花费的时间比你自己的组件更多,那你可能需要去查找其它可替代的组件,删除这个组件,或者尝试减少使用这个组件。 + +![](https://cdn-images-1.medium.com/max/2000/1*SLEt6zuG1eYEhKfq9Fxw4A.png) + +## 5. 只渲染一次 + +![](https://cdn-images-1.medium.com/max/2000/1*6PL_PU-Dg-UHrIPZutTLfw.png) + +上图来自于 Vue.js 的官方文档。如果你希望所有元素都完成挂载后,某些元素只会被渲染一次,那么你可以使用 v-once 指令。 + +假设在你的应用程序运行期间,有一部分数据不会发生变化,那么使用 v-once 指令可以确保这部分内容只会渲染一次。 + +## 6. 虚拟滚动 + +这是优化 Vue 应用性能的最后一步啦。你曾经在屏幕上滚动过 Facebook 的页面吗?(或者是 Twitter、Instagram 或者任何流行的社交软件)我打赌你这么做过!你可以无尽地滚动下去,并且页面不会越来越卡顿。但如果你的 Vue 应用中有一个巨大的列表需要渲染,你会看到页面随着长度增加会越来越卡顿。 + +如果你决定实现无限的滚动,而不是分页功能,那么你应该可以使用下面两个开源项目之一,来实现虚拟滚动条和渲染大量的列表: + +* [https://github.com/tangbc/vue-virtual-scroll-list](https://github.com/tangbc/vue-virtual-scroll-list) +* [https://github.com/Akryum/vue-virtual-scroller](https://github.com/Akryum/vue-virtual-scroller) + +这两个我都使用过,个人认为 `vue-virtual-scroll-list` 的体验更好一点,使用起来更容易,而且不依赖会破坏用户本身 UI 的绝对定位。 + +## 结论 + +虽然这篇指南没有包含所有可能遇到的情况,但这六种方法涵盖了 Vue 应用程序许多常见的性能问题。 + +实现高效的前端性能可能比你想象的更重要。开发人员的计算机通常比 app 用户的计算机更好。你的用户甚至可能都不使用计算机,而是使用速度慢并且已经过时的智能手机。 + +因此我们开发人员被赋予了这项重任,我们要尽可能做到最好,并提供最佳的用户体验。你可以将这六种绝技作为一个自测清单,用来帮助确认你的 Vue 应用程序可以让所有的用户流畅运行。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/7-helpful-time-complexities.md b/article/2020/7-helpful-time-complexities.md index 69dd82c2d72..e2a3b3be57e 100644 --- a/article/2020/7-helpful-time-complexities.md +++ b/article/2020/7-helpful-time-complexities.md @@ -2,85 +2,85 @@ > * 原文作者:[Ellis Andrews](https://medium.com/@ellisandrews1) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/7-helpful-time-complexities.md](https://github.com/xitu/gold-miner/blob/master/article/2020/7-helpful-time-complexities.md) -> * 译者: -> * 校对者: +> * 译者:[PingHGao](https://github.com/PingHGao) +> * 校对者:[rachelcdev](https://github.com/rachelcdev), [Isildur46](https://github.com/Isildur46) -# 7 Helpful Time Complexities +# 算法中七种常见的时间复杂度 ![](https://cdn-images-1.medium.com/max/2000/1*6C2DkLB3o2RjBbb0aCvKUQ.jpeg) -As programmers, we’re often striving to write the most efficient code possible. But how do we know if the code we’ve written is efficient? The answer: Big O analysis. The goal of this article is to explain this concept in the simplest terms possible. I’ll start with an introduction to Big O, followed by examples of the seven most common cases you’re likely to come across. Feel free to skip to the second section if you’re already familiar with the concept but want a concrete refresher with real Python code! - -## Explain it Like I’m 5: The Big O Edition +作为程序员,我们经常努力编写尽可能高效的代码。但是我们怎么知道我们编写的代码是否高效?答案:大 O 分析。本文的目的是用尽可能简单的术语来解释这个概念。我将首先介绍 Big O,然后举例说明您可能会遇到的七个最常见的情况。如果您已经熟悉这个概念,但是想要使用真实的 Python 代码进行具体的复习,请随时跳到第二部分! +## 像我只有 5 岁一样给我解释:大 O 版 ![](https://cdn-images-1.medium.com/max/2000/1*34pO-qdgbiTPThB7lmV91Q.png) -Put simply, “Big O” notation is how we talk about the efficiency of an algorithm. Specifically, it describes how the running time* of an algorithm changes as the algorithm’s input grows arbitrarily large. While this is a succinct definition, I don’t know a single five-year-old who would understand that statement, so let’s break it down further. Here are a few definitions: +简而言之,我们用「大 O 表示法」来描述算法的效率。具体来说,它描述了算法输入任意增加时,算法的运行时间是如何变化的。虽然这是一个简洁的定义,但我不认识哪个 5 岁小孩能理解这种表述,所以让我们进一步详细讲解。以下是一些定义: -> **1. Algorithm** **—** A set of logical steps that acts on an input to produce an output. +> **1. 算法** **—** 一组逻辑步骤,作用于输入以产生输出。 -In this article, I will conflate an **algorithm** with something a little more familiar: a **function**. Think about what most functions do that you’ve written. They take one or more arguments as input, perform a specified recipe of operations on those arguments, and then return a value as output. Don’t be scared by the fancy word, you’ve probably already written tons of algorithms! From here on out, when I say “algorithm” you can really think “function”. +在本文中,我将**算法**与更熟悉的概念联系:**函数**。回想一下你编写的大多数函数的功能,它们将一个或多个参数作为输入,对这些参数执行指定的操作步骤,然后返回一个值作为输出。不要害怕这个花哨的词,您可能已经写了很多算法!从现在开始,当我说「算法」时,你可以直接把它理解为「函数」。 -> **2. Running Time** **—** The number of operations an algorithm has to perform. +> **2. 运行时间** **—** 算法需要执行的操作数量。 -There are many factors that could affect how long an algorithm takes to run in seconds, minutes, hours, etc. on a given computer. So instead of focusing on the actual **time** that an algorithm takes to run, Big O frames the run time in terms of the **number of operations** performed. Fewer operations equal a shorter running time (more efficient), whereas more operations equal a longer running time (less efficient). Thus, we have a standard way of comparing algorithms. +有许多因素可能会影响算法在特定计算机上的运行时间,无论运行时间是以秒、分、时等时间单位来衡量。因此,大 O 表示法不关注算法运行的实际**时间**,而是根据需要执行的**操作数**来定义运行时间。较少的操作等于较短的运行时间(效率更高),而较多的操作等于较长的运行时间(效率较低)。因此,我们有了比较算法的标准方法。 -> **3. Input Size —** The amount of data the algorithm is given to process. +> **3. 输入规模 —** 算法需要处理的数据量。 -In Big O, we’re interested in how algorithms diverge in terms of performance as we give them more and more data to process. For example, you could probably write several fairly similarly optimized functions for finding the maximum value in a list of three random numbers. But what if the list instead contained 100 numbers? Or 1,000? 1,000,000? This is what we mean by the “input size growing arbitrarily large”, and is why Big O is sometimes called “asymptotic analysis”. In Big O, the size of the input is referred to as “**n**”. +在大 O 表示法中,我们关注的是随着数据输入量的增长,不同算法在性能表面方面的差异。举个例子,假设需要在三个随机数的列表中查找最大值,你或许有能力编写几个函数,并把他们的性能优化到相似的程度。但是,如果列表包含 100 个数字怎么办?1,000?1,000,000 呢?这就是我们所说的「输入规模任意增大」,这也是为什么大 O 表示法有时被称为「渐近分析」的原因。在大 O 表示法中,输入规模称用「**n**」表示。 -In addition to running time, Big O can also be used to describe how much space (memory, disk, etc.) an algorithm uses relative to the input size. In this article, I will focus on time complexity. +除了运行时间外,大 O 表示法还可以用于描述算法基于输入规模而对空间(内存,磁盘等)的消耗程度。在本文中,我将聚焦于介绍时间复杂度。 -#### How to Read and Write Big O +#### 如何读写大 O -Now that we understand what Big O helps us do, what does it look like? Well, it’s written with a capital “O” followed by a mathematical expression in terms of “n” (the size of the input) in parentheses. Here are the seven examples that you will most frequently encounter, ranked from most efficient to least efficient. +既然我们已经了解大 O 表示法的作用了,那么它究竟怎么写呢?好吧,它的写法是大写的「O」,后面跟着一个括号,括号里面是一个包含「n」(即输入规模)的数学表达式。下文中有最常见的七个示例,按照运行效率从高到低排序。 -1. **O(1) —** Constant -2. **O(log n) —** Logarithmic -3. **O(n) —** Linear -4. **O(n log n) —** Log-linear -5. **O(nᵏ) —** Polynomial -6. **O(kⁿ) —** Exponential -7. **O(n!) —** Factorial +1. **O(1) —** 常数复杂度 +2. **O(log n) —** 对数复杂度 +3. **O(n) —** 线性复杂度 +4. **O(n log n) —** 对数线性复杂度 +5. **O(nᵏ) —** 多项式复杂度 +6. **O(kⁿ) —** 指数复杂度 +7. **O(n!) —** 阶乘复杂度 -Below is a graph plotting the number of operations (the running time) against the size of the input for an algorithm with each complexity. +下图描绘了各种复杂度的算法中,当输入规模增长时,操作数量(运行时间)的变化趋势。 ![Source: [https://www.bigocheatsheet.com/](https://www.bigocheatsheet.com/)](https://cdn-images-1.medium.com/max/3412/1*PpKIWUPNwB0a4kJvywCgqA.png) -You can see that, as the size of the input increases, the running time of the algorithms in the red shaded area increases drastically. On the other hand, the performance of the algorithms in the yellow and green shaded areas is much less dependent upon the size of the input and is, therefore, more efficient and scalable. -As a final point of clarification, Big O analysis is usually used to describe the **dominant trend** of an algorithm as the input gets very large. Thus, insignificant terms can be dropped if they are overpowered by more significant terms. For instance, an algorithm with a computed time complexity **O(n² + n)** would simply be referred to as **O(n²)** due to the fact that as **n** grows very large, the effect of the **n²** term greatly outstrips that of the **n** term. +你可以看到,随着输入规模的增长,红色阴影区域中算法的运行时间急剧增长。另一方面,在黄色和绿色阴影区域中的算法,当输入规模增长时,运行时间在变化不是很大,因此它们更高效,处理大量数据时更游刃有余。 + +最后需要指明的一点,大 O 表示法通常用于描述当输入规模变得非常大时,算法呈现的「显著趋势」。因此,大的显著趋势会盖过一些小的细枝末节的趋势。例如,我们实际测算得到时间复杂度为 **O(n²+ n)** 的算法会简化为 **O(n²)**,原因是随着 **n** 变得非常大时, **n²** 这一项的显著性远远盖过了 **n** 这一项的显著性。 -## Examples +## 例子 -Now, let’s look at some common examples of algorithms that fall under each of the aforementioned complexities. +现在,让我们看一下上述每种复杂度的算法对应的一些常见例子。 -#### 1. O(1) — Constant +#### 1. O(1) — 常数复杂度 -The running time of algorithms of this complexity does not increase as the size of the input increases. A common operation of this nature is a value lookup by index in an array or key in a hash table: +这种复杂度的算法的运行时间不会随着输入规模的增加而增加。这类操作的实际例子就是在数组中按索引查找值,或者在哈希表中按键查找值: ```Python from typing import Any, Dict, List -# Example 1 +# 例 1 def list_lookup(list_: List[Any], index: int) -> Any: """Lookup a value in a list by index.""" return list_[index] -# Example 2 +# 例 2 def dict_lookup(dict_: Dict[Any, Any], key: Any) -> Any: """Lookup a value in a dictionary by key.""" return dict_[key] ``` -No matter how large the list or dictionary passed into these functions is, they will complete at the same time (one operation). +无论传递给这些函数的列表或字典有多大,它们用同等的时间来完成(只有一步操作)。 -#### 2. O(log n) — Logarithmic +#### 2. O(log n) — 对数复杂度 -The classic logarithmic algorithm example is a [binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm). This is an algorithm for finding a value in a sorted array by iteratively looking at the middle value, checking if the target value is less than or greater than the middle value, and then eliminating the half of the array in which we are certain that the value does not lie. Here is an implementation: +典型的对数复杂度算法是[二分搜索算法](https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%88%86%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95)。这是一种用于在有序数组中查找特定值的算法,它不断迭代读取当前范围的中间值,判断目标值是小于还是大于中间值,排除不包含目标的那一半内容。下面是它的一种实现: ```Python from typing import Any, List @@ -88,41 +88,41 @@ from typing import Any, List def binary_search(list_: List[int], target_value: int) -> int: """ - Perform a binary search of a sorted input list for a target value. - Return the index of the target value in the list, or -1 if not found. + 对有序的输入列表执行二分搜索以找到目标值。 + 返回列表中目标值的索引,如果未找到则返回 -1。 """ - # Initialize left and right indexes for start of search + # 初始化左右索引以开始搜索 left = 0 right = len(list_) - 1 - # Perform binary search + # 执行二分搜索 while left <= right: - # Calculate the middle index of the remaining list values to be searched + # 计算要搜索的剩余列表的中间位置的索引 middle = left + (right - left) // 2 - # Check if target_value is at the middle index. If so, we've found it and we're done. + # 检查目标值是否在中间索引处。如果是,我们已经找到并完成。 if list_[middle] == target_value: return middle - # If target_value is greater than the middle value, ignore the left half of the remaining list values + # 如果目标值大于中间值,请忽略剩余列表的左半部分 elif list_[middle] < target_value: left = middle + 1 - # If target_value is less than the middle value, ignore right half of the remaining list values + # 如果目标值小于中间值,请忽略剩余列表的右半部分 else: right = middle - 1 - # Return a sentinel value of -1 if the target_value was not found in the whole list + # 如果在整个列表中未找到目标值,则返回 -1 return -1 ``` -Given that the size of the array yet to be searched is halved on each iteration, searching an array twice as large would only take one additional iteration! Thus, as the array size increases the runtime increases logarithmically. +由于每次迭代,待搜索的数组长度会减半。因此哪怕搜索的数组长度翻了一倍,也只需多迭代一次!因此,随着数组长度的增加,运行时间将呈对数增长。 -#### 3. O(n) — Linear +#### 3. O(n) — 线性复杂度 -Algorithms with linear time complexity typically involve iterating over a data structure serially. To borrow from our previous logarithmic search example, a search for a value in an array can also be performed in (less efficient) linear time: +线性复杂度算法往往在连续迭代数据结构时涉及到。参考先前的对数搜索示例,在数组中搜索值可以用(效率较低)的线性时间来进行: ```Python from typing import Any, List @@ -130,64 +130,64 @@ from typing import Any, List def linear_search(list_: List[Any], target_value: Any) -> int: """ - Perform a linear search of an input list for a target value. - Return the index of the target value in the list, or -1 if not found. + 对输入列表执行线性搜索以找到目标值。 + 返回列表中目标值的索引,如果未找到则返回 -1。 """ - # Iterate over each item in the list, checking whether it is the target value + # 遍历列表中的每一项,检查其是否为目标值 for index, item in enumerate(list_): if item == target_value: return index - # Return a sentinel value if the target_value was not found in the list + # 如果在列表中未找到目标值,则返回一个标记值 return -1 ``` -It’s clear that as the size of the input list grows, the worst-case scenario for the number of loop iterations required to find the item is directly proportional to the size increase, as every item in the list needs to be checked. +显然,随着输入列表大小的增加,由于需要检查列表中的每个项目,最坏情况下找到目标所需的循环迭代次数的增长与输入列表的大小增长成正比。 -#### 4. O(n log n) — Log-linear +#### 4. O(n log n) — 对数线性复杂度 -Log-linear complexity algorithms are a little harder to spot than our previous examples. As their name suggests, they involve both a logarithmic and a linear component. The most common examples of these are sorting algorithms. “Merge sort” is one such algorithm for sorting an array in which the array is iteratively halved, sorted in pieces, and merged back together in sorted order. This is perhaps easier to see through a diagram, so I’ll omit the code implementation for this one. +列举对数线性复杂度算法的示例会比之前难一些。顾名思义,它们同时包含对数和线性部分。其中最常见的示例是排序算法。有一个算法叫「归并排序」,它用迭代手法将数组分成一小块一小块,对每小块进行拆分、排序,然后再按顺序重新将各个小块合并在一起。通过图像可以更容易看明白,因此我将省略代码的实现。 -![Merge sort algorithm. Source: [https://en.wikipedia.org/wiki/Merge_sort](https://en.wikipedia.org/wiki/Merge_sort)](https://cdn-images-1.medium.com/max/2560/1*jgT8yBf2lsaCjdbsIPZJsQ.png) +![归并排序算法。来源:[https://en.wikipedia.org/wiki/Merge_sort](https://en.wikipedia.org/wiki/Merge_sort)](https://cdn-images-1.medium.com/max/2560/1*jgT8yBf2lsaCjdbsIPZJsQ.png) -#### 5. O(nᵏ) — Polynomial +#### 5. O(nᵏ) — 多项式复杂度 -At this point, we’re getting into algorithms with time complexities that do not scale very well and should usually be avoided if possible (referring back to the graph above, we’re in the red zone!). However, many “brute-force” algorithms fall under the polynomial complexity category and can be useful starting points for solving a problem. For example, below is a quadratic (k=2) polynomial algorithm for finding the duplicate items in an array: +在这里,我们开始着手研究时间复杂度较差的算法,通常应尽可能避免使用它(请参考上文的图表,我们正处于红色区域!)。但是,许多「暴力」算法都属于多项式复杂度,可以作为帮助我们解决问题的切入点。例如,下面是查找数组中重复项的二次(k = 2)多项式算法: ```Python from typing import Any, List, Set def find_duplicates(list_: List[Any]) -> Set[Any]: - """Find all duplicate items in a list.""" + """查找列表中所有的重复项。""" - # Initialize a set to hold the duplicate items + # 初始化一个集合以保存重复项 duplicates = set() - # Check each item in the list against every other item in the list + # 将列表中的每一项与列表中的其他所有项进行检查 for index_1, item_1 in enumerate(list_): for index_2, item_2 in enumerate(list_): if index_1 != index_2 and item_1 == item_2: duplicates.add(item_1) - # Return the set of duplicate items + # 返回重复项的集合 return duplicates ``` -For each item in the array, we check it against every other item in the array. Thus, if the array contains **n** items we perform **n** * **n = n**² operations for a time complexity of **O(n²)**. +对于数组中的每一项,我们都将其数组其余各进行检查。因此,如果数组包含 **n** 个项目,我们将执行 **n** * **n = n**² 个运算,时间复杂度为 **O(n²)**。 -Extra credit: Can you think of a better algorithm for solving this problem? +附加题:你能想出更好的算法来解决此问题吗? -#### 6. O(kⁿ) — Exponential +#### 6. O(kⁿ) — 指数复杂度 -Our penultimate common time complexity is exponential, in which the running time increases by a constant factor as the size of the input increases. A typical example of this is naively computing the **n**th term in the [Fibonacci sequence](https://en.wikipedia.org/wiki/Fibonacci_number). +我们的倒数第二个常见时间复杂度是指数复杂度,即随着输入规模的增加,运行时间将按固定倍数来增长。一个典型的例子是直接计算[斐波纳契数列](https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97)中的第 n 项。 ```Python def nth_fibonacci_term(n: int) -> int: - """Recursively finds the nth term in the Fibonacci sequence. Assumes positive n.""" - # Base case -- The first two numbers of the sequence are {0, 1} + """递归计算斐波纳契数列的第 n 项。假设 n 是整数。""" + # 基本情况 —— 前两项的值为 {0,1} if n <= 2: return n - 1 @@ -195,17 +195,17 @@ def nth_fibonacci_term(n: int) -> int: ``` -In the example above, the number of operations performed doubles whenever the input **n** increases by 1. This is due to the fact that we do not cache the results of each function call, and must re-calculate all previous values down to the base case each time. Thus, the time complexity of the algorithm is **O(2ⁿ)**. +在上面的示例中,每当输入 **n** 增加 1 时,执行的操作数量就会翻倍。这是因为我们没有缓存每个函数调用的结果,所以必须从最开始重新计算所有先前的值。因此,该算法的时间复杂度为 **O(2ⁿ)**。 -#### 7. O(n!) — Factorial +#### 7. O(n!) — 阶乘复杂度 -Last but not least (but certainly least efficient) are algorithms with factorial time complexity. These should generally be avoided, as they rapidly become unviable as the input scales. One example of such an algorithm is a brute-force solution to [The Traveling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). This problem seeks to find the shortest possible route that visits all points in a coordinate system and return to the starting point. The brute-force solution involves comparing all possible routes (read: permutations) against each other and selecting the shortest one. Note that this is not usually an acceptable solution to the problem, unless the number of points to visit is very low. +最后但同样重要(但肯定是效率最低)的类型是阶乘时间复杂度的算法。通常应避免这中复杂度,因为随着输入规模的增加,它们会很快变得难以运行。这种算法有一个示例,那就是[旅行推销员问题](https://www.baidu.com/s?ie=UTF-8&wd=%E6%97%85%E8%A1%8C%E6%8E%A8%E9%94%80%E5%91%98%E9%97%AE%E9%A2%98)的暴力解法。这个问题是希望找到一条最短路径,要求该路径必须访问坐标系中的所有点,并最终回到起点。暴力解法涉及相互比较所有可能的路线(读作:排列组合)并选择最短的。请注意,除非要访问的点数很少,否则这通常不是解决此问题的合理方法。 -![A Traveling Salesman Solution. Source: [https://en.wikipedia.org/wiki/Travelling_salesman_problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem)](https://cdn-images-1.medium.com/max/2000/1*Vq7Dq63LQrL9xC9Y8XqtGQ.png) +![一个旅行商问题的解法。来源:[https://en.wikipedia.org/wiki/Travelling_salesman_problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem)](https://cdn-images-1.medium.com/max/2000/1*Vq7Dq63LQrL9xC9Y8XqtGQ.png) -## Final Thoughts +## 结语 -While we’ve covered a lot of cases here, there is more to learn on the topic! I’ve focused on **worst-case time complexity**, but it can also be useful to think in terms of the average or best case as well. I also didn’t touch on space complexity, which can be equally important if memory is limited. The good news is that the syntax and general thought process is the same for that kind analysis. Hopefully the next time you’re in a coding interview or need to write a performant function, you now have the tools to attack it with confidence. +尽管我们在这里介绍了很多案例,但在该主题上还有很多东西要学习!我关注的是“最坏情况下的时间复杂度”,但考虑平均情况或最佳情况也很有用。我也没有提到空间的复杂性,如果内存有限,这也同样重要。好消息是,这种分析的方法和一般思考过程是相同的。希望下次您进行代码面试时或需要编写性能函数时,你有了可以放心地解决它的工具。 > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/article/2020/Damn-Cool-Algorithms-Log-structured-storage.md b/article/2020/Damn-Cool-Algorithms-Log-structured-storage.md new file mode 100644 index 00000000000..48853a5390a --- /dev/null +++ b/article/2020/Damn-Cool-Algorithms-Log-structured-storage.md @@ -0,0 +1,69 @@ +> * 原文地址:[Damn Cool Algorithms: Log structured storage](http://blog.notdot.net/2009/12/Damn-Cool-Algorithms-Log-structured-storage) +> * 原文作者:[Nick Johnson ](http://blog.notdot.net/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/Damn-Cool-Algorithms-Log-structured-storage.md](https://github.com/xitu/gold-miner/blob/master/article/2020/Damn-Cool-Algorithms-Log-structured-storage.md) +> * 译者:[jackwener](https://github.com/jackwener) +> * 校对者:[ousheobin](https://github.com/ousheobin),[chzh9311](https://github.com/chzh9311) + +## 酷毙了的算法:日志结构存储 + +通常来说,当你在设计一个文件系统或数据库这样的存储系统时,你会非常关注这个问题:如何在磁盘上存储数据。你必须注意为要存储的对象和索引数据分配空间;你也必须注意当您要扩展现有对象时(譬如追加到文件中)会发生什么,你还必须考虑旧对象被删除,新对象被存入时带来的存储碎片化问题。所有的这些问题都带来了很多复杂性,而且解决方案往往是有缺陷的或者低效的。 + +日志结构化存储是一种能够解决这些问题的技术。它起源于 1980 年代的[“日志结构文件系统”](http://en.wikipedia.org/wiki/Log-structured_file_system),但最近它被越来越多地用作数据库引擎中的结构化存储。在其原来应用的文件系统应用中,它存在一些明显的缺点导致无法广泛应用,但是正如我们将看到的那样,这些问题对于数据库引擎而言并不那么严重,同时日志结构化存储还能为数据库引擎带来更多除更容易进行存储管理以外的优势。 + +顾名思义,日志结构化存储系统的基本组织是日志,即仅附加的数据项序列。每当您有新数据要写入时,您只需将其添加到日志的末尾,而不需要在磁盘上找到它的位置。通过相同的方式处理元数据可完成数据索引,即把元数据的更新也追加到日志中。这看起来效率低下,但基于磁盘的索引结构(如 B 树)通常应用十分广泛,因此每次写入时需要更新的索引节点数量通常非常少。让我们看一个简单的例子。我们将从一个仅包含单个数据项和一个引用该数据项的索引节点的日志开始: + +![](http://lh3.ggpht.com/_23zDbjk-dKI/SyZO9lQGgXI/AAAAAAAABnQ/VZYZ7XBRHio/log-1.png) + +到现在为止还不错。现在,假设我们要添加第二个元素。我们将新元素添加到日志末尾,然后更新索引条目,并将更新后的版本也添加到日志中: + +![](http://lh4.ggpht.com/_23zDbjk-dKI/SyZO9z_SnKI/AAAAAAAABnU/GkRZ_W-jsEE/log-2.png) + +原有的索引项(A)仍在日志文件中,但不再生效:它已被新项 A' 替换,A' 引用 Foo 的原始未修改副本,以及新项 Bar。当有东西想读取文件系统时,它会找到索引的根节点,并像在任何其他使用基于磁盘的索引的系统中一样使用它。 + +寻找索引的根源值得一提。简单的方法是查看日志中的最后一个块,因为我们最后编写的总是索引的根。但是,这并不理想,因为在您尝试读取索引时,另一个进程可能正在向日志追加数据。我们可以通过在日志文件的开头使用一个包含指向当前根节点的指针的块来避免这种情况。每当更新日志时,我们重写第一个条目以确保它指向新的根节点。为了简洁起见,我们没有在图表中显示这一点。 + +接下来,让我们检查一下更新元素时会发生什么。假设我们修改 Foo: + +![](http://lh3.ggpht.com/_23zDbjk-dKI/SyZO9ypFpXI/AAAAAAAABnY/6l3a56oq0uY/log-3.png) + +我们开始写一个全新的 Foo 副本到日志的末尾。然后,我们再次更新索引节点(在本例中只有 A'),并将它们写入日志的末尾。同样,Foo 的旧副本仍然保留在日志中;它只是不再被更新的索引引用。 + +你可能已经意识到这个系统是不可持续的。总有一天,我们的存储空间会用完,所有这些旧数据会占满空间。在文件系统中,这是通过将磁盘视为环形缓冲区并覆盖旧的日志数据来处理的。当这种情况发生时,仍然有效的数据只会再次被追加到日志中,就好像它是新写入的一样,这就释放了旧副本以进行覆盖。 + +在常规文件系统中,我前面提到的一个缺点就是在这里暴露出来的。随着磁盘越来越满,文件系统需要花费越来越多的时间进行垃圾收集,并将数据写回日志的头部。当您达到 80% 的容量时,文件系统实际上已经停止工作了。 + +但是,如果您将日志结构存储用于数据库引擎,这不是问题!我们在常规文件系统上实现了这一点,因此我们可以利用它来简化我们的生活。如果我们将数据库分成多个固定长度的块,那么当我们需要回收一些空间时,我们可以选择一个块,重写任何仍然有效(active)的数据,然后删除该块。上一个例子中的第一个片段开始显得有点稀疏,所以让我们这样做: + +![](http://lh6.ggpht.com/_23zDbjk-dKI/SyZO96QYb4I/AAAAAAAABnc/GZzRiNzKPjw/log-4.png) + +我们在这里所做的只是获取 'Bar' 的现有副本并将其写入日志的末尾,接着是更新的索引节点,如上所述。现在我们已经做完了,第一个日志段已经完全空了,并且可以删除了。 + +与文件系统方法相比,这种方法有几个优点。首先,我们不局限于首先删除最旧的段:如果中间段几乎为空,我们可以选择对其进行垃圾回收。对于那种一些数据保留时间较长,而另一些数据需要重复读写的数据库,这一点特别有用:我们不想浪费太多时间重写相同的未修改数据。对于何时进行垃圾收集,我们也有一些更大的灵活性:我们通常可以等到一个段基本上是过时的,然后再对其进行垃圾收集,从而进一步减少我们必须做的额外工作。 + +不过,这种方法对数据库的优势不止于此。为了保持事务的一致性,数据库通常使用“预写日志”(Write Ahead Log)或 WAL。当数据库希望将事务持久化到磁盘时,它首先将所有更改写入 WAL,将这些更改刷新到磁盘,然后更新实际的数据库文件。这使得它可以通过重放WAL中记录的更改来从崩溃中恢复。但是,如果使用日志结构存储,则预写日志**就是**数据库文件,因此只需要写入一次数据。在恢复情况下,我们只需打开数据库,从最后一个记录的索引头开始,线性地向前搜索,并在执行过程中从数据中重建任何丢失的索引更新。 + +利用我们上面的恢复方案,我们也可以进一步优化我们的写操作。与每次写入时都写入更新的索引节点不同,我们可以将它们缓存在内存中,并且只定期将它们写入磁盘。只要我们提供某种方法来区分已完成事务和未完成事务,我们的恢复机制将会负责在崩溃时重建内容 + +使用这种方法,备份也更容易:我们可以通过在数据库完成后将每个新的日志段复制到备份介质来连续、增量地备份数据库。要恢复,我们只需再次运行恢复过程。 + +这个系统的最后一个主要优点是数据库中的并发和事务语义。为了提供事务一致性,大多数数据库使用复杂的锁系统来控制哪些进程可以在什么时候更新数据。根据所需的一致性级别,这可能涉及到读取者获取锁以确保在读取数据时数据不会被修改,以及写入者需要锁定数据以进行写入,并且如果有大量的并发读取,即使写入速率相对较低,也可能导致性能显著下降。 + +我们可以用多版本并发控制([Multiversion Concurrency Control,MVCC](http://en.wikipedia.org/wiki/Multiversion_concurrency_control))来解决这个问题。每当一个节点想从数据库中读取数据时,它都会查找当前的根索引节点,并将该节点用于其事务的其余部分。由于现有数据在基于日志的存储系统中从未修改过,因此该进程现在有了获取句柄时的数据库快照:并发事务所做的任何操作都不会影响其对数据库的视图。就这样,我们实现了无锁读取! + +在回写数据时,我们可以利用[乐观并发(Optimistic concurrency)](http://en.wikipedia.org/wiki/Optimistic_concurrency)。如上所述,在典型的读取-修改-写入周期中,我们首先执行读取操作。然后,为了写入更改,我们对数据库进行了写入锁定,并确认在第一阶段中读取的所有数据均未被修改。我们可以通过查看索引并检查我们关注的数据的地址是否与上次查看的地址相同来快速完成此操作。如果相同,则不会发生写操作,我们可以自己进行修改。如果不同,则发生冲突的事务,我们只需回滚并从读取阶段重新开始。 + +当我高度赞扬它时,你可能会想知道什么系统已经使用了这个算法。我所知的却很少,但以下是几个值得注意的: + +- 尽管最初的 [Berkeley DB](http://en.wikipedia.org/wiki/Berkeley_DB) 使用了相当标准的体系结构,但Java端口 [BDB-JE](http://www.oracle.com/database/berkeley-db/je/index.html) 使用了我们刚才描述的所有组件。 +- [CouchDB](http://couchdb.apache.org/) 使用了刚才描述的系统,但是它没有将日志分成段并进行垃圾收集,而是在累积了足够多的过时数据时重写整个数据库。 +- [PostgreSQL](http://www.postgresql.org/) 使用 MVCC,它的 WAL(write ahead logs)是结构化的,以便允许我们描述的增量备份方法。 +- [App Engine](http://code.google.com/appengine/) 数据存储基于 Bigtable,Bigtable 采用了不同的磁盘存储方法,但是事务层使用乐观并发。 + +如果你知道其他数据库系统使用了本文详细描述的想法,请在评论中告诉我们! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/a-complete-introduction-to-webassembly-and-its-javascript-api.md b/article/2020/a-complete-introduction-to-webassembly-and-its-javascript-api.md new file mode 100644 index 00000000000..0209d8e9141 --- /dev/null +++ b/article/2020/a-complete-introduction-to-webassembly-and-its-javascript-api.md @@ -0,0 +1,293 @@ +> * 原文地址:[A Complete Introduction to WebAssembly and It’s JavaScript API](https://blog.bitsrc.io/a-complete-introduction-to-webassembly-and-its-javascript-api-3474a9845206) +> * 原文作者:[Mahdhi Rezvi](https://medium.com/@mahdhirezvi) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/a-complete-introduction-to-webassembly-and-its-javascript-api.md](https://github.com/xitu/gold-miner/blob/master/article/2020/a-complete-introduction-to-webassembly-and-its-javascript-api.md) +> * 译者:[JohnieXu](https://github.com/JohnieXu) +> * 校对者:[samyu2000](https://github.com/samyu2000)、[plusmultiply0](https://github.com/plusmultiply0) + +# WebAssembly 及其 JavaScript API 的完整介绍 + +![[Louis Hansel @shotsoflouis](https://unsplash.com/@louishansel?utm_source=medium&utm_medium=referral) 发布于 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/10944/0*HV8EPAnwvRa8_4JH) + +自计算机诞生以来,原生应用程序的性能有了很大的提高。相比之下,由于 JavaScript 不是为了提高运行速度而发明的,因此 web 应用程序非常慢。但是,由于浏览器之间的激烈竞争以及诸如 V8 之类的 JavaScript 引擎的快速发展,使 JavaScript 能够在计算机上快速运行。但是它仍然无法超越原生应用程序的性能。其中的主要原因在于,JavaScript 代码需要经过多次编译才能生成机器代码。 + +![JS 引擎各阶段平均耗时统计 — 来自于: [Lin Clark](https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/fd3c55e9-3dda-473b-a76b-0ba4d0e039ad/08-diagram-now01-large-opt.png)](https://cdn-images-1.medium.com/max/2400/0*bGwF1hjg50k_o2C0.png) + +随着 WebAssembly 的诞生,我们所熟悉的 Web 应用程序有望发生革命性的变化。它能使 Web 应用程序运行加快。让我们看一下什么是 WebAssembly,以及如何与 JavaScript 集成以构建运行速度惊人的应用程序。 + +## 什么是 WebAssembly? + +**在理解 WebAssembly 之前,让我们先看看什么是汇编(Assembly)。** + +汇编语言是一种底层的编程语言,与底层的机器指令有非常密切的联系。换句话说, 汇编就是将这种语言转换为机器可理解的代码 (称为机器码) 的一个过程。 + +**WebAssembly** 可以通俗地理解为在 web 应用程序中使用的汇编语言。它是一种低级的类似汇编的语言,具有紧凑的二进制格式,使您能够以接近原生的速度运行 web 应用程序。它还为诸如 C、C++ 和 Rust 之类的语言提供了编译目标,从而使客户端应用程序能够以近乎原生的性能在 web 上运行。 + +此外,WebAssembly 的初衷是与 JavaScript 协同运行,而不是替换它。使用 WebAssembly JavaScript API,你的应用程序既可凭借 WebAssembly 获得优良性能,又可使用 JavaScript 实现多功能、多兼容性。这开启了 web 应用程序的全新篇章,一些原来不能用于 Web 系统的代码和功能如今也可以运行在 Web 系统上。 + +## WebAssembly 有何不同 + +[Lin Clark](https://www.smashingmagazine.com/author/linclark/) 预测,于 2017 年推出的 WebAssembly 可能会使 Web 开发进入一个拐点。它是在现代浏览器引入 JIT 编译器之后发生的,由于 JIT 将 JavaScript 的速度提高了近10倍,JIT 的引入也是一个拐点。 + +![JavaScript 性能统计 — 来自于: [Lin Clark](https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/f5961531-2863-4e2a-afac-a3fafd927aa2/03-perf-graph10-large-opt.png)](https://cdn-images-1.medium.com/max/2400/0*Py-XN25Ym7msk12v.png) + +如果仔细比较 JavaScript 与 WebAssembly 代码编译的过程,你应该可以注意到 WebAssembly 的编译过程中有几个过步骤被剥离了出来,同时还有几个步骤被去掉了。下面是两个编译过程的对比。 + +![JS 代码编译与 WebAssembly 代码编译过程大致对比 — 来自于: [Lin Clark](https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/01483767-04a0-4438-be58-f7e6512f1b39/10-diagram-future01-large-opt.png)](https://cdn-images-1.medium.com/max/2400/0*A4PPwrXlDXzU4rpL.png) + +如果仔细比较以上两个过程,您会注意到 WebAssembly 中的重新优化部分已被完全剥离。这主要是因为编译器不需要对 WebAssembly 代码做出任何假设,因为代码中诸如数据类型等需要明确定义的东西已经明确定义了。 + +但是 JavaScript 并非如此,因为 JIT 应该做出假设来运行代码,如果假设失败,它应该重新优化其代码。 + +## 如何获取 WebAssembly 代码 + +接下来的才是开发者要面临的最重要的问题。WebAssembly 是一项非常伟大的技术,那开发者应该如何充分使用它的能力呢? + +有如下几种使用方法。 + +* 从头开始编写 WebAssembly 代码——除非您非常了解基础知识,否则不建议这样做。 +* 从 C 编译到 WebAssembly +* 从 C++ 编译到 WebAssembly +* 从 Rust 编译到 WebAssembly +* 使用 [AssemblyScript](https://github.com/AssemblyScript/assemblyscript) 将严格变体版的 Typescript 编译到 WebAssembly。对于不熟悉 C/C++ 或 Rust 的 web 开发人员来说,这是一个很不错的选择。 +* 同时还支持更多的语言编译可供选择,下面将会讲到。 + +此外,还有一些工具,例如 [Emscripten](https://emscripten.org/) 和 [WebAssembly Studio](https://webassembly.studio/) 可以帮助完成上述代码编译的过程。 + +## JavaScript 的 WebAssembly API + +为了充分利用 WebAssembly 的特性,我们必须将其与 JavaScript 代码集成。这可以借助 JavaScript WebAssembly API 来实现。 + +#### 模块编译和实例化 + +WebAssembly 代码位于后缀名为 `.wasm` 的文件中,这个文件需要在客户端被编译至相应系统对应的机器码。可以通过 `WebAssembly.compile` 方法来编译 WebAssembly 模块。接收到编译好的 WebAssembly 模块后可以使用 `WebAssembly.instantiate` 方法来将其实例化。或者,也可以通过将获取到的 `.wasm` 文件内容转换为 ArrayBuffer 并传递至 `WebAssembly.instantiate` 的方式来进行实例化。 + +```js +let exports; + +fetch('sample.wasm').then(response => + response.arrayBuffer(); +).then(bytes => + WebAssembly.instantiate(bytes); +).then(results => { + exports = results.instance.exports; +}); +``` + +上述方法有一个缺点是:因 `WebAssembly.instantiate` 方法不能直接访问字节码,因此需要将获取的模块文件内容转换为 `ArrayBuffer` 再进行编译、实例化操作。 + +还有另外一种方法,使用 `WebAssembly.compileStreaming` 和 `WebAssembly.instantiateStreaming` 方法来实现上面编译、实例化的功能,这种方式的优点是能够直接访问字节码,而无需先将文件内容转换为 `ArrayBuffer`。 + +```js +let exports; + +WebAssembly.instantiateStreaming(fetch('sample.wasm')) +.then(obj => { + exports = obj.instance.exports; +}) +``` + +值得注意的是,上述两种实例化 WebAssembly 模块的方法都会返回编译好的模块实例对象,以便快速启动模块实例。 + +```js +let exports; +let compiledModule; + +WebAssembly.instantiateStreaming(fetch('sample.wasm')) +.then(obj => { + exports = obj.instance.exports; + //access compiled module + compiledModule = obj.module; +}) +``` + +#### 导入对象(Import Object) + +完成 WebAssembly 模块实例化后,可以向模块实例传入一个导入对象(Import Object),这个导入对象的属性值可以是以下 4 种类型。 + +* 全局变量(Globals) +* 函数(Function) +* 内存(Memory) +* 表(Table) + +导入对象可以理解为是向模块实例上附加的一系列用于实现特定功能的辅助工具方法,如果未提供导入对象,编译器将会分配默认值。 + +#### 全局变量(Globals) + +使用 WebAssembly 可以创建全局变量,这些全局变量可以在 JavaScript 和 WebAssembly 模块中访问。并且可以导入、导出这些变量,同时可以在一个或多个 WebAssembly 模块实例中使用它们。 + +可以使用构造函数 `WebAssembly.Global()` 来创建全局变量实例。 + +```js +const global = new WebAssembly.Global({ + value: 'i64', + mutable: true +}, 20); +``` + +该构造函数接收两个参数,分别是: + +* 第一个参数是一个对象,其 value 属性表示表示值的类型,其 mutable 属性表示值是否可以修改,允许的值类型有:`i32`、`i64`、`f32` 和 `f64`; +* 第二个参数是变量的值,其值的类型必须与第一个参数中指定的类型一致,例如:如果参数一中类型是 `i32`,则值的类型必须是 32 位整型,如果参数一中类型是 `f64`,则值的类型必须是 64 位浮点型。 + +```js +const global = new WebAssembly.Global({ + value: 'i64', + mutable: true +}, 20); + +let importObject = { + js: { + global + } +}; + +WebAssembly.instantiateStreaming(fetch('global.wasm'), importObject) +``` + +**上面创建的全局对象实例必须通过 `WebAssembly.instantiateStreaming` 或 `WebAssembly.instantiate` 方法传入到 WebAssembly 实例对象的导入对象上,才能确保 WebAssembly 实例对象可以正确访问。** + +#### 内存(Memory) + +WebAssembly 模块对象在实例化过程时需要通过导入对象传递一个已经分配好内存空间的对象。如果不传递这么一个对象,JIT 在编译时将会自动传入默认内存对象。 + +传入的内存对象也可以是 `ArrayBuffer`,这样就可以通过索引值轻松访问存储的内存值。因此,通过内存对象传递的数据值可以在 JavaScript 和 WebAssembly 之间共享。 + +#### 表(Table) + +表是位于 WebAssembly 内存之外的一种可变长度的数组型数据,表存储的值是对数据的引用(指针)。看起来与内存对象(Memory)很相似,两者最大的区别在于内存对象存储的数据是原始字节,而表存储的内存数据的指针。 + +表(Table)这种 WebAssembly 数据结构的引入是为了提高运行时的安全性。 + +可以使用 `set()`、`grow()` 和 `get()` 方法来操作表。 + +## 一个示例 + +下面我将使用 WebAssembly Studio 创建的一个应用编译为 `.wasm` 文件,来演示如何使用 WebAssembly,你也可以在线查看这个 [demo](https://webassembly.studio/?f=wne209a6cxq)。 + +这里创建了对数字进行幂运算的函数,这个函数需要先传入一个值,然后在 JavaScript 程序中接收输出结果。 + +在 wasm(译者注:此处 wasm 指的是上文 WebAssembly 的实例,下同)中对字符串进行操作时需要额外注意了。wasm 里面不存在字符串(string)这一数据类型,字符串在 wasm 里面采用 ASCII 码来处理。传递给 JavaScript 的是存储计算结果的内存地址。另外,由于内存对象是 `ArrayBuffer`,因此需要对齐其进行遍历来转换为字符串。 + +**JavaScript 文件** + +```js +let exports; +let buffer; +(async() => { + let response = await fetch('../out/main.wasm'); + let results = await WebAssembly.instantiate(await response.arrayBuffer()); + // 或者 + // let results = await WebAssembly.instantiateStreaming(fetch('../out/main.wasm')); + let instance = results.instance; + exports = instance.exports; + buffer = new Uint8Array(exports.memory.buffer); + + findPower(5,3); + + printHelloWorld(); + +})(); + +const findPower = (base = 0, power = 0) => { + console.log(exports.power(base,power)); +} + +const printHelloWorld = () => { + let pointer = exports.helloWorld(); + let str = ""; + for(let i = pointer;buffer[i];i++){ + str += String.fromCharCode(buffer[i]); + } + console.log(str); +} +``` + +**C 文件** + +```c +#define WASM_EXPORT __attribute__((visibility("default"))) +#include + + +WASM_EXPORT +double power(double number,double power_value) { + return pow(number,power_value); +} + +WASM_EXPORT +char* helloWorld(){ + return "hello world"; +} +``` + +## 使用场景 + +WebAssembly 的诞生打开了另一个充满各种可能性的世界。 + +* **赋给了 web 环境使用 c、C++ 等语言开发的现成库或者项目的能力** + +比如,如果找不到某个功能的 JavaScript 版本实现,以前没有 WebAssembly,你需要从头开始变成,使用 JavaScript 来实现这个功能。而现在,如果能找到别的语言实现这一功能的库,则可以借助 WebAssembly 的能力直接复用这个库。从技术开发的角度来看,这会大幅度节省开发时间,带来巨大的突破。 + +[Squoosh](https://squoosh.app/) 应用采用 WebAssembly 实现了二维码和图片识别功能,应用程序因此也能在低版本浏览器中以接近原生的速度运行。另外,[eBay](https://tech.ebayinc.com/engineering/webassembly-at-ebay-a-real-world-use-case/) 也通过编译原有的 C++ 库至 WebAssembly 从而实现了条码扫描功能。 + +* **对现有的 C、C++ 项目稍作修改就可以让其运行在 web 环境,并且同时拥有接近原生的速度** + +像 [AutoCAD](https://www.autodesk.com/products/autocad-web-app/overview?linkId=68719474)、[QT](https://www.qt.io/qt-examples-for-webassembly) 以及 [Google Earth](https://medium.com/google-earth/earth-on-web-the-road-to-cross-browser-7338e0f46278) 这些应用简单修改现有代码库就可以凭借接近原生的性能运行在 web 端,这些最终都要归功于 WebAssembly 的能力。 + +* **由 C、C++ 或 Rust 等语言开发的库可以借助 WebAssembly 来编译至 web 端可运行的库,即使相应的库可能已有 JavaScript 版本的实现,但是通过编译至 WebAssembly 来运行,应用的运行速度将加快并且可以具有更好的性能** + +谷歌团队曾在 [Squoosh](https://squoosh.app/) 应用中将类似 C 或 C++ 开发的 JPEG、MozJPEG 等解码器编译成了 WebAssembly 版本,替换了之前的解码器。编译之后的解码器在不牺牲图片质量的情况下,进一步缩减了图片文件的体积。 + +#### 支持的编程语言 + +不仅仅只有 C、C++ 或 Rust 语言支持编译至 WebAssembly,许多其他语言正在积极努力地争取支持 WebAssembly 编译。以下是当前支持编译 WebAssembly 的编程语言列表。 + +* C/C++ +* [Rust](https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm) +* [AssemblyScript (类似 TypeScript 语法)](https://docs.assemblyscript.org/) +* [C#](https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-3.1&tabs=visual-studio) +* [F#](https://fsbolero.io/docs/) +* [Go](https://golangbot.com/webassembly-using-go/) +* [Kotlin](https://kotlinlang.org/docs/reference/native-overview.html) +* [Swift](https://swiftwasm.org/) +* [D](https://wiki.dlang.org/Generating_WebAssembly_with_LDC) +* [Pascal](https://wiki.freepascal.org/WebAssembly/Compiler) +* [Zig](https://ziglang.org/documentation/master/#WebAssembly) + +--- + +## 不足之处 + +WebAssembly 使得程序可以直接执行编译好的二进制文件,这同时也引入了很多安全性的问题。例如,这个例子——[漏洞可以被利用](vulnerabilities can be exploited](vulnerabilities can be exploited](https://www.virusbulletin.com/virusbulletin/2018/10/dark-side-webassembly/)的问题就很难被发现,甚至都无法通过栈进行跟踪。尽管 WebAssembly 本身已经做了部分安全性功能,但我个人认为这个功能都还不够,还需要进一步改进。使用这些新的功能将导致传统的防护层(如防病毒和 URL 过滤等)失效。如果不能解决这些问题,意味着在未来这些普通浏览器的安全性将大大降低。 + +你可以阅读下面的文章了解更多关于 WebAssembly 安全性的问题。 + +- [WebAssembly 黑暗的一面](https://www.virusbulletin.com/virusbulletin/2018/10/dark-side-webassembly/) +- [wasm 安全性的担忧](https://securityboulevard.com/2020/01/research-more-worries-with-wasm-3/) +- [官方的完全性说明](https://webassembly.org/docs/security/) + +## 总结一下 + +虽然网上有炒作说 WebAssembly 即将替代 JavaScript,但是我不赞成 JavaScript 将被替代的这种说法。WebAssembly 的诞生是为了同 JavaScript 一同协作的,而非替代 JavaScript。此外,调试 JavaScript 代码比调试 WebAssembly 代码容易得多,并且 JavaScript 的那些自由灵活的语法在 WebAssembly 中是不支持的。 + +众望所归,可以毫不保留地说 WebAssembly 的出现将会给更多类型的 web 应用开发铺平道路。 + +> “虽然无法预测这些性能上的提升能促使哪些新应用诞生,但是只要现在或过去稍有一丝迹象,未来一定会令我们惊喜。” —— Lin Clark + +## 参考文章 + +- [An Abridged Cartoon Introduction To WebAssembly by Lin Clark](https://www.smashingmagazine.com/2017/05/abridged-cartoon-introduction-webassembly/) +- [Creating a WebAssembly module instance with JavaScript by Lin Clark](https://hacks.mozilla.org/2017/07/creating-a-webassembly-module-instance-with-javascript/) +- [Memory in WebAssembly by Lin Clark](https://hacks.mozilla.org/2017/07/memory-in-webassembly-and-why-its-safer-than-you-think/) +- [WebAssembly table imports… what are they? by Lin Clark](https://hacks.mozilla.org/2017/07/webassembly-table-imports-what-are-they/) +- [WebAssembly Official Website](https://webassembly.org/) +- [Google IO 2019 — WebAssembly for Web Developers](https://www.youtube.com/watch?v=njt-Qzw0mVY) +- [MDN Docs — WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) +- [MDN Docs — WebAssembly JavaScript API](https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/a-comprehensive-guide-to-slices-in-golang.md b/article/2020/a-comprehensive-guide-to-slices-in-golang.md new file mode 100644 index 00000000000..5c647cbef18 --- /dev/null +++ b/article/2020/a-comprehensive-guide-to-slices-in-golang.md @@ -0,0 +1,424 @@ +> * 原文地址:[A Comprehensive Guide to Slices in Golang](https://codeburst.io/a-comprehensive-guide-to-slices-in-golang-bacebfe46669) +> * 原文作者:[Radhakishan Surwase](https://medium.com/@rksurwase) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/a-comprehensive-guide-to-slices-in-golang.md](https://github.com/xitu/gold-miner/blob/master/article/2020/a-comprehensive-guide-to-slices-in-golang.md) +> * 译者:[JalanJiang](http://jalan.space/) +> * 校对者:[Emin](https://github.com/Eminlin),[Samuel Jie](https://github.com/suhanyujie) + +# Golang 切片综合指南 + +![由于 [Paweł Czerwiński](https://unsplash.com/@pawel_czerwinski) 拍摄于 [Unsplash](https://unsplash.com/s/photos/array)](https://cdn-images-1.medium.com/max/12000/1*i7lsjZyVnJxDEIg8Qibdlw.jpeg) + +在这篇文章中,我们将复习「切片」的概念,它是 Golang 中一个重要的数据结构,这一数据结构为你提供了处理与管理数据集合的方法。切片是围绕着动态数组的概念构建的,它与动态数组相似,可以根据你的需要而伸缩。 + +* 就增长而言,切片是**动态**的,因为它们有自己的内置函数 **append**,可以快速高效地增长切片。 +* 你还可以通过切割底层内存来减少切片的大小。 +* 在底层内存中切片是在连续的块上分配的,因此切片为你提供的便利之处包括:索引、迭代与垃圾回收优化。 + +#### 切片的表示 + +* 切片不存储任何数据,它仅描述底层数组的一部分。 +* 切片使用一个包含三个字段的结构表示:指向底层数组的指针(pointer)、长度(length)与容量(capacity)。 +* 这个数据结构类似于切片的描述符。 + +![图 1:切片的表示](https://cdn-images-1.medium.com/max/2000/1*PW4Y8P0_gTspgYwcxfDrtQ.png) + +* **指针(Pointer):**指针用于指向数组的第一个元素,这个元素可以通过切片进行访问。在这里,指向的元素不必是数组的第一个元素。 +* **长度(Length):**长度代表数组中所有元素的总数。 +* **容量(Capacity):**容量表示切片可扩展的最大大小。 + +#### 使用长度声明一个切片 + +在声明切片过程中,当你仅指定长度(Length)时,容量(Capacity)值与长度(Length)值相同。 + +![图 2:使用长度声明一个切片。](https://cdn-images-1.medium.com/max/2000/1*5ssbGNTliiFWF_rcxN6RRg.png) + +```Go +// 使用长度声明一个切片。创建一个整型切片。 +// 长度和容量均为 5。 +slice := make([]int, 5) +fmt.Println(len(slice)) // 打印结果 5 +fmt.Println(cap(slice)) // 打印结果 5 +``` + +#### 使用长度和容量声明一个切片 + +在声明切片过程中,当你分别指定长度(Length)和容量(Capacity)时,这将初始化一段无法访问的底层数组来创建一个具有可用容量的切片。 + +```Go +/* + 使用长度和容量声明一个切片 + 创建一个整型切片。 + 长度为 3,容量为 5 。 +*/ +slice := make([]int, 3, 5) +fmt.Println(len(slice)) // 打印结果 3 +fmt.Println(cap(slice)) // 打印结果 5 +``` + +![图 3:使用长度和容量声明一个切片。](https://cdn-images-1.medium.com/max/2000/1*6OLPqO2Z2x-QKPU_9EDA2A.png) + +但请注意,尝试创建容量小于长度的切片是不允许的。 + +#### 使用切片字面量创建切片 + +创建**切片**的惯用方法是使用**切片字面量**。它与创建数组相似,只是它不需要在 [ ] 操作符中指定值。你初始化切片时所用元素的数量将决定切片的初始长度与容量。 + +```Go +// 创建字符串类型切片。 +// 长度与容量均为 5。 +slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"} +fmt.Println(len(slice)) // 打印结果 5 +fmt.Println(cap(slice)) // 打印结果 5 +// 创建一个整型切片。 +// 长度与容量均为 3。 +intSlice:= []int{10, 20, 30} +fmt.Println(len(intSlice)) // 打印结果 3 +fmt.Println(cap(intSlice)) // 打印结果 3 +``` + +#### 声明一个带有索引位置的切片 + +当使用切片**字面量**时,你可以初始化切片的**长度**与**容量**。你所需要做的就是初始化表示所需长度和容量的**索引**。下面的语法将创建一个长度和容量均为 100 的切片。 + +```Go +// 创建字符串类型切片。 +// 用空字符串初始化第 100 个元素。 +slice := []int{99: 88} +fmt.Println(len(slice)) +// 打印结果 100 +fmt.Println(cap(slice)) +// 打印结果 100 +``` + +![图 4: 声明一个带有索引位置的切片。](https://cdn-images-1.medium.com/max/2000/1*nG722TP5WDx3hZOHBpcFyQ.png) + +#### 声明数组与切片的区别 + +* 如果你使用 [ ] 操作符中指定一个值,那么你在创建一个数组。 +* 如果你不在 [ ] 中指定值,则创建一个切片。 + +```Go +// 创建一个包含 3 个整数的数组。 +array := [3]int{10, 20, 30} + +// 创建一个长度和容量均为 3 的整型切片。 +slice := []int{10, 20, 30} + +``` + +#### 声明一个 nil 切片 + +* 切片用 `nil` 代表零值。 +* 一个 nil 切片的长度和容量等于 0,且没有底层数组。 + +```Go +// 创建一个整型 nil 切片。 +var slice []int32 +fmt.Println(slice == nil) +// 此行将打印 true +fmt.Println(len(slice)) +// 此行将打印 0 +fmt.Println(cap(slice)) +// 此行将打印 0 +``` + +![图 5:声明 nil 切片。](https://cdn-images-1.medium.com/max/2000/1*2KWa4gM4_M_47eBcKISK9w.png) + +#### 声明一个空切片 + +还可以通过初始化声明切片创建一个空切片。 + +```Go +// 使用 make 来创建一个整型空切片。 +sliceOne := make([]int, 0) +// 使用切片字面量创建一个整型空切片。 +sliceTwo := []int{} +fmt.Println(sliceOne == nil) // 这将打印 false +fmt.Println(len(sliceOne)) // 这将打印 0 +fmt.Println(cap(sliceOne)) // 这将打印 0 +fmt.Println(sliceTwo == nil) // 这将打印 false +fmt.Println(len(sliceTwo)) // 这将打印 0 +fmt.Println(cap(sliceTwo)) // 这将打印 0 +``` + +![图 6:声明一个空切片。](https://cdn-images-1.medium.com/max/2000/1*x3dfcqD71X5M0G2F4D7QoQ.png) + +#### 为任何特定索引赋值 + +要修改单个元素的值,请使用 [ ] 操作符。 + +```Go +// 创建一个整型切片。 +// 包含 4 个元素的长度和容量。 +slice := []int{10, 20, 30, 40} +fmt.Println(slice) // 这将打印 [10 20 30 40] +slice[1] = 25 // 改变索引 1 的值。 +fmt.Println(slice) // 这将打印 [10 25 30 40] +``` + +![图 7:为任何特定索引赋值。](https://cdn-images-1.medium.com/max/2000/1*E-LTi2XYMjW0m5RGwzfktQ.png) + +#### 对切片进行切片 + +我们之所以称呼切片为切片,是因为你可以通过对底层数组的一部分进行切片来创建一个新的切片。 + +```Go +/* 创建一个整型切片。 +长度和容量均为 5。*/ +slice := []int{10, 20, 30, 40, 50} +fmt.Println(slice) // 打印 [10 20 30 40 50] +fmt.Println(len(slice)) // 打印 5 +fmt.Println(cap(slice)) // 打印 5 +/* 创建一个新切片。 +长度为 2,容量为 4。*/ +newSlice := slice[1:3] +fmt.Println(slice) // 打印 [10 20 30 40 50] +fmt.Println(len(newSlice)) // 打印 2 +fmt.Println(cap(newSlice)) // 打印 4 +``` + +![图 8:对切片进行切片。](https://cdn-images-1.medium.com/max/2000/1*7g5CJ002CXIEo9iQn-Dp6A.png) + +在执行切片操作之后,我们拥有两个共享同一底层数组的切片。然而,这两个切片以不同的方式查看底层数组。原始切片认为底层数组的容量为 5,但 newSlice 与之不同,对 newSlice 而言,底层数组的容量为 4。newSlice 无法访问位于其指针之前的底层数组元素。就 newSlice 而言,这些元素甚至并不存在。使用下面的方式可以为任意切片后的 newSlice 计算长度和容量。 + +#### 切片的长度与容量如何计算? + +> 切片 **slice[i:j]** 的**底层数组容量为 k** +长度(Length):j - i +容量(Capacity):k - i + +**计算新的长度和容量** + +> 切片 **slice[1:3]** 的**底层数组容量为 5** +长度(Length):3 - 1 = 2 +容量(Capacity):5 - 1 = 4 + +#### 对一个切片进行更改的结果 + +一个切片对底层数组的共享部分所做的更改可以被另一个切片看到。 + +```Go +// 创建一个整型切片。 +// 长度和容量均为 5。 +slice := []int{10, 20, 30, 40, 50} +// 创建一个新的切片。 +// 长度为 2,容量为 4。 +newSlice := slice[1:3] +// 变更新切片索引 1 位置的元素。 +// 改变了原切片索引 2 位置的元素。 +newSlice[1] = 35 +``` + +将数值 35 分配给 newSlice 的第二个元素后,该更改也可以在原始切片的元素中被看到。 + +#### 运行时错误显示索引超出范围 + +一个切片只能访问它长度以内的索引位。尝试访问超出长度的索引位元素将引发一个运行时错误。与切片容量相关联的元素只能用于切片增长。 + +```Go +// 创建一个整型切片。 +// 长度和容量均为 5。 +slice := []int{10, 20, 30, 40, 50} +// 创建一个新的切片。 +// 长度为 2,容量为 4。 +newSlice := slice[1:3] +// 变更 newSlice 索引 3 位置的元素。 +// 对于 newSlice 而言,该元素不存在。 +newSlice[3] = 45 + +/* +Runtime Exception: +panic: runtime error: index out of range +*/ +``` + +#### 切片增长 + +与使用数组相比,使用切片的优势之一是:你可以根据需要增加切片的容量。当你使用内置函数 「append」 时,Golang 会负责处理所有操作细节。 + +* 使用 append 前,你需要一个源**切片**和一个要追加的值。 +* 当你的 append 调用并返回时,它将为你提供一个更改后的新切片。 +* **append** 函数总会增加新切片的长度。 +* 另一方面,容量可能会受到影响,也可能不会受到影响,这取决于源切片的可用容量。 + +#### 使用 append 向切片追加元素 + +```Go +/* 创建一个整型切片。 + 长度和容量均为 5。 */ +slice := []int{10, 20, 30, 40, 50} + +/* 创建一个新切片。 + 长度为 2,容量为 4。*/ +newSlice := slice[1:3] +fmt.Println(len(newSlice)) // 打印 2 +fmt.Println(cap(newSlice)) // 打印 4 + +/* 向容量空间分配新元素。 + 将值 60 分配给新元素。 */ +newSlice = append(newSlice, 60) +fmt.Println(len(newSlice)) // 打印 3 +fmt.Println(cap(newSlice)) // 打印 4 +``` + +当切片的底层数组没有可用容量时,append 函数将创建一个新的底层数组,拷贝正在引用的现有值,然后再分配新值。 + +#### 使用 append 增加切片的长度和容量 + +```Go +// 创建一个整型切片。 +// 长度和容量均为 4。 +slice := []int{10, 20, 30, 40} +fmt.Println(len(slice)) // 打印 4 +fmt.Println(cap(slice)) // 打印 4 + +// 向切片追加新元素。 +// 将值 50 分配给新元素。 +newSlice= append(slice, 50) +fmt.Println(len(newSlice)) // 打印 5 +fmt.Println(cap(newSlice)) // 打印 8 +``` + +![图 9:增加切片的长度和容量](https://cdn-images-1.medium.com/max/2000/1*GeiklLBspOlv_qxzw5GCVA.png) + +在 append 操作后,newSlice 被给予一个自有的底层数组,该底层数组的容量是原底层数组容量的两倍。在增加底层数组容量时,append 操作十分聪明。举个例子,当切片的容量低于 1,000 个元素时,容量增长总是翻倍的。一旦元素的数量超过 1,000 个,容量就会增长 1.25 倍,即 25%。随着时间的推移,这种增长算法可能会在 Golang 中发生变化。 + +更改新切片不会对旧切片产生任何影响,因为新切片现在有一个不同的底层数组,它的指针指向一个新分配的数组。 + +#### 将一个切片追加到另一个切片中 + +内置函数 **append** 还是一个 **可变参数** 函数。这意味着你可以传递多个值来追加到单个切片中。如果你使用 … 运算符,可以将一个切片的所有元素追加到另一个切片中。 + +```Go +// 创建两个切片,使用两个整型元素初始化每个切片。 +slice1:= []int{1, 2} +slice2 := []int{3, 4} +// 合并两个切片并打印结果。 +fmt.Println(append(slice1, slice2...)) +// 输出:[1 2 3 4] +``` + +#### 对切片执行索引 + +* 通过指定一个下限和一个上限来形成切片,例如:`a[low:high]`。这将选择一个半开范围,其中包含切片的第一个元素,但不包含切片的最后一个元素。 +* 你可以省略上限或下限,这将使用它们的默认值。下限的默认值是 0,上限的默认值是切片的长度。 + +```Go +a := [...]int{0, 1, 2, 3} +// 一个数组 +s := a[1:3] +// s == []int{1, 2} +// cap(s) == 3 +s = a[:2] +// s == []int{0, 1} +// cap(s) == 4 +s = a[2:] +// s == []int{2, 3} +// cap(s) == 2 +s = a[:] +// s == []int{0, 1, 2, 3} +// cap(s) == 4 +``` + +#### 遍历切片 + +Go 有一个特殊的关键字 **range**,你可以使用该关键字对切片进行遍历。 + +```Go +// 创建一个整型切片。 +// 长度和容量均为 4。 +slice := []int{10, 20, 30, 40} +// 遍历每个元素并打印值。 +for index, value := range slice { + fmt.Printf("Index: %d Value: %d\n", index, value) +} +/* +输出: +Index: 0 Value: 10 +Index: 1 Value: 20 +Index: 2 Value: 30 +Index: 3 Value: 40 +*/ +``` + +* 在遍历切片时,关键字 range 将返回两个值。 +* 第一个值是索引下标,第二个值是索引位中值的副本。 +* 一定要知道 range 是在复制值,而不是返回值的引用。 + +```Go +/* + 创建一个整型切片。 + 长度与容量均为 4。 +*/ +slice := []int{10, 20, 30, 40} +/* + 遍历每个元素并打印 + 元素的值和地址。 +*/ +for index, value := range slice { + fmt.Printf("Value: %d Value-Addr: %X ElemAddr: %X\n", + value, &value, &slice[index]) +} +/* +Output: +Value: 10 Value-Addr: 10500168 ElemAddr: 1052E100 +Value: 20 Value-Addr: 10500168 ElemAddr: 1052E104 +Value: 30 Value-Addr: 10500168 ElemAddr: 1052E108 +Value: 40 Value-Addr: 10500168 ElemAddr: 1052E10C +*/ +``` + +**range** 关键字提供元素的拷贝。 + +如果你不需要下标值,你可以使用下划线字符丢弃该值。 + +```Go +// Create a slice of integers. +// Contains a length and capacity of 4 elements. +slice := []int{10, 20, 30, 40} +// Iterate over each element and display each value. +for _, value := range slice { + fmt.Printf("Value: %d\n", value) +} +/* +Output: +Value: 10 +Value: 20 +Value: 30 +Value: 40 +*/ +``` + +关键字 **range** 总是从开始处遍历一个切片。如果你需要对切片的迭代进行更多的控制,你可以使用传统的 **for** 循环。 + +```Go +// 创建一个整型切片。 +// 长度和容量均为 4。 +slice := []int{10, 20, 30, 40} +// 从元素 30 开始遍历每个元素。 +for index := 2; index < len(slice); index++ { + fmt.Printf("Index: %d Value: %d\n", index, slice[index]) +} +/* +输出: +Index: 2 Value: 30 +Index: 3 Value: 40 +*/ +``` + +#### 总结 + +在本文中,我们深入探讨了切片的概念。我们了解到,切片并不存储任何数据,而是描述了底层数组的一部分。我们还看到,切片可以在底层数组的范围内增长和收缩,并配合索引可作为数组使用;切片的零值是 nil;函数 **len**、**cap** 和 **append** 都将 **nil** 看作一个长度和容量都为 0 的**空切片**;你可以通过**切片字面量**或调用 **make** 函数(将长度和容量作为参数)来创建切片。希望这些对你有所帮助! + +**免责声明** + +我参考了各种博客、书籍和媒体故事来撰写这篇文章。如有任何疑问,请在评论中与我联系。 + +**到此为止……开心编码……快乐学习😃** + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/a-high-level-overview-of-load-balancing-algorithms.md b/article/2020/a-high-level-overview-of-load-balancing-algorithms.md new file mode 100644 index 00000000000..89a75679d17 --- /dev/null +++ b/article/2020/a-high-level-overview-of-load-balancing-algorithms.md @@ -0,0 +1,82 @@ +> * 原文地址:[A High-Level Overview of Load Balancing Algorithms](https://medium.com/better-programming/a-high-level-overview-of-load-balancing-algorithms-8c7d3368276) +> * 原文作者:[Aastikta Sharma](https://medium.com/@aastiktasharma) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/a-high-level-overview-of-load-balancing-algorithms.md](https://github.com/xitu/gold-miner/blob/master/article/2020/a-high-level-overview-of-load-balancing-algorithms.md) +> * 译者:[jackwener](https://github.com/jackwener) +> * 校对者:[lsvih](https://github.com/lsvih),[zenblo](https://github.com/zenblo) + +# 简述网络层与应用层的负载均衡算法 + +![Photo by [Martin Sanchez](https://unsplash.com/@martinsanchez?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/12000/0*5Q1kzxdcs6WZv19y) + +## 负载均衡的简介 + +**负载平衡**是将网络负载均匀分布在多个服务器上的过程。它有助于处理流量高峰时的任务统一分配及扩大需求。服务器可以存在于云数据中心或本地。它可以是物理服务器,也可以是虚拟服务器。负载均衡器(LB)的一些主要功能包括: + +* 高效路由数据 +* 防止服务器过载 +* 检查服务器执行运行状况 +* 在面对大流量时提供新的服务器实例 + +## 负载均衡算法分类 + +在 OSI 七层模型中,负载均衡主要应用在第 4 层(传输层)到第 7 层(应用层)。 + +![](https://cdn-images-1.medium.com/max/2808/1*A9uYwKDdWjmPVEPiKzSE0A.png) + +根据流量的分布情况(譬如流量是网络层流量还是应用层流量),不同类型的负载均衡算法可以有效地分配网络流量。 + +* 负载均衡器根据TCP端口,IP底层路由网络层流量。 +* 应用层流量根据各种其他属性(如 HTTP 头,SSL)进行路由,甚至为负载均衡器提供内容交换功能。 + +## 网络层算法 + +#### 1. 轮询算法(Round-robin algorithm) + +流量负载被分配到第一个可用的服务器,然后该服务器推到队列底。如果服务器是相同的,并且没有持久的连接,这个算法可以证明是有效的。主要有两种类型的循环算法: + +* **加权轮询算法:**如果服务器容量不一样,可以用此算法分配负载。分配权重或者效率参数给池中的服务器并基于这些参数,以类似的循环方式分配负载 +* **动态轮询算法:**也可以在运行时计算分配给服务器以标识其容量的权重。动态轮询机制有助于根据运行时权重将请求发送到服务器 + +#### 2. 最少连接算法(Least-connections algorithm) + +此算法计算特定时间内每个服务器的活动连接数,并将传入流量定向到连接最少的服务器。这在需要持久连接的情况下非常有用。 + +#### 3. 加权最小连接算法(Weighted least-connections algorithm) + +这与上面的最少连接算法相似,但是除了考虑与服务器的活动连接数量外,它还考虑服务器容量。 + +#### 4. 最小响应时间算法(Least-response-time algorithm) + +这也类似于最少连接算法,但是它也考虑了服务器的响应时间。该请求以最短的响应时间发送到服务器。 + +#### 5. 哈希算法(Hashing algorithm) + +不同的请求参数决定请求将被发送到哪。基于此的不同类型的算法有: + +* **源/目的地址哈希:**源和目标 IP 地址一起哈希,确定为请求提供服务的服务器。如果连接断开,可以在重试时将同一请求重定向到同一服务器。 +* **URL 哈希:**哈希请求的 URL,此方法避免相同请求对象存储在许多缓存中,从而帮助减少服务器缓存的重复。 + +#### 6. 其他算法(Miscellaneous algorithms) + +也有一些其他的算法,如下: + +* **最小带宽算法:** 负载均衡器选择在过去 14 分钟内带宽消耗最少的服务器。 +* **最少数据包算法:** 类似上面,负载均衡器选择传输数据包数量最少的服务器以重定向流量。 +* **自定义负载算法:** 负载均衡器根据服务器上的当前负载来选择服务器,该负载可由内存,处理单元使用情况,响应时间,请求数等确定。 + +## 应用层算法 + +在这一层,可以根据请求的内容分配流量。因此,负载均衡器可以做出更明智的决定。由于它已经连接了所有从服务器来的路径,因此也可以跟踪服务器响应,这有助于更有效地确定服务器负载。 + +在此层使用的最重要的算法之一是**最少等待请求算法**。此算法将待处理的 HTTP 请求的流量定向到最可用的服务器。该算法有助于通过监视服务器负载来调整请求流量的突峰。 + +## 总结 + +这些是一些已知的负载均衡算法。在选择适用的算法时,需要考虑许多因素,例如,高流量或突然的峰值。好的算法选择有助于维持应用程序的可靠性和较高性能。因此,对这些内容有良好了解,将在设计大型分布式系统时很有帮助。。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/abstract-data-types-and-the-software-crisis.md b/article/2020/abstract-data-types-and-the-software-crisis.md new file mode 100644 index 00000000000..31ed0926b7b --- /dev/null +++ b/article/2020/abstract-data-types-and-the-software-crisis.md @@ -0,0 +1,283 @@ +> * 原文地址:[Abstract Data Types and the Software Crisis](https://medium.com/javascript-scene/abstract-data-types-and-the-software-crisis-671ea7fc72e7) +> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/abstract-data-types-and-the-software-crisis.md](https://github.com/xitu/gold-miner/blob/master/article/2020/abstract-data-types-and-the-software-crisis.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[leexgh](https://github.com/leexgh)、[landiy](https://github.com/landiy)、[lsvih](https://github.com/lsvih) + +# 抽象数据类型与软件危机 + +![Image: [MattysFlicks — Smoke Art — Cubes to Smoke](https://www.flickr.com/photos/68397968@N07/11432696204) ([CC BY 2.0](https://creativecommons.org/licenses/by/2.0/))](https://cdn-images-1.medium.com/max/4096/1*DSu4IJYOeNzJbQIip9oTVg.jpeg) + +> **注:** 这是《组合软件》系列的一部分[(现在是一本书!)](https://leanpub.com/composingsoftware)。从基础开始学 JavaScript ES6+ 函数式编程和组合软件技术。敬请关注,未完待续! +[购买此书](https://leanpub.com/composingsoftware) | [索引](https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc) | [\< 上一篇](https://medium.com/javascript-scene/abstraction-composition-cb2849d5bdd6) | [下一篇 >](https://medium.com/javascript-scene/functors-categories-61e031bac53f) + +## 抽象数据类型 + +> **不要与以下内容混淆:** +> +> **代数数据类型**(有时缩写为 ADT 或 AlgDT)。代数数据类型是指编程语言中的复杂类型(例如 Rust、Haskell、F#),这些类型表现出的特性之一是具有特定的代数结构,例如,积(product)与和(sum)类型。 +> +> **代数结构。** 代数结构是从抽象代数研究和应用而来的,抽象代数与 ADT 一样,通常也使用代数公理来进行描述,但它的应用范围却远不止计算机和代码。有些代数结构是不能在软件中完全地建模的。相比之下,抽象数据类型可以作为规范和指南来正式验证软件运行。 + +抽象数据类型(ADT)是由公理定义的抽象概念,这些公理表示数据和对该数据的操作。ADT 的定义,不在具体实例的范畴内,也不指代实现中具体的数据类型、结构或算法。相反,ADTs 对数据类型的定义,仅仅是根据数据类型的操作,和这些操作必须遵循的公理来的。 + +## 常见数据类型示例 + +* 链表(List) +* 栈(Stack) +* 队列(Queue) +* 集合(Set) +* 映射(Map) +* 流(Stream) + +ADT 可以代表对任何类型的数据的任何一组操作。换句话说,所有可能的 ADT 的穷举列表是无限的,其原因与所有可能的英语句子的穷举列表是无限的类似。ADT 是对未指定数据的一组操作的抽象概念,而不是对某特定组的具体数据的操作。一个常见的误解是,许多大学课程和数据结构教科书中讲述的 ADT 的具体示例就是 ADT。许多这样的课程和书籍将数据结构标记为“ADT”,然后跳过 ADT 并以具体的术语来描述数据结构,而从未使学生接触到数据类型的实际抽象表示。**这就糟了!** + +ADT 可以表达许多有用的代数结构,包括半群,monoid,函子,单子等。[Fantasyland 规范](https://github.com/fantasyland/fantasy-land)就是一个很实用的目录,里面的代数结构均使用ADT描述,旨在鼓励 JavaScript 中的互操作实现。可以使用提供的公理来验证库构建器的实现。 + +## 为什么要使用 ADT? + +抽象数据类型非常有用,因为它们为我们提供了一种以数学上合理且明确的方式来正式定义可重用模块的方法。这使我们可以共享一种通用语言,以引用大量有用的软件构建块词汇:学习和牢记这种理念,对我们畅游在不同领域、框架,甚至编程语言之间都会大有帮助。 + +## ADT 的发展历史 + +在 1960 年代和 1970 年代初,许多程序员和计算机科学研究人员对软件危机感兴趣。正如 Edsger Dijkstra 在他的图灵奖演讲中所说的那样: + +> “软件危机的主要原因是机器变得功能强大了几个数量级!坦率地说:只要没有机器,编程就完全没有问题。当我们有几台不够强大的计算机时,编程是一个小问题,当我们有了非常强大的计算机时,编程也成为了一个同等非常严重的问题。” + +他所指的问题是软件非常复杂。NASA 的阿波罗登月舱和制导系统的印刷版大约是文件柜的高度。如此大量的代码,想象一下试图阅读和理解其中的每一行代码的困难程度。 + +现代软件要复杂几个数量级。Facebook 在 2015 年大约有 [6200 万行代码](https://www.informationisbeautiful.net/visualizations/million-lines-of-code/)。如果每页打印 50 行,则将填满 124 万页。如果堆叠这些页面,则每英尺或 688 英尺可获得约 1800 页。这比撰写本文时所在的旧金山最高住宅大楼[千禧塔](https://en.wikipedia.org/wiki/Millennium_Tower_(San_Francisco))还要高。 + +管理软件复杂性是几乎每个软件开发人员都面临的主要挑战之一。在 1960 年代和 1970 年代,他们没有我们今天认为理所当然的程序语言、模式或工具。诸如 linters、intellisense 甚至静态分析工具之类的东西也尚未发明出来。 + +许多软件工程师指出,他们在大多数情况下构建硬件就可以正常工作。但是,软件通常是错综复杂且易出错的。软件通常是: + +* 超预算 +* 延期 +* 漏洞 +* 缺乏需求 +* 维护困难 + +要是你构思模块化的软件,那你应该无需了解整个系统即可知道如何使系统的一部分正常工作。该软件设计原理被称为局部性。为了实现局部性,您需要可以独立于系统其余部分理解的模块。您应该能够清楚地描述**模块**,而无需过多说明其实现。这就是 ADT 解决的问题。 + +从 1960 年代一直延续到今天,提高软件模块化的状态是一个核心问题。考虑到这些问题,包括 Barbara Liskov(即面向对象五大设计原则 S.O.L.I.D 中的 L - "Liskov 替换原则" 中的Liskov本人),Alan Kay,Bertrand Meyer 和其他计算机科学传奇人物一起致力于描述和指定各种工具来实现软件的模块化。分别包括 ADT、面向对象程序设计和契约式设计。 + +ADT 源自 Liskov 和她的学生在 1974 年至 1975 年之间使用 [CLU 编程语言](https://en.wikipedia.org/wiki/CLU_(programming_language))所做的工作。它们极大地促进了软件模块规范的发展(这是我们用来描述允许软件模块进行接口交互的语言)。软件接口形式上可验证的一致性,使我们向软件模块化和互通性又迈出了一大步。 + +Liskov 于 2008 年因其在数据抽象,容错和分布式计算方面的工作而获得了图灵奖。ADT 在这一成就中发挥了重要作用,如今,几乎每所大学计算机科学课程中都包含了 ADT。 + +软件危机从未完全解决,任何专业开发人员都应该熟悉上述许多问题,但是学习如何使用诸如对象、模块和 ADT 之类的工具肯定会有所帮助。 + +## ADT 的技术规范 + +可以使用几个标准来判断 ADT 规范的适用性。我称这些标准为 **FAMED**,但我只是发明了助记符。原始标准由 Liskov 和 Zilles 在 1975 年著名的论文[《数据抽象的规范技术》](http://csg.csail.mit.edu/CSGArchives/memos/Memo-117.pdf)中发表。 + +* **正式。** 规范必须是正式的。规范中每个元素的含义必须定义得足够详细,以使目标受众有相当大的机会从规范中构建符合的实现。对于规范中的每个公理,必须有在代码中实现的代数证明。 +* **通用。** ADT 应该广泛适用。ADT 通常应可用于许多不同的具体用例。在代码的特定部分中以特定语言描述特定的实现,这样的 ADT 可能过分具体了。相反,ADT 最适合描述公共数据结构、库组件、模块、编程语言功能等的行为。例如,用 ADT 描述堆栈的操作,或用 ADT 描述 promise 的表现。 +* **最小化。** ADT 规范应最小化。规范应该包括行为中有趣且广泛适用的部分,仅此而已。每种行为都应准确无误地加以描述,但应尽可能少地具体描述。大多数 ADT 规范应使用少量公理来证明。 +* **可扩展。** ADT 应该是可扩展的。需求的微小变化应该只会导致规范的微小变化。 +* **声明式的。** 声明性规范描述的是是什么,而不是怎么做。ADT 应定义事物是什么,以及输入和输出之间的关系映射,而不是创建数据结构的步骤,或每个操作必须执行的具体步骤。 + +好的 ADT 应该具备以下几点: + +* **通俗易懂的描述。** 如果 ADT 没有附带一些易于理解的描述,它们可能会非常简洁。自然语言描述与代数定义相结合,可以相互检查,以清除规范中的任何错误或读者对其理解的歧义。 +* **定义。** 明确定义本规范中使用的任何术语,以避免产生歧义。 +* **抽象特征。** 描述预期的输入和输出,而不将其链接到具体的类型或数据结构。 +* **公理。** 公理不变量的代数定义常常证明了某实现已符合了规范要求。 + +## 堆栈 ADT 示例 + +堆栈是后进先出(LIFO)的项目,它允许用户通过将新项目推入堆栈顶部或从堆栈顶部弹出最近推送的项目来与堆栈进行交互。 + +堆栈通常用于解析、排序和数据整理算法中。 + +## 堆栈定义 + +* `a`:任意类型 +* `b`:任意类型 +* `item`:任意类型 +* `stack()`:空堆栈 +* `stack(a)`:含有一个元素 `a` +* `[item, stack]`:`item` 和 `stack` 成对出现 + +## 抽象签名 + +#### 构造函数 + +该栈操作接受任意数量的项目,并返回这些项目的堆栈。通常,构造函数的抽象签名是根据自身定义的。请不要将此与递归函数混淆。 + +* stack(...items) => stack(...items) + +#### 堆栈操作(返回堆栈的操作) + +* push(item, stack()) => stack(item) +* `pop(stack) => [item, stack]` + +## 公理 + +堆栈公理主要处理堆栈和项目标识,堆栈项目的顺序以及堆栈为空时的弹出行为。 + +#### 特性 + +入栈和出栈操作没有副作用,如果做入栈操作并立即从同一堆栈进行出栈操作,则堆栈应处于入栈之前的状态。 + +```js +pop(push(a, stack())) = [a, stack()] +``` + +* 给定:推入 `a` 进堆栈并立即从堆栈中弹出。 +* 结果:返回一对 `a` 和 `stack()`。 + +#### 顺序 + +从堆栈中弹出应该遵循以下顺序:后进先出(LIFO)。 + +```js +pop(push(b, push(a, stack()))) = [b, stack(a)] +``` + +* 给定:推入 `a` 进堆栈,然后推入 `b` 进堆栈,然后从堆栈弹出。 +* 结果:返回一对 `b` 和 `stack()`。 + +#### 空栈 + +从空堆栈弹出会导致未定义的项目值。具体来说,可以用 Maybe(item),Nothing 或 Either 定义。在 JavaScript 中,习惯使用 `undefined`,从空堆栈弹出不会更改堆栈。 + +```js +pop(stack()) = [undefined, stack()] +``` + +* 给定:从空堆栈弹出。 +* 结果:返回一对 undefined 和 `stack()`。 + +## 具体实现 + +抽象数据类型可以有许多具体的实现,可以使用不同的语言,库,框架等。这是上述堆栈 ADT 的一种实现,使用封装的对象以及该对象上的纯函数: + +```js +const stack = (...items) => ({ + push: item => stack(...items, item), + pop: () => { + // 创建项目列表 + const newItems = [...items]; + + // 从列表中移除最后一项 + // 把它赋给变量 + const [item] = newItems.splice(-1); + + // 成对返回 + return [item, stack(...newItems)]; + }, + // 可以在 assert 函数中比较堆栈 + toString: () => `stack(${ items.join(',') })` +}); + +const push = (item, stack) => stack.push(item); +const pop = stack => stack.pop(); +``` + +另一个以纯函数的形式是在 JavaScript 现有数组类型上实现堆栈操作: + +```js +const stack = (...elements) => [...elements]; + +const push = (a, stack) => stack.concat([a]); + +const pop = stack => { + const newStack = stack.slice(0); + const item = newStack.pop(); + return [item, newStack]; +}; +``` + +两种版本均满足以下公理证明: + +```js +// 一个简单的 assert 函数 +// 将显示公理测试结果 +// 若不满足公理,则会抛出描述性错误 +const assert = ({given, should, actual, expected}) => { + const stringify = value => Array.isArray(value) ? + `[${ value.map(stringify).join(',') }]` : + `${ value }`; + + const actualString = stringify(actual); + const expectedString = stringify(expected); + + if (actualString === expectedString) { + console.log(`OK: + given: ${ given } + should: ${ should } + actual: ${ actualString } + expected: ${ expectedString } + `); + } else { + throw new Error(`NOT OK: + given ${ given } + should ${ should } + actual: ${ actualString } + expected: ${ expectedString } + `); + } +}; + +// 传递具体值给函数 +const a = 'a'; +const b = 'b'; + +// 证明 +assert({ + given: 'push `a` to the stack and immediately pop from the stack', + should: 'return a pair of `a` and `stack()`', + actual: pop(push(a, stack())), + expected: [a, stack()] +}) + +assert({ + given: 'push `a` to the stack, then push `b` to the stack, then pop from the stack', + should: 'return a pair of `b` and `stack(a)`.', + actual: pop(push(b, push(a, stack()))), + expected: [b, stack(a)] +}); + +assert({ + given: 'pop from an empty stack', + should: 'return a pair of undefined, stack()', + actual: pop(stack()), + expected: [undefined, stack()] +}); +``` + +## 结论 + +* **抽象数据类型(ADT)** 是由公理定义的抽象概念,公理表示一些数据和对该数据的操作集合。 +* **抽象数据类型专注于是什么而不是怎么做**(它们以声明性的方式定义,并且未指定算法或数据结构)。 +* **常见示例**包括列表,堆栈,集合等。 +* ADT 为我们提供了一种以数学上合理,准确和明确的方式正式定义可重用模块的方法。 +* ADTs 是由 Liskov 和学生在 1970 年代使用 CLU 编程语言编写的。 +* **ADT 应该是 FAMED 的。** 正式的,广泛适用的,最小的,可扩展的和声明性的。 +* **ADT 应该包含** 人类可读的描述,定义,抽象签名以及可正式验证的公理。 + +> **温馨提示:** 如果不确定是否应该封装函数,请问自己是否要将其包含在组件的 ADT 中。请记住,ADT 应该是最小的,因此,如果它不是必需的,与其他操作缺乏凝聚力,或者其规范可能会改变,则对其进行封装。 + +## 词汇表 + +* **公理**在数学上是正确的陈述,必须成立。 +* **从数学上讲,** 合理的含义是每个术语在数学上都有很好的定义,因此可以根据它们写出明确且可证明的事实陈述。 + +## 下一步 + +[EricElliottJS.com](https://ericelliottjs.com/) 提供了几小时的视频课程和有关此类主题的互动练习。如果您喜欢此内容,请考虑加入。 + +--- + +**埃里克·埃利奥特(Eric Elliott)** 是技术产品和平台顾问,是[“组合软件系列”](https://slack-redir.net/link?url=https%3A%2F%2Fleanpub.com%2Fcomposingsoftware)的作者,是 [EricElliottJS.com](https://slack-redir.net/link?url=http%3A%2F%2FEricElliottJS.com) 和 [DevAnywhere.io](https://slack-redir.net/link?url=http%3A%2F%2FDevAnywhere.io) 的共同创始人,也是开发团队的指导者。他为 **Adobe 系统,Zumba Fitness,《华尔街日报》,ESPN,BBC 和顶级录音艺术家(包括 Usher,Frank Ocean,Metallica 等)** 的软件开发做出了贡献。 + +**他与世界上最美丽的女人一起过着清静悠闲的隐居生活。** + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/adaptive-video-with-css-math.md b/article/2020/adaptive-video-with-css-math.md new file mode 100644 index 00000000000..78385031e15 --- /dev/null +++ b/article/2020/adaptive-video-with-css-math.md @@ -0,0 +1,94 @@ +> * 原文地址:[Adaptive video with CSS Math](https://medium.com/@yokselzok/adaptive-video-with-css-math-d71640c6068a) +> * 原文作者:[Йоксель Зок](https://medium.com/@yokselzok) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/adaptive-video-with-css-math.md](https://github.com/xitu/gold-miner/blob/master/article/2020/adaptive-video-with-css-math.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[regon-cao](https://github.com/regon-cao) + +# 使用原生 CSS 实现自适应视频 + +我在研究 [CSS 数学函数](https://www.w3.org/TR/css-values-4/#calc-notation)时,曾考虑过响应式 iframe,也能找到一些现有的解决方案,例如[这个](https://css-tricks.com/fluid-width-video/),但是需要使用包装器或 JavaScript。假如没有包装器,只使用原生 CSS 能实现相同的功能吗? + +首先,我们需要获取视频的宽高比。然而无法从属性中获取视频的宽高比(此方法[存在](https://www.w3.org/TR/css-values-3/#attr-notation)于规范中,但浏览器不支持),因此需要使用自定义属性: + +```HTML + +``` + +自定义属性中的宽度和高度必须在没有 px 单位的情况下使用,否则无法处理这些值来计算视频的宽高比。 + +接着需要计算视频的宽高比: + +```css +.video { + --aspect-ratio: calc(var(--height) / var(--width)); +} +``` + +并给高度添加单位: + +```css +.video { + --aspect-ratio: calc(var(--height) / var(--width)); + --height-with-units: calc(var(--height) * 1px); +} +``` + +在移动设备上 iframe 必须适应窗口大小,为此添加以下内容: + +```css +.video { + --aspect-ratio: calc(var(--height) / var(--width)); + --height-with-units: calc(var(--height) * 1px); + + max-width: 100%; +} +``` + +最后一步有点棘手,但也不是很难。在移动设备上,iframe 会被宽度压缩。如何才能获取实际的宽度呢?如果 iframe 被拉伸到页面宽度,那么页面宽度大约等于窗口宽度,那么我们可以使用 viewport 数值来表示 iframe 的宽度,它将等于 `100vw`。使用 iframe 实际的宽度以及宽高比,就可以计算高度: + +```css +calc(100vw * var(--aspect-ratio)) +``` + +这个表达式只适用于 iframe 的宽度等于窗口宽度的移动设备。桌面应用该怎么处理呢?可以根据屏幕大小,借助 CSS 数学计算为 iframe 获取适当的高度。用 `min()` 来选择哪个高度更适合: + +```css +height: min(calc(100vw * var(--aspect-ratio)), var(--height-with-units)); +``` + +如果从 `100vw` 计算的高度大于初始高度,则 `min()` 将选择初始高度,iframe 不会增长更多。相反,如果从 `100vw` 计算的高度小于初始高度,`min()` 将选择计算高度,iframe 将被高度压缩。 + +最终的 CSS 代码: + +```CSS +.video { + /* 获取宽高比 */ + --aspect-ratio: calc(var(--height) / var(--width)); + /* 给高度添加单位 */ + --height-with-units: calc(var(--height) * 1px); + + max-width: 100%; + + /* 获取初始最小高度 + 或根据窗口宽高比来计算高度 */ + height: min(calc(100vw * var(--aspect-ratio)), var(--height-with-units)); +} +``` + +打开[**在线示例**](https://codepen.io/yoksel/pen/oNxmgYq?editors=0100)并通过调整窗口大小来查看其工作方式。 + +**注意:** 如果在预处理器(SCSS、Less)中使用以上代码,要避免在不同的计量单位下处理 `min()`。使得预处理器强制忽略 CSS 数学函数,在 SCSS 中,函数名必须以大写字母:`Min(…)` 开头;而对于 Less 函数,必须这样包装:`~”min(…)”`。 + +我没有在实际项目中使用过这个解决方案,但希望它会有用。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/applications-of-some-of-the-famous-algorithms.md b/article/2020/applications-of-some-of-the-famous-algorithms.md new file mode 100644 index 00000000000..c2b110c72f2 --- /dev/null +++ b/article/2020/applications-of-some-of-the-famous-algorithms.md @@ -0,0 +1,105 @@ +> * 原文地址:[Applications of Some of The Famous Algorithms](https://levelup.gitconnected.com/applications-of-some-of-the-famous-algorithms-cdaecee58ed1) +> * 原文作者:[Shubham Pathania](https://medium.com/@spathania08) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/applications-of-some-of-the-famous-algorithms.md](https://github.com/xitu/gold-miner/blob/master/article/2020/applications-of-some-of-the-famous-algorithms.md) +> * 译者: +> * 校对者: + +# Applications of Some of The Famous Algorithms + +![Photo by [Kaleidico](https://unsplash.com/@kaleidico?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/10804/0*d-YSolz0sbA5uAkw) + +#### Do you know the practical use cases behind learning these algorithms? + +During my college days, I started learning programming by practicing most of the famous algorithms. I never tried to understand how these algorithms can be helpful in the real world. There must be some reason why we start learning them, right? + +As a software developer, I used many of these algorithms today in my projects. It is interesting to find a practical implementation behind those algorithms that I once learning for the sake of getting a job. + +In this article, I am going to share some of the practical scenarios where we use some of these algorithms. Beginners can find it interesting to relate while learning, whereas it might refresh the memory of experienced programmers. + +--- + +Let’s take a closer look. + +## Fibonacci Sequence + +Almost every developer has gone through the algorithm for the Fibonacci series. The [Fibonacci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) is the series of numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, and 55 on to infinity. + +Have you ever wondered what could be the possible scenario in our world where we can utilize this algorithm? + +The sequence has a series of interesting properties. The sum of any two consecutive numbers equals the next highest number. Coincidentally, it works as a nearly-accurate converter between miles and kilometers. + +Consider any number in the Fibonacci sequence as miles. The next number in the sequence is approximately that same distance in kilometers. For example, 8 miles is about 13 kilometers. 13 miles is about the same as 21 kilometers. + +Among many of the features of Fibonacci sequences, investors have harnessed their power to predict **stock prices**. The most popular Fibonacci-based investment system is the [Elliot Wave Theory](https://elitecurrensea.com/education/elliott-wave-patterns-fibonacci-relationships-core-reference-guide/). + +## Palindrome Algorithm + +This is another common algorithm that is recursively asked in interviews. A palindrome is a string that reads the same forward and backward. For example — radar, toot, and madam. + +Now many of us believe what could be the possible practical implementation of this algorithm besides testing logical ability, but there’s more to it. It is useful in [DNA sequence processing](https://pubmed.ncbi.nlm.nih.gov/11700586/). + +Today, more DNA sequences are becoming available. The information about DNA sequences is stored in molecular biology databases. The size and importance of these databases will be bigger in the future. Therefore this information must be stored or communicated efficiently. + +CTW (Context Tree Weighting Method) can compress DNA sequences less than two bits per symbol. Two characteristic structures of DNA sequences are known. One is called Palindromes or reverse complements, and the other structure is approximate repeats. + +Before encoding the next symbol, the algorithm searches an approximate repeat and palindrome using hash and dynamic programming. If there is a palindrome or an approximate repeat with enough length, then our algorithm represents it with length and distance. + +## Binary Search Algorithm + +It is also known as half-interval search, logarithmic search, or binary chop, is a search algorithm that finds the position of a target value within a sorted array. + +The method is to compare the middle element with the targeted value (key element) if they are unequal. The half in which the target cannot lie is eliminated, and the search continues on the remaining half until it is successful or the remaining half is empty. + +This seems to be a quite effective method since it escapes the redundancy of going over every element and instead narrows down the searching range efficiently. + +Every programmer is taught that binary search is a good and fast way to search an ordered list of data. There are many textbook examples of using binary search, but where do we actually use it in real life? + +One practical application to this algorithm is validating user credentials in an application. You might have seen how applications with millions of users validate your credential within a fraction of seconds. That’s all possible due to the binary search. + +Binary search is used **everywhere**. Take any sorted collection from any language library (Java, .NET, C++ STL, and so on), and they all will use (or have the option to use) binary search to find values. + +## Merge Sort Algorithm + +Merge sort is a sorting technique based on the **divide and conquer** technique. It works on two basic principles: + +* Sorting a smaller list is faster than sorting a larger list. +* Combining two sorted sublists is faster than two unsorted lists. + +Merge sort is used mostly undersize constraints. + +In any e-commerce website, we usually have a section — **You might like**. They have maintained an array for all the user accounts. Whichever has the least number of inversion with our array of choices, they start recommending what they have bought or like. + +This is one of the most common implementations of merge sort in today’s world. + +## Armstrong Number + +A number is called an Armstrong number if the sum of cubes of digits of a number is equal to the number itself. + +For example, 153 is an Armstrong number as − + +``` +153 = (1)3 + (5)3 + (3)3 +153 = 1 + 125 + 27 +153 = 153 +``` + +There is no direct implementation of Armstrong number in real-world applications, but it is extensively used in security algorithms for data encryption and decryption. + +--- + +Here’s a [link to a paper](https://www.ijitee.org/download/volume-1-issue-1/) where using Armstrong numbers for wireless sensor networks are discussed. They have used Armstrong number-based security algorithm in which a 128-bit key is generated using the Armstrong number and which is used in the [AES algorithm](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) for data encryption and decryption. + +## Final thoughts + +We have seen practical use cases of some of the most commonly seen programming algorithms. Many of us have already worked on them as a beginner without much awareness of their real-world applications. + +--- + +It is a good approach to understand the benefits before learning something, as it will help us to understand the algorithm better. There are several other algorithms that we use in our day-to-day life. I would leave that up to you to find out their practical use cases. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/aspect-oriented-programming-in-javascript.md b/article/2020/aspect-oriented-programming-in-javascript.md new file mode 100644 index 00000000000..f7b9ae92150 --- /dev/null +++ b/article/2020/aspect-oriented-programming-in-javascript.md @@ -0,0 +1,175 @@ +> * 原文地址:[Aspect-Oriented Programming in JavaScript](https://blog.bitsrc.io/aspect-oriented-programming-in-javascript-c4cb43f6bfcc) +> * 原文作者:[Fernando Doglio](https://medium.com/@deleteman123) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/aspect-oriented-programming-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/article/2020/aspect-oriented-programming-in-javascript.md) +> * 译者:[Liusq-Cindy](https://github.com/Liusq-Cindy) +> * 校对者:[Chorer](https://github.com/Chorer)、[nia3y](https://github.com/nia3y) + +# JavaScript 的面向切面编程 + +![Image by [Arturs Budkevics](https://pixabay.com/users/artursfoto-3533503/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1744952) from [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1744952)](https://cdn-images-1.medium.com/max/3840/1*sfjo3NiG4oHxwXQpdqCu9g.jpeg) + +我们都知道面向对象编程,或者至少听说过 JavaScript 领域的函数式编程,但是,你听说过面向切面编程吗? + +我知道,它听起来像是《魔法战队》中某一集出现的东西。然而,AOP 是实际存在的。此外,虽然我们现在没有使用它,但它却可以被应用于我们日常会见到的一些用例中。 + +它最大的优势在于,你可以毫不费力的将 AOP 与 FP 或 OOP 结合使用,就像 JavaScript 中的 OOP 和 FP 一样。 因此,首先让我们了解这个切面的作用,以及它对 JavaScript 开发人员的实际用途。 + +## AOP 简介 + +面向切面编程给我们提供了一个方法,让我们可以在不修改目标逻辑的情况下,将代码注入到现有的函数或对象中。 + +虽然不是必须的,但注入的代码意味着具有横切关注点,比如添加日志功能、调试元数据或其它不太通用的但可以注入额外的行为,而不影响原始代码的内容。 + +给你举一个合适的例子,假设你已经写好了业务逻辑,但是现在你意识到没有添加日志代码。通常的方法是将日志逻辑集中到一个新的模块中,然后逐个函数添加日志信息。 + +然而,如果你可以获取同一个日志程序,在你想要记录的每个方法执行过程中的特定节点,只需一行代码就可将程序注入,那么这肯定会给你带来很多便利。难道不是吗? + +#### 切面、通知和切点(是什么、在何时、在何地) + +为了使上面的定义更形式化一点,让我们以日志程序为例,介绍有关 AOP 的三个概念。如果你决定进一步研究这个范式,这些将对你有所帮助: + +* **切面 (**是什么**):** 这是你想要注入到你的目标代码的 “切面” 或者行为。在我们的上下文环境(JavaScript)中,这指的是封装了你想要添加的行为的函数。 +* **通知 (**在何时**):** 你希望这个切面什么时候执行?“通知” 指定了你想要执行切面代码的一些常见的时刻,比如 “before”、“after”、“around”、“whenThrowing” 等等。反过来,它们指的是与代码执行相关的时间点。对于在代码执行后引用的部分,这个切面将拦截返回值,并可能在需要时覆盖它。 +* **切点 (**在何地**):** 他们引用了你想要注入的切面在你的目标代码中的位置。理论上,你可以明确指定在目标代码中的任何位置去执行切面代码。实际上这并不现实,但你可以潜在地指定,比如:“我的对象中的所有方法”,或者“仅仅是这一个特定方法”,或者我们甚至可以使用“所有以 `get_` 开头的方法”之类的内容。 + +有了这些解释,你会发现创建一个基于 AOP 的库来向现有的基于 OOP 的业务逻辑(举个例子)添加日志逻辑是相对容易的。你所要做的就是用一个自定义函数替换目标对象现有的匹配方法,该自定义函数会在适当的时间点添加切面逻辑,然后再调用原有的方法。 + +## 基本实现 + +因为我是一个视觉学习者,所以我认为,展示一个基本的例子说明如何实现一种 `切面` 方法来添加基于 AOP 的行为将是个漫长的过程。 + +下面的示例将阐明实现它有多容易以及它给你的代码带来的好处。 + +```JavaScript +/** 用于获取一个对象中所有方法的帮助函数 */ +const getMethods = (obj) => Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(item => typeof obj[item] === 'function') + +/** 将原始方法替换为自定义函数,该函数将在通知指示时调用我们的切面 */ +function replaceMethod(target, methodName, aspect, advice) { + const originalCode = target[methodName] + target[methodName] = (...args) => { + if(["before", "around"].includes(advice)) { + aspect.apply(target, args) + } + const returnedValue = originalCode.apply(target, args) + if(["after", "around"].includes(advice)) { + aspect.apply(target, args) + } + if("afterReturning" == advice) { + return aspect.apply(target, [returnedValue]) + } else { + return returnedValue + } + } +} + +module.exports = { + // 导出的主要方法:在需要的时间和位置将切面注入目标 + inject: function(target, aspect, advice, pointcut, method = null) { + if(pointcut == "method") { + if(method != null) { + replaceMethod(target, method, aspect, advice) + } else { + throw new Error("Tryin to add an aspect to a method, but no method specified") + } + } + if(pointcut == "methods") { + const methods = getMethods(target) + methods.forEach( m => { + replaceMethod(target, m, aspect, advice) + }) + } + } +} +``` + +非常简单,正如我提到的,上面的代码并没有涵盖所有的用例,但是它应该足以涵盖下一个示例。 + +但是在我们往下看之前,注意一下这个 `replaceMethod` 函数,这就是“魔法”生效的地方。它能够创建新函数,也可以决定我们何时调用我们的切面以及如何处理它的返回值。 + +接下来说明这个库的用法: + +```JavaScript +const AOP = require("./aop.js") + +class MyBussinessLogic { + + add(a, b) { + console.log("Calling add") + return a + b + } + + concat(a, b) { + console.log("Calling concat") + return a + b + } + + power(a, b) { + console.log("Calling power") + return a ** b + } +} + +const o = new MyBussinessLogic() + +function loggingAspect(...args) { + console.log("== Calling the logger function ==") + console.log("Arguments received: " + args) +} + +function printTypeOfReturnedValueAspect(value) { + console.log("Returned type: " + typeof value) +} + +AOP.inject(o, loggingAspect, "before", "methods") +AOP.inject(o, printTypeOfReturnedValueAspect, "afterReturning", "methods") + +o.add(2,2) +o.concat("hello", "goodbye") +o.power(2, 3) +``` + +这只是一个包含三个方法的基本对象,没什么特别的。我们想要去注入两个通用的切面,一个用于记录接收到的属性,另一个用于分析他们的返回值并记录他们的类型。两个切面,两行代码(并不需要六行代码)。 + +这个示例到这里就结束了,这里是你将得到的输出: + +![](https://cdn-images-1.medium.com/max/2000/1*9KZBwObbqAEuJAv1GWSryg.png) + +## AOP 的优点 + +在知道了 AOP 的概念及用途后,也行你已经猜到了为什么人们会想要使用面向切面编程,不过还是让我们做一个快速汇总吧: + +* **封装横切关注点的好方法**。我非常喜欢封装,因为它意味着更容易阅读和维护可以在整个项目中重复使用的代码。 +* **灵活的逻辑**。在注入切面时,围绕通知和切入点实现的逻辑可以为你提供很大的灵活性。反之这又有助于你动态地打开和关闭代码逻辑的不同切面(有意的双关)。 +* **跨项目重复使用切面**。你可以将切面视为组件,即可以在任何地方运行的小的、解耦的代码片段。如果你正确地编写了切面代码,就可以轻松地在不同的项目中共享它们。 + +## AOP 的主要问题 + +因为并非每件事都是完美的,这种范式遭到了一些批评者的反对。 + +他们提出的主要问题是,它的主要的优势实际上隐藏了代码逻辑和复杂性,在不太清楚的情况下可能会产生副作用。 + +如果你仔细想想,他们说的有一定道理,AOP 给了你很多能力,可以将无关的行为添加到现有的方法中,甚至可以替换它们的整个逻辑。当然,这可能不是引入此范式的确切原因,而且它肯定不是我上面提供的示例的意图。 + +然而,它确实可以让你去做任何你想做的事情,再加上缺乏对良好编程实践的理解,可能会导致非常大的混乱。 + +为了不让自己听起来太老套,我转述一下 Uncle Ben 的话: + +> 能力越大,责任越大 + +如果你想正确地使用 AOP ,那么就必须理解软件开发的最佳实践。 + +在我看来,仅仅因为你使用这个工具之后可能会带来很大的损害,并不足以说明这个工具就是不好的,因为它也会带来很多的好处(即你可以将很多常见的逻辑提取到一个集中的位置,并可以在你需要的任何地方用一行代码注入它)。对我来说,这是一个强大的工具,值得学习,也绝对值得使用。 + +--- + +面向切面编程是 OOP 的完美补充,特别是得益于 JavaScript 的动态特性,我们可以非常容易地实现它(如这里的代码演示)。它提供了强大的功能,能够对大量逻辑进行模块化和解耦,以后甚至可以与其他项目共享这些逻辑。 + +当然,如果你不正确地使用它,你会把事情搞得一团糟。但是你绝对可以利用它来简化和清理大量的代码。这就是我对 AOP 的看法,你呢?你曾经听说过 AOP 吗?你以前使用过它吗?请在下面留言并分享你的想法! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/auto-documenting-a-python-project-using-sphinx.md b/article/2020/auto-documenting-a-python-project-using-sphinx.md index 6081ce263a5..8d308b5b077 100644 --- a/article/2020/auto-documenting-a-python-project-using-sphinx.md +++ b/article/2020/auto-documenting-a-python-project-using-sphinx.md @@ -2,88 +2,88 @@ > * 原文作者:[Julie Elise](https://medium.com/@julie_elise) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/auto-documenting-a-python-project-using-sphinx.md](https://github.com/xitu/gold-miner/blob/master/article/2020/auto-documenting-a-python-project-using-sphinx.md) -> * 译者: -> * 校对者: +> * 译者:[Herman](https://github.com/actini) +> * 校对者:[lsvih](https://github.com/lsvih) -# Auto-Documenting a Python Project Using Sphinx +# 使用 Shpinx 为 Python 项目自动生成文档 ![Photo by [Jason Blackeye](https://unsplash.com/photos/nyL-rzwP-Mk) on [Unsplash](https://unsplash.com/photos/nyL-rzwP-Mk)](https://cdn-images-1.medium.com/max/12000/1*KOMqHlHUwgvf0RgqXUHMgA.jpeg) -While thorough documentation is necessary, it’s often put on the back burner and looked upon as a chore and a low-priority task. As a developer, it’s easy to fall back on the mindset of “why document the code when you, the author, know exactly what it’s doing?” When the code is rapidly changing, keeping the docs up to date becomes an even more substantial burden. +虽说非常有必要好好写项目文档,但写文档这个事儿还是经常被一拖再拖,并且大家都觉得它很繁琐、优先级也很低。开发人员也常常会想“既然对自己写的代码了如指掌,为啥还要写文档呢?”另外,随着代码的不断更新,维护文档也变成了一项繁重的负担。 -Luckily, manually writing out documentation is not required due to the capabilities of [Sphinx](https://www.sphinx-doc.org/en/master/), a tool that automatically generates documentation from the docstrings in your code. +好消息,得益于 [Sphinx](https://www.sphinx-doc.org/en/master/) 的强大功能,我们无须再手动写文档了,Sphinx 可以从代码的注释中自动生成项目文档。 -Below is a step-by-step guide to easily auto-generate clean and well-organized documentation from Python code using Sphinx. +接下来我们逐步学习在 Python 代码中如何使用 Sphinx 自动生成结构良好、形式整洁的文档。 -## 1. Install Sphinx +## 1. 安装 Sphinx -Sphinx can be installed using pip by opening up the terminal and running `pip install -U Sphinx`, or by downloading the official [Python package](https://pypi.org/project/Sphinx/#files). +在终端中执行 `pip install -U Sphinx` 可以使用 pip 安装 Sphinx,或者直接从 [Python package](https://pypi.org/project/Sphinx/#files) 官网上下载也可以。 -[Here](https://www.sphinx-doc.org/en/master/usage/installation.html) is the official page outlining other ways of installing Sphinx, depending on your platform. +Sphinx 官网上也讲了其他的安装方式,根据你的实际情况自由选择合适的方式安装即可,详见[这里](https://www.sphinx-doc.org/en/master/usage/installation.html)。 -## 2. Initialize the Sphinx Configuration +## 2. 初始化 Sphinx 配置 -In the root directory of your project, run `sphinx-quickstart` to initialize the sphinx source directory to create a default configuration. Running this command will prompt you to fill out some basic configuration properties such as whether to create separate source and build directories, the project name, author name, and project version. +在项目根目录下运行 `sphinx-quickstart` 来初始化 sphinx 的 `source` 目录并创建默认的配置。命令执行过程中,需要你填写一些基本的配置内容,比如是否创建单独的 `source` 和 `build` 目录、项目的名称、作者以及版本。 -![Initialize the sphinx config using **sphinx-quickstart**](https://cdn-images-1.medium.com/max/2412/1*NiE2w5uY6KtD8DII_vnYmA.png) +![使用 **sphinx-quickstart** 初始化 sphinx 配置](https://cdn-images-1.medium.com/max/2412/1*NiE2w5uY6KtD8DII_vnYmA.png) -As shown above, running the `sphinx-build` command creates a `Makefile`, a `make.bat` file, as well as `build` and `source` directories. +如上所示,运行 `sphinx-build` 命令会创建 `Makefile` 和 `make.bat` 文件以及 `build` 和 `source` 目录(使用单独的 `source` 和 `build` 目录的情况,译者注)。 -## 3. Update the conf.py File +## 3. 更新 `conf.py` 文件 -The `conf.py` file inside the `source` folder describes the Sphinx configuration, which controls how Sphinx builds the documentation. If you wish to override the theme, version, or module directory, you’ll need to override these changes here. Below are some recommended overrides: +`source` 目录下的 `conf.py` 是 Sphinx 的配置文件,控制着 Sphinx 如何生成文档。如果你可以在这里重新定义主题、版本或者模块目录。以下是一些推荐的配置内容: -#### Update the theme +#### 修改主题 -The default theme for sphinx is [alabaster](https://alabaster.readthedocs.io/en/latest/). There are many existing [themes](https://www.sphinx-doc.org/en/1.8/theming.html) to choose from, and it’s even possible to create your own. A recommended theme is `sphinx_rtd_theme`, which is a nice-looking, modern, mobile-friendly theme. +Sphinx 默认的主题是 [alabaster](https://alabaster.readthedocs.io/en/latest/)。你既可以从[这里](https://www.sphinx-doc.org/en/1.8/theming.html)选择心仪的主题,也可以自定义主题。推荐使用 `sphinx_rtd_theme` 的主题,不仅样式美观、具有现代感,还兼容手机视图。 -To use `sphinx_rtd_theme`, you’ll need to install the sphinx-rtd-theme Python package by running `pip install sphinx-rtd-theme` in the terminal or by downloading the theme [here](https://pypi.org/project/sphinx-rtd-theme/#files). +你需要先安装 `sphinx_rtd_theme` 主题然后才能使用,可以通过运行 `pip install sphinx-rtd-theme` 安装,也可以手动[下载](https://pypi.org/project/sphinx-rtd-theme/#files)该主题。 -Update the `html_theme` variable inside the `conf.py` file to point to the desired theme name: +在 `conf.py` 文件中更新 `html_theme` 的值: ![](https://cdn-images-1.medium.com/max/2884/1*Yy0z8_qggtEY2STcw7DIXw.png) -#### Update the version +#### 修改版本 -During each release, you’ll want to update the documentation version to point to the project release version, either manually or using an automated process. +每次项目发布都需要更新文档的版本,使其和项目版本保持一致,你可以手动更新也可以自动实现。 ![](https://cdn-images-1.medium.com/max/2724/1*cggJvzpzN1__-Om7rhwi9w.png) -#### Specify the location of the Python modules +#### 指定模块目录的路径 -Update the system **path** to point to the project’s modules directory so that sphinx can find the source files. Lines 13–15 will append the module directory to the system path, and are commented out by default. Uncomment these lines and update the line that reads sys.path.insert(0, os.path.abspath(‘.’)) to append the directory that contains the Python modules. +你也可以将项目的模块目录(即需要使用 sphinx 自动生成文档的代码文件所在的目录,译者注)添加到系统路径中,这样 sphinx 就能找到源文件了。配置文件中默认被注释掉的 13 ~ 15 行意在将模块目录添加到系统路径中,移除注释并修改 `sys.path.insert(0, os.path.abspath(‘.’))` 这一行,把你的模块目录添加进去。 ![](https://cdn-images-1.medium.com/max/2808/1*RYT_TSZLL8haGobmqXrrUA.png) -#### Add extension support for autodoc +#### 添加 autodoc 的扩展支持 -The `extensions` variable is assigned to a list of extensions needed to build the documentation. For instance, if you’re planning to include documentation from your doc using the [autodoc directives](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html), you’ll need to activate it by adding `sphinx.ext.autodoc `****to the extension list. +`extensions` 是 Sphinx 生成文档的时候需要用到的一系列扩展。比如,你想使用 [autodoc 指令](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html)自动导入需要生成文档的模块,只需在扩展列表中添加 `sphinx.ext.autodoc` 就行了。 -#### Add extension support for NumPy and Google Doc style docstrings +#### 添加扩展支持 NumPy 和 Google Doc 风格的注释 -This, of course, is optional depending on the preferred docstring format. Should the documentation in your code follow the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html), you’ll need to append `sphinx.ext.napoleon` to the extensions list. +当然,这取决于你喜欢哪种格式的注释。如果代码的注释遵循了 [Google Python 风格指南](https://google.github.io/styleguide/pyguide.html),你需要将 `sphinx.ext.napoleon` 添加到扩展列表中。 ![](https://cdn-images-1.medium.com/max/2672/1*jNTzF4AbQvDwsiSY582DdA.png) -## 4. Auto-generate the rst Files +## 4. 自动生成 rst 文件 -Sphinx generates the HTML documentation from reStructuredText (rst) files. These rst files describe each webpage and may contain autodoc directives which will ultimately generate the documentation from docstrings in an automatic way. There’s an automatic way to generate these files, so there’s no need to manually write out the autodoc directives for each class and module. +Sphinx 会根据 reStructruedText(rst)文件生成 HTML 文档。这些 rst 文件是对每个页面的描述,也可能会包含一些 autodoc 指令,并且最终会根据注释内容自动生成文档。由于可以自动生成这些文档,所以就没必要靠人工去给每个类或者模块去手写 autodoc 指令啦。 -The `sphinx-autodoc` command will automatically generate rst files with [autodoc directives](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) from your code. This command only needs to be run when a new module is added to the project. +`sphinx-autodoc` 命令会根据代码生成包含 [autodoc 指令](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) 的 rst 文件。一旦 rst 文件生成之后,只有在项目中添加了新的模块时才需要重新运行这个命令。 -First, make sure that the `sphinx.ext.autodoc` extension is included in the extensions list in `conf.py` as described in the section above. +首先,按照前文将 `sphinx.ext.autodoc` 扩展添加到 `conf.py` 文件的扩展列表中。 -To autogenerate the rst files, run the `sphinx-apidoc` command using the following syntax: +要自动生成 tst 文件,只需按照下面的语法运行 `sphinx-apidoc` 命令: -sphinx-apidoc -o \ \ +`sphinx-apidoc -o \<输出目录> \<模块目录>` -In our example, the output directory is `source` , and the module directory is `python`. +在本例中,`source` 是输出目录,`python` 是模块目录, -sphinx-apidoc -f -o source python +`sphinx-apidoc -f -o source python` -Running the sphinx-apidoc -o source python command will generate the rst files `test.rst`, and `modules.rst`. `test.rst` includes directives to write out the documentation for the classes and functions in `test.py`, and the `modules.rst` contains a list of which module files to include on the modules page (i.e. test). +运行 `sphinx-apidoc -o source python` 命令会生成 `rest.rst` 和 `modules.rst` 文件。`test.rst` 包含了生成 `test.py` 文件中的类和方法文档所需的指令,而 `modules.rst` 文件包含了在模块列表中需要包含的文件(比如 test 文件)。(类似于模块的目录,译者注) -![Generate rst files using **sphinx-apidoc**](https://cdn-images-1.medium.com/max/2588/1*NYjOLtNGK77AAhDai5vekA.png) +![使用 **sphinx-apidoc** 生成 rst 文件](https://cdn-images-1.medium.com/max/2588/1*NYjOLtNGK77AAhDai5vekA.png) ```Text test module @@ -96,13 +96,13 @@ test module ``` -## 5. Build the HTML +## 5. 生成 HTML -Now that you have the configuration and rst files set up, we can now run the `make html` command from the terminal in the main directory to generate the HTML files. The HTML files will be created inside the build/HTML folder. +既然你已经准备好了配置文件和 rst 文件,现在我们可以运行 `make html` 命令来生成 HTML 文件了,HTML 文件将会保存在 `build/HTML` 目录中。 -![Build HTML using **make HTML**](https://cdn-images-1.medium.com/max/2484/1*3h79Oyr6zuvy3efZ3kq0Jg.png) +![使用 **make HTML** 生成 HTML](https://cdn-images-1.medium.com/max/2484/1*3h79Oyr6zuvy3efZ3kq0Jg.png) -As you can see in this particular case, the warning Warning: "Document isn't included in any toctree was issued since we haven’t included the modules.rst file in any toctree. To fix this, add `modules` under the toctree directive in `index.rst` as shown below: +如你所见,这里出现了一个警告“Document isn't included in any toctree was issued since we haven’t included the modules.rst file in any toctree”,将 `modules` 添加到 `index.rst` 的 `toctree` 指令下可以修复这个问题: ```Text .. SphinxDemo documentation master file, created by @@ -129,43 +129,43 @@ Indices and tables * :ref:`search` ``` -Run the build again: +重新生成: ![](https://cdn-images-1.medium.com/max/2468/1*W3nn6gsVP2UhBUBgrPGWkQ.png) -The HTML files were generated in the build/HTML folder. Open up index.html in the browser to view the generated docs: +HTML 文件都在 `build/HTML` 目录下,我们在浏览器中打开 index.html 来一睹为快: ![index.html](https://cdn-images-1.medium.com/max/4392/1*Q3YACR12o9iy3HFzVujvGQ.png) -## 6. Advanced Sphinx Markup +## 6. 高级 Shpinx 指令 -There are additional Sphinx [directives](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html) that will help your documentation look and feel more modern and organized. Here are some of the top useful features that will help you further customize the documentation. All examples are generated with the `sphinx_rtd_theme`: +还有许多其他的 Sphinx [指令](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html) 能帮你把文档组织地更好看、更具有现代感。以下这些指令都备受好评,希望对你优化文档有帮助。以下所有的案例都是使用 `sphinx_rtd_theme` 主题生成的: -#### Table of contents +#### 目录 -Sphinx uses a custom directive, known as the **toctree** directive, to describe the relations between different files in the form of a tree, or table of contents. +Sphinx 使用了传统的广为人知的 **toctree** 指令以树状结构来描述不同文件之间的关系,也就是目录。 -![Rendered toctree example](https://cdn-images-1.medium.com/max/4396/1*Jx7OJnsEzr6azKdYihxFKA.png) +![目录](https://cdn-images-1.medium.com/max/4396/1*Jx7OJnsEzr6azKdYihxFKA.png) -#### Note box +#### 提示框 -A note box can be created using the **note** directive. +可以使用 **note** 指令创建提示框。 .. note:: This is a **note** box. -![Rendered note example](https://cdn-images-1.medium.com/max/2832/1*ziyCsuYgUZd6isrSn18DXA.png) +![提示框](https://cdn-images-1.medium.com/max/2832/1*ziyCsuYgUZd6isrSn18DXA.png) -#### Warning box +#### 警告框 -A warning box can be created using the **warning** directive. +可以使用 **warning** 指令创建警告框。 .. warning:: This is a **warning** box. -![Rendered warning example](https://cdn-images-1.medium.com/max/2844/1*lKsiVUE_OmCkc7vJutDEpw.png) +![警告框](https://cdn-images-1.medium.com/max/2844/1*lKsiVUE_OmCkc7vJutDEpw.png) -#### Image +#### 图片 -An image can be added using the **image** directive. +可以使用 **image** 指令创建图片。 ```Text .. image:: sphinx.png @@ -175,9 +175,9 @@ An image can be added using the **image** directive. ``` -#### Table +#### 表格 -A table can be added using the **table** directive. +可以使用 **table** 指令创建表格。 ```Text .. table:: @@ -193,18 +193,18 @@ A table can be added using the **table** directive. ``` -![Rendered table example with an embedded image](https://cdn-images-1.medium.com/max/2176/1*cw-s-06qUEIzUnQLhwR09Q.png) +![表格和图片](https://cdn-images-1.medium.com/max/2176/1*cw-s-06qUEIzUnQLhwR09Q.png) -## Resources +## 其他资源 * [Sphinx Documentation](https://www.sphinx-doc.org/en/master/usage/index.html) * [ReStructuredText Guide](https://docutils.sourceforge.io/rst.html) * [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) * [Autogenerate C++ Documentation using Sphinx, Breath, and Doxygen](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/) -## Conclusion +## 结束语 -In this article, we covered the basics required to configure and build Sphinx documentation for any Python project. Sphinx relies on rst files, so any kind of customization that reStructuredText can handle is possible. Being familiar with the capabilities of Sphinx and automation tools when it comes to generating documentation will hopefully encourage you to write and maintain up-to-date documentation. +本文中,我们介绍了在 Python 项目中配置和使用 Sphinx 生成文档的基本内容。Sphinx 依赖 rst 文件,因此你可以在 rst 文件中自定义任何 reStructuredText 格式的内容。希望熟练使用 Sphinx 等自动化工具生成文档能够激励你书写并维护与时俱进的文档! > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/article/2020/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.md b/article/2020/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.md new file mode 100644 index 00000000000..a1d868e249d --- /dev/null +++ b/article/2020/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.md @@ -0,0 +1,179 @@ +> * 原文地址:[Avoiding Memory Leaks in Node.js: Best Practices for Performance](https://blog.appsignal.com/2020/05/06/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.html) +> * 原文作者:[Deepu K Sasidharan](https://twitter.com/deepu105) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.md](https://github.com/xitu/gold-miner/blob/master/article/2020/avoiding-memory-leaks-in-nodejs-best-practices-for-performance.md) +> * 译者: [laampui](https://github.com/laampui) +> * 校对者: [Usualminds](https://github.com/Usualminds), [regon-cao](https://github.com/regon-cao) + +# 在 Node.js 中避免内存泄漏:性能最佳实践 + +内存泄漏是每一位开发者最终都会遇到的问题。它存在于大多数的编程语言里,即使是能够自动管理内存的语言也不例外。内存泄漏会导致一些如应用缓慢、崩溃、高延迟等问题。 + +在这篇文章中,我们会了解到什么是内存泄漏以及如何在 Node.js 中避免它。虽然这篇文章着重点在 NodeJS,但应该也适用于 JavaScript 和 TypeScript。规避内存泄漏有助于你的应用更高效地利用资源同时也能带来性能提升。 + +## JavaScript 中的内存管理 + +要理解内存泄漏,我们首先需要理解 NodeJS 是如何管理内存的。这意味着需要了解内存是如何被 NodeJS 的 JavaScript 引擎管理的。对于 JavaScript,NodeJS 使用 **[V8 引擎](https://v8.dev/)**,对于内存是如何被 V8 组织及利用,你可以参阅 [Visualizing memory management in V8 Engine](https://dev.to/deepu105/visualizing-memory-management-in-v8-engine-javascript-nodejs-deno-webassembly-105p) 来获得更好的理解。 + +总结上面提及的那篇参阅文章: + +内存主要分为栈和堆。 + +* **栈**:存放静态数据,包括方法(函数)帧、原始值和指向对象的指针。这里的空间是被操作系统管理的。 +* **堆**:V8 存放对象或动态数据。这是内存区域中最大的一块并且这里是 **垃圾回收(GC)** 生效的地方。 + +> V8 通过垃圾收集管理堆内存。简单地说,它会释放没有被引用的对象。例如,没有被栈直接或间接引用(通过另一个对象引用)的对象,它的内存空间都会被释放以用于新对象的创建。 +> +> V8 的垃圾收集器主要负责回收处理无用的内存,并提供给 V8 进程重复使用。V8 垃圾收集器是区分新老生代的(堆中的对象按它们的存放时间分组并会在不同的阶段被清理)。V8 的垃圾回收有两个阶段和三种算法。 + +![Mark-sweep-compact GC](https://d33wubrfki0l68.cloudfront.net/e3979bee7b7b51e6124594ea36dfde4eb7015da5/5c860/images/blog/2020-05/mark-sweep-compact.gif) + +## 什么是内存泄漏 + +简单来说,内存泄漏就是堆上的一块孤立内存,这小块内存不再被程序使用并且也没有被垃圾收集器释放回操作系统,所以,这是一块没有被使用的内存。这样的内存块持续增加可能会导致应用没有足够内存空间去支撑其继续工作,也可能会导致你的操作系统没有足够的内存可供分配,进而导致系统缓慢或崩溃。 + +## 什么导致了内存泄漏 + +自动内存管理(如 V8 中的垃圾收集机制)目的在于避免内存泄漏,像循环引用不再是一个需要开发者关注的问题,然而内存泄漏依然可能发生,也许是因为预料之外的堆中的引用亦或是各种原因。一些常见的原因列举如下。 + +* **全局变量**:因为 JavaScript 中的全局变量被根节点(window 或 global `this`)引用,所以它们在整个应用生命周期中不会被收集,即会一直占用内存。这同样也适用于那些被全局变量(或其子属性)引用的对象,通过根节点引用数量庞大的对象可能导致内存泄漏。 +* **多个引用**: 当同一个对象被多个对象引用时,当其中一个引用被挂起,可能会导致内存泄漏。 +* **闭包**: JavaScript 闭包有一个很酷的特性,就是能够保存被它关联的上下文,当一个闭包持有一个引用,该引用指向堆中的一个庞大对象时,闭包会令该庞大对象持续在内存中直到闭包不再使用它。这意味着你可能会轻易地陷入这种情况,即持有着一个引用的闭包被不正确地使用从而导致内存泄漏。 +* **定时器 & 事件**:使用 setTimeout、setInterval、Observers 和事件监听器时,如果没有妥当处理保存在它们回调函数中的庞大对象引用时,可能会导致内存泄漏。 + +## 避免内存泄漏的最佳实践 + +现在我们理解了什么会导致内存泄漏,马上看看如何避免它们,以及了解确保高效使用内存的最佳实践。 + +### 减少全局变量的使用 + +因为全局变量从不会被垃圾回收,所以最好不要过度使用它们,以下是一些方法: + +**避免意外的全局变量** + +当你赋值给一个未声明的变量时,在默认情况下 JavaScript 会自动提升它为全局变量。这可能是一种会导致内存泄漏的低级错误。另一种情况是赋值给 [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)(在 JavaScript 中依然很神圣的东西)。 + +```js +// foo 会被提升为全局变量 +function hello() { + foo = "Message"; +} + +// foo 同样会成为全局变量,因为在非严格模式下,全局函数里的 \`this\` 指向全局上下文 +function hello() { + this.foo = "Message"; +} +``` + +为了避免这些意外,总是在 JS 文件顶部使用 `'use strict';` 在严格模式下编写 JavaScript。在严格模式下,上述例子会报错。当你使用 ES modules 或转译器(如 TypeScript 或 Babel),你不需要声明严格模式因为这些工具已经自动开启。在最近的 NodeJS 版本,你可以在使用 `node` 命令时加上 `--use_strict` 参数开启全局严格模式。 + +```javascript +"use strict"; + +// foo 不会被提升到全局环境 +function hello() { + foo = "Message"; // 会抛运行时错误 +} + +// foo 不会成为全局变量,因为严格模式下,全局函数的 \`this\` 指向自身 +function hello() { + this.foo = "Message"; +} +``` + +当你使用箭头函数,你同样需要小心不要意外的创建全局变量,不幸的是,严格模式对这种情况没有帮助,你可以使用来自 ESLint 的 `no-invalid-this` 规则来避免这种情况。如果你不使用 ESLint,确保不要在全局箭头函数里向 `this`赋值。 + +```js +// foo 会成为全局变量,因为箭头函数没有 `this`,它会沿着词法作用域向上寻找最近的 `this` +const hello = () => { + this.foo = "Message"; +} +``` + +最后,记住不要使用`bind` 或 `call` 方法绑定 `this` 到任何函数,因为这会违背使用严格模式的初衷。 + +**谨慎地使用全局作用域** + +一般来说,尽可能地避免使用全局作用域和全局变量是一种好的实践。 + +1. 尽可能地不要使用全局作用域,相反,利用函数的局部作用域,因为它们会被垃圾回收并且内存会被释放。如果你基于某些原因非要使用全局变量,当你不再使用它时将它的值设为 `null`。 +2. 只对常量、缓存和可复用的单例使用全局变量。不要因为传参麻烦而使用全局变量,对于在函数和类之间共享数据,可以通过参数或对象属性的方式传递。 +3. 不要在全局作用域存放大对象。如果你必须存放它们,当你不再需要它们时,确保将它们赋值为 null。对于缓存对象,可以写一个工具函数周期地清理它们,避免它们无限制地增长。 + +### 高效利用栈内存 + +尽可能地使用栈变量,这有助于内存和性能的提升,因为访问栈远远比访问堆要快,同时这也确保了我们不会意外地制造内存泄漏。当然,单纯使用静态数据是不现实的。在现实世界的应用里,我们会不得不使用大量的对象和动态数据,但我们可以学习一些技巧来更好地利用栈。 + +1. 避免从栈变量引用堆对象,同时,切勿保留未使用的变量。 +2. 使用解构从对象或数组中获取需要的字段,而不是将整个对象或数组传递给函数、闭包、定时器或事件处理函数。这避免了闭包保留一个对象的引用。获取的字段往往都是原始值,而原始值是存放在栈中的。 + +```js +function outer() { + const obj = { + foo: 1, + bar: "hello", + }; + + const closure = () { + const { foo } = obj; + myFunc(foo); + } +} + +function myFunc(foo) {} +``` + +### 高效利用堆内存 + +在实际的应用中使用堆内存往往是无法避免的,但是我们可以遵循以下几点来更高效地利用堆内存: + +1. 尽可能地拷贝对象而不是传递引用,只在对象较大且拷贝操作代价也大时才传递引用。 +2. 尽可能避免对象操作,相反,使用对象扩展或 `Object.assign` 来复制它们。 +3. 避免对同一个对象创建多个引用,相反,应拷贝一份这个对象。 +4. 使用短暂存活的变量。 +5. 避免创建嵌套过深的对象,如果无法避免,记得在当前作用域及时清理它们。 + +### 适当地使用闭包、定时器和事件处理函数 + +正如我们前面看到的,闭包、定时器和事件处理器是内存泄漏常发生的地方。让我们先从闭包开始,它是 JavaScript 中最常见的代码。看看以下来自 Meteor 团队的代码,因为 `longStr` 从未被回收并持续消耗内存,所以导致了内存泄漏,更多细节请阅读[这篇博客](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156)。 + +```js +var theThing = null; +var replaceThing = function () { + var originalThing = theThing; + var unused = function () { + if (originalThing) console.log("hi"); + }; + theThing = { + longStr: new Array(1000000).join("*"), + someMethod: function () { + console.log(someMessage); + }, + }; +}; +setInterval(replaceThing, 1000); +``` + +上面的代码创建了多个闭包,并且这些闭包持有对象引用。在这个情况下,可以通过在 `replaceThing` 函数末尾将 `originalThing` 的值设为 null 避免内存泄漏。这种情况同时也可以通过创建对象副本来避免,也可以参考前面提到的几种方法。 + +至于定时器,永远记住传递对象副本且避免对对象进行修改。同时,当定时器结束,记得使用 `clearTimeout` 和 `clearInterval` 方法。 + +对于事件监听器和观察者也一样,当任务完成就清理它们,不要让事件监听器一直运行,特别是当它们持有父级作用域的对象引用时。 + +## 总结 + +由于 JS 引擎的进化和对语言本身的优化,JavaScript 中的内存泄漏已不像以往那样是个大问题,但如果我们粗心大意,内存泄漏依然可能发生,并会导致性能问题甚至使得应用或操作系统崩溃。确保我们的代码不会发生内存泄漏的第一步是需要理解 V8 引擎是如何管理内存的。第二步是理解什么导致了内存泄漏。一旦我们理解了这两点,我们可以尽力避开导致内存泄漏的情景。当我们真的面对内存泄漏或性能问题时,我们会知道解决问题的方向在哪。至于 NodeJS,有些工具会有所帮助,例如,[Node-Memwatch](https://github.com/lloyd/node-memwatch) 和 [Node-Inspector](https://nodejs.org/en/docs/guides/debugging-getting-started/) 都是调试内存问题的优秀工具。 + +## 参考 + +* [Memory leak patterns in JavaScript](https://www.ibm.com/developerworks/web/library/wa-memleak/wa-memleak-pdf.pdf) +* [Memory Management](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management) +* [Cross-Browser Event Handling Using Plain ole JavaScript](https://docs.microsoft.com/en-us/previous-versions/msdn10/ff728624(v=msdn.10)) +* [Four types of leaks in your JavaScript code and how to get rid of them](https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/) +* [An interesting kind of JS memory leak](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers.md b/article/2020/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers.md new file mode 100644 index 00000000000..d36a967546c --- /dev/null +++ b/article/2020/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers.md @@ -0,0 +1,171 @@ +> * 原文地址:[Best Features of ES2017 — Async Functions and Arrays and Shared Buffers](https://medium.com/javascript-in-plain-english/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers-74dace23aa59) +> * 原文作者:[John Au-Yeung](https://medium.com/@hohanga) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers.md](https://github.com/xitu/gold-miner/blob/master/article/2020/best-features-of-es2017-async-functions-and-arrays-and-shared-buffers.md) +> * 译者:[tonylua](https://github.com/tonylua) +> * 校对者:[Chorer](https://github.com/Chorer), [dupanpan](https://github.com/dupanpan) + +# ES2017 最佳特性 -- 数组中的异步函数以及共享缓冲区 + +![照片由 [Elaine Casap](https://unsplash.com/@ecasap?utm_source=medium&utm_medium=referral) 拍摄并发表在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上](https://oscimg.oschina.net/oscnet/up-1da089eee95145e809f80d9ce4b883ce7b3.JPEG) + +自 2015 年起,JavaScript 可谓突飞猛进。 + +现在使用它比过去要舒服多了。 + +在本文中,我们将着眼于 ES2017 的最佳特性。 + +## 异步函数(Async Functions)和 Array.prototype.forEach() + +`Array.prototype.forEach` 并不适用 `async` 和 `await` 语法。 + +举例来说,如果有如下代码: + +```js +async function downloadContent(urls) { + urls.forEach(async url => { + const content = await makeRequest(url); + console.log(content); + }); +} +``` + +那么并不会得到包含若干 promise 的结果,因为 `forEach` 不会等待每个 promise 完成。 + +取而代之的是,可以用 for-of 循环来迭代每个异步函数以获取结果: + +```js +async function downloadContent(urls) { + for (const url of urls) { + const content = await makeRequest(url); + console.log(content); + } +} +``` + +for-of 循环能感知 `await` 操作符,所以可以用它循序运行所有异步函数。 + +若要并行运行若干异步函数,可以使用 `Promise.all`: + +```js +async function downloadContent(urls) { + await Promise.all(urls.map( + async url => { + const content = await makeRequest(url); + console.log(content); + })); +} +``` + +我们将多个 URL 映射为异步函数的集合,这样一来就能在 promise 数组上调用 `Promise.all` 了。 + +调用该方法后会返回一个 promise,其解决值(resolved value)是一个包含了每一个 promise 解决值的数组。 + +## 立即调用异步函数表达式 + +我们也可以创建立即运行的异步函数。 + +举例来说,相比于以下写法: + +```js +async function foo() { + console.log(await promiseFunc()); +} +foo(); +``` + +我们可以这么写: + +```js +(async function () { + console.log(await promiseFunc()); +})(); +``` + +也可以写成箭头函数: + +```js +(async () => { + console.log(await promiseFunc()); +})(); +``` + +## 未处理过的 rejection + +在使用异步函数时,并不用担心未处理过的 rejection 。 + +这是因为当浏览器遇到它们时会自动报告。 + +举例来说,我们可以这样写: + +```js +async function foo() { + throw new Error('error'); +} +foo(); +``` + +而后我们将在控制台中看到被记录的报错信息。 + +## Shared Array Buffers + +ES2017 引入的共享数组缓冲区(shared array buffers)使得我们可以构建并发的应用了。 + +这让我们可以在多个 worker 和主线程之间共享 `SharedArrayBuffer` 对象的字节数据。 + +被共享的缓冲由一个类型化数组(typed array)包裹,这样就能访问到它们了。 + +我们可以快速在 worker 间共享数据,而跨 worker 的数据协同也变得简便了。 + +举例来说,可以编写如下代码来创建一个共享数组缓冲区: + +```js +const worker = new Worker('worker.js'); + +const sharedBuffer = new SharedArrayBuffer( + 100 * Int32Array.BYTES_PER_ELEMENT); + +worker.postMessage({ + sharedBuffer +}); + +const sharedArray = new Int32Array(sharedBuffer); +``` + +我们在 `worker.js` 中创建了一个 worker。 + +之后我们用 `SharedArrayBuffer` 创建了一个 shared buffer。 + +它包含 100 个元素。 + +接着,为了与其它 worker 共享缓冲区,我们调用了 `postMessage` 以发送缓冲数据。 + +要访问缓冲区中的数据,就得创建一个新的 `Int32Array` 实例。 + +接下来在 `worker.js` worker 中,这样编写以获得缓冲数据: + +```js +self.addEventListener('message', (event) => { + const { + sharedBuffer + } = event.data; + const sharedArray = new Int32Array(sharedBuffer); + //... +}); +``` + +我们监听了 `message` 事件并从 `event.data` 中取得了 `sharedBuffer` 属性。 + +之后就能用与先前相同的方式访问它了。 + +## 总结 + +异步函数并不适配既有的数组实例方法。 + +同时,我们可以使用共享数组缓冲区在主线程和 worker 线程之间共享数据。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/best-static-site-generators-for-vue-js.md b/article/2020/best-static-site-generators-for-vue-js.md new file mode 100644 index 00000000000..bbb6c3ca8b5 --- /dev/null +++ b/article/2020/best-static-site-generators-for-vue-js.md @@ -0,0 +1,156 @@ +> * 原文地址:[Best Static Site Generators for Vue.js](https://blog.bitsrc.io/best-static-site-generators-for-vue-js-e273d52ea208) +> * 原文作者:[Chameera Dulanga](https://medium.com/@chameeradulanga) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/best-static-site-generators-for-vue-js.md](https://github.com/xitu/gold-miner/blob/master/article/2020/best-static-site-generators-for-vue-js.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[NieZhuZhu](https://github.com/NieZhuZhu)、[wynn-w](https://github.com/wynn-w) + +# 四个优秀 Vue.js 静态站点生成器 + +![Photo by [Igor Son](https://unsplash.com/@igorson?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/green?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/9180/1*xKSrtHfuh8uTPcNyZmxjGw.jpeg) + +在过去几年里,Vue.js 已经成为 web 应用程序开发的热门选择。随着它的流行,该框架已经扩展到曾经以 React 为主导的静态站点生成器领域。 + +像 Gatsby 和 NextJS 等这类 React.js 的静态网页生成器,你可以找到几个支持生成静态网页的 Vue.js 框架。然而,考虑到它们的功能特性,选择一个合适的并不容易。 + +因此,在本文中,我将介绍四个最佳 Vue.js 静态网页生成器框架,并进行详细的比较,以便你找到合适的框架进行使用。 + +## 1. Nuxt.js — 32k stars 和 280+ 贡献者 + +![Source: [https://nuxtjs.org/](https://nuxtjs.org/)](https://cdn-images-1.medium.com/max/3296/1*XyZK_B7uum1Da-Q0VZ6Niw.png) + +首先要介绍的是 Nuxt.js,这是一个建立在 Vue.js 之上的开源框架。Nuxt.js 通过抽象客户-服务器分布细节来简化 web 开发。 + +Nuxt.js 遵循健壮的模块化架构设计,有 50 多个不同的模块可供使用。这些模块将提供内置支持,用以将 PWA 功能和标准功能(如谷歌分析)引入应用程序。 + +Nuxt.js 最大的优点之一是具有 `nuxt generate` 命令。 + +> 通过这个命令,你只要花费很少的精力就能开发一个纯静态的网站。 + +通过查看 Nuxt.js 的统计数据,你会发现它有 32k stars 和 280+ 贡献者。例如 GitLab、NESPRESSO 和 UBISOFT 这些公司已经开始使用 Nuxt.js。 + +#### 优点 + +* 优化支持。 +* 服务器端渲染。 +* 快速开发和运行快。 +* 明确的项目结构 +* 支持无服务器静态站点生成。 +* 自动代码拆分。 + +#### 缺点 + +* 使用自定义库可能会有一些问题。 +* 关于调试的使用存在很多待解决 issue。 +* 有大型社区但仍比不上 Gatsby 和 Next.js。 + +## 2. VuePress — 针对以内容为中心的静态网站进行优化 + +![Source: [https://vuepress.vuejs.org/](https://vuepress.vuejs.org/)](https://cdn-images-1.medium.com/max/2468/1*6rBV7Id9ZvogzPotQBP9cA.png) + +VuePress 是作为一个文档生成系统开发的另一个 Vue.js 静态站点生成器。然而,1.x 版本发布后,VuePress 被认为是一个静态文件生成器。 + +在 VuePress 中,每个页面都被视为一个标记文件,它们被呈现为一个 HTML 页面,并在页面加载时充当单页面应用程序。 + +根据官方文件,VuePress 主要由两部分组成: + +1. 带有基于 Vue.js 主题系统的静态站点生成器。 +2. 添加全局功能以及针对文档优化的默认主题的插件 API。 + +如果我们把 VuePress 和 Nuxt.js 进行比较,可以看到 Nuxt.js 几乎可以做到 VuePress 所能做到的一切。 + +> **然而,VuePress 更适合用来创建以内容为中心的静态网站,而 Nuxt.js 更侧重于网络应用程序开发。** + +查看在 GitHub 的统计数据,VuePress 的项目仓库中有 17k stars 和 340+ 贡献者。它还被一些公司使用,例如 FinTech Consortium、IADC 和 Directus。 + +#### 优点 + +* 更好的加载性能。 +* SEO 友好。 +* 提供内置 markdown 扩展。 +* 包含强大的搜索插件、PWA 功能、谷歌分析等。 +* 带有 markdown 到 HTML 的默认转换处理。 + +#### 缺点 + +* 相比之下是新技术,还不如 Nuxt.js 那样受认可。 +* 大多数共享主机提供商都没有安装 VuePress。 + +## 3.Gridsome — 基于 GraphQL 的数据驱动框架 + +![Source: [https://gridsome.org/](https://gridsome.org/)](https://cdn-images-1.medium.com/max/3122/1*fmNKCcOC47EB-KAdeXfD0g.png) + +接下来要介绍的是 Gridsome,它以建立快速轻量静态网站而闻名。跟 React 中的 Gatsby 类似,Gridsome 是一个数据驱动的框架。Gridsome 使用一个 GraphQL 的数据层从数据源中获取内容,然后动态生成页面。 + +> GraphQL 充当 Gridsome 的内容管理系统。 + +你可以通过使用 `gridsome develop` 命令在本地运行项目,在 **localhost:8080/___explore** 上浏览这个 GraphQL 数据层。 + +同样,你可以使用 `gridsome build` 构建网站,它将生成可用于生产环境的优化 HTML 文件。 + +查看 Gridsome 的 GitHub 统计,它只有 7k stars 和 100+ 贡献者。但这并不妨碍 Gridsome 拥有一些独特且竞争力强的功能特性。 + +#### 优点 + +* 便捷的本地开发设置和热重载。 +* 提供开箱即用的代码拆分、资源优化和渐进式图片展示,以提高性能。 +* 支持 PWA 功能。 +* SEO 友好。 +* 结构清晰和自动配置路由。 +* 丰富的插件。 + +#### 缺点 + +* 需要掌握 GraphQL 基础知识。 +* 相比之下是新技术,还不如 Nuxt.js、VuePress 那样受认可。 + +## 4. Saber — 从不同的文件系统中提取数据 + +![Source: [https://saber.land/](https://saber.land/)](https://cdn-images-1.medium.com/max/2702/1*OR9DwoeaIjrjEAuPF0FhqA.png) + +Saber.js 是另一个静态站点生成器,有大量的内置特性可以使用。 + +> 大概浏览一下 Saber.js,感觉更像是 Gatsby、Gridsome 和 Nuxt.js 的结合。 + +类似于 Gatsby 和 Gridsome,Saber 允许你用想要的数据创建静态网站。你可以从不同的文件系统中提取数据。使用 Saber,你就不用担心不会用 GraphQL。 + +Saber 使用其文件系统作为路由 API(与 Nuxt.js 非常类似),具有很高的可扩展性。虽然 Saber 团队目前只支持 Vue.js,但它也计划扩展对 React 的支持。 + +由于 Saber 对这项业务来说仍然是新技术,它的 GitHub 项目也只有2k stars。我相信 Saber 框架只要稳定下来,它的 star 数量肯定会增加。 + +#### 优点 + +* 自动代码拆分。 +* 基于文件系统的路由。 +* 热代码重载。 +* 内置 Markdown 支持。 +* 支持 i18n。 + +#### 缺点 + +* 没有 CLI。 +* 还处于 Beta 版本。 + +## 结论 + +在静态网站生成器领域,React 是首选,并占据了整个空间。然而,Vue.js 能够用我们上面讨论的那些优秀的框架来改变这种情况。此外,它们中的一些框架已经对基于 React 的框架构成了真正的威胁。 + +例如,Gatsby 和 Gridsome 在功能特性上看起来非常相似。除此之外,Gridsome 在使用表现、学习曲线、社区规模等方面已经能够追上 Gatsby。 + +让我们比较一下基于 Vue.js 的和基于 React 的静态站点生成器,可以看到像 Nuxt.js、VuePress、Gridsome 这样的框架有能力和 Gatsby、NextJS 竞争。 + +然而,当比较上述四个框架时,从 GitHub 和 [npmtrends.com](https://www.npmtrends.com/) 统计数据来看,其中 Nuxt.js 和 VuePress 是佼佼者。 + +![[npmtrends.com Stat Comparison](https://www.npmtrends.com/gridsome-vs-nuxt-vs-vuepress-vs-saber)](https://cdn-images-1.medium.com/max/2684/1*NsUUJyOV9gsT2Hwjmy-sbw.png) + +![GitHub Statistics](https://cdn-images-1.medium.com/max/2000/1*2ydbJAirl8vJ3J8JA1M6xA.png) + +但是,我们不应该忘记,这些框架中的每一个都有其独特的功能。例如,Saber 有可能成为全球热门,因为它计划扩大对 React 的支持。 + +我希望这篇文章能帮助你找到合适的框架。如果你有任何问题,请在下面的评论中提及。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/better-composition-in-vue.md b/article/2020/better-composition-in-vue.md new file mode 100644 index 00000000000..1635b70b985 --- /dev/null +++ b/article/2020/better-composition-in-vue.md @@ -0,0 +1,355 @@ +> * 原文地址:[Better Component Composition in VueJS](https://itnext.io/better-composition-in-vue-fd35b9fe9c79) +> * 原文作者:[Francesco Vitullo](https://medium.com/@francisvitullo) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/better-composition-in-vue.md](https://github.com/xitu/gold-miner/blob/master/article/2020/better-composition-in-vue.md) +> * 译者:[tonylua](https://github.com/tonylua) +> * 校对者:[Gesj\-yean](https://github.com/Gesj-yean), [dupanpan](https://github.com/dupanpan) + +# VueJS 中更好的组件组合方式 + +![照片由 [uniqsurface](https://unsplash.com/@uniqsurface?utm_source=medium&utm_medium=referral) 拍摄并发表在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上](https://cdn-images-1.medium.com/max/7000/0*janl0y40OKFy4aID) + +**VueJS** 中有一些组合组件并复用逻辑的方法。在本文中,我将展示一种在 Vuejs (2.* 及 3.*) 中改进组合方式的方法。 + +我的确欣赏最近的 **Composition API** 提案,但我认为视野还可以更开阔。 + +下面,你可以看到一个实现了一种常规用例(从远端获取一个简单的数据并将其搭配不同的转场效果显示出来)的组件,尽管大部分逻辑及其相关的模版、数据和其它变量等与出现在其它地方或组件中的相同逻辑并无不同,它们还是出现在了该组件中。 + +```Vue + + + + + + +``` + +该如何重构并改善这个组件呢?让我们一步步地让其更易读且更容易复用。 + +#### Vue Composition API + +感谢新的 Vue Composition API,使得我们可以在不丢失由 Vue 组件提供的响应性或其它特性的前提下,抽出一些逻辑以来复用它。 + +这种方式有助于组织代码、让组件更易读,并有助于降低总体复杂度。作为一种建议,我相信这些应该是重构巨大、复杂和混乱的组件时的首要之事。 + +我们将抽取与获取数据有关的部分及相关的变量(**loading、error** 等……),但我并不想谈论什么是 Composition API 以及其特性、优点和缺点。 + +让我们来创建一个提供了获取数据必要功能及若干响应式变量的简单函数: + +```TypeScript +import { reactive, toRefs, computed, Ref, ComputedRef } from '@vue/composition-api'; + +interface ReceivedData { + text?: string +} + +interface FetchState { + loading: boolean, + error: boolean, + data: ReceivedData +} + +interface FetchDataVars { + loading: Ref; + error: Ref; + data: Ref; + fetchData: Function; + hasData: ComputedRef +} + +export default (): FetchDataVars => { + const state = reactive({ + loading: true, + error: false, + data: {} + }); + + const fetchData = async () => { + state.loading = true; + setTimeout(() => { + state.data = { text: 'example' }; + state.loading = false; + }, 4000); + } + + const hasData = computed(() => state.data && !!state.data.text) + + return { + ...toRefs(state), + fetchData, + hasData + } +} +``` + +新创建的函数现在返回了可被用于组件的一组响应式变量 (**loading、error、data**,及 **hasData**) 及一个用来执行数据获取任务的异步函数 (**fetchData**,将会改变上述响应式变量) 。 + +而后,来使用 Composition API 重构组件: + +```Vue + + + + + + + +``` + +正如你所注意到的,我们的组件还包含了 setup 方法,由其调用 **useFetchData** 函数,同时解构返回的变量和函数并将它们返回给组件实例。 + +在这个例子中,我在 mounted 生命周期钩子中使用了 **fetchData** 函数,但其实你可以在期望的任意位置调用它。无论何时,被该函数求值或改变的结果都会反映在组件中,因为它们都是响应式属性。 + +#### JSX 和 TSX + +现在假设我们想要将获取的数据传递到一个内部组件中。借助 VueJS 有多种实现的方法,但我却想使用 **TSX** (你若更喜欢 **JSX** 也行) 来重构代码: + +```Vue + +``` + +我知道这看起来很像 React,但我相信这开启了以更好的方法优化组合方式的许多可能之门。 + +这其实很易懂,它完成了和模板同样的事情,但我们将 HTML 部分移入了 render 函数中。 + +我们尚未完成将数据传递进内部组件的任务,实际上我们像下面这样改进一点代码就行,也就是将所有东西导出成一个我们可复用的函数: + +```TSX +import useFetchData from '../composables/use-fetch-data'; +import { defineComponent } from '@vue/composition-api'; + +export default () => defineComponent({ + setup() { + const { loading, error, data, fetchData, hasData } = useFetchData(); + return { + loading, + error, + data, fetchData, + hasData + } + }, + mounted() { + this.fetchData(); + }, + render() { + return ( +
+ { this.loading &&
Loading ...
} + { this.error &&
An Error occured, please try again
} + {
{ this.data }
} +
+ ) + } +}); +``` + +现在我们已经更上一层楼了,摆脱 **SFC** (单文件组件 -- Single File Component 文件) 后我们就可以真正的改进组织方式了。 + +在此阶段,我们使用 defineComponent 创建了一个使用 Composition API 的组件并依托 JSX/TSX 消除了模板部分。这种方式的妙处在于可以将一个组件视为一个函数并自如运用函数式编程范式(如一级函数、纯函数等等……)了。 + +举例来说,render 函数也包含了一个显示数据的 div,但想象下若将一个组件作为刚才所导出函数的一个参数,并在返回的 JSX/TSX 中使用它(将响应/数据作为属性传递给组件)是如何的呢。 + +看起来可能会是这样的: + +```TSX +import useFetchData from '../composables/use-fetch-data'; +import { defineComponent } from '@vue/composition-api'; +import { Component } from 'vue'; + +export default (component: Component) => defineComponent({ + setup() { + const { loading, error, data, fetchData, hasData } = useFetchData(); + return { + loading, + error, + data, fetchData, + hasData + } + }, + mounted() { + this.fetchData(); + }, + render() { + const injectedComponentProps = { + data: this.data + } + return ( +
+ { this.loading &&
Loading ...
} + { this.error &&
An Error occured, please try again
} + +
+ ) + } +}); +``` + +现在我们正期待着将一个组件作为参数并在 render 函数中使用它。 + +还可以做得更多。 + +实际上,我们也可以期待将 **useFetchData** 函数作为所导出函数的一个参数。 + +```TSX +import useFetchData from '../composables/use-fetch-data'; +import { defineComponent, ComputedRef, Ref } from '@vue/composition-api'; +import { Component } from 'vue'; + +interface FetchDataVars { + loading: Ref; + error: Ref; + data: Ref; + fetchData: Function; + hasData: ComputedRef +} + +type FetchData = () => FetchDataVars ; + +export default (component: Component, factoryFetchData: FetchData) => defineComponent({ + setup() { + const { loading, error, data, fetchData, hasData } = factoryFetchData(); + return { + loading, + error, + data, fetchData, + hasData + } + }, + mounted() { + this.fetchData(); + }, + render() { + const injectedComponentProps = { + data: this.data + } + return ( +
+ { this.loading &&
Loading ...
} + { this.error &&
An Error occured, please try again
} + +
+ ) + } +}); +``` + +借助这些改变,在组件之上,接受一个类型为 **FetchData** 并返回一组符合预期的变量/函数/计算值的 **函数** 作为参数,就可以使用包装过的新组件。 + +这是一种依托函数式途径达成的相当有用的替代继承/扩展的方法。所以,不同于扩展已有的组件并覆写组件的函数的是,我们可以真正传入期望的组件和函数了。Typescript 在此仅有助于强类型化和类型推断,所以只用 Javascript 也是足够的。 + +例如,如果我们想要使用它,看起来会是这样的: + +```TypeScript +import withLoaderAndFetcher from './components/withLoaderAndFetcher'; + + +import useFetchDataForEndpointOne from './composables/useFetchDataForEndpointOne' +import useFetchDataForEndpointTwo from './composables/useFetchDataForEndpointTwo' +import useFetchDataForEndpointThree from './composables/useFetchDataForEndpointThree' + + +import ComponentA from './components/ComponentA.vue'; +import ComponentB from './components/ComponentB.vue'; +import ComponentC from './components/ComponentC.vue'; + + +const composedA = withLoaderAndFetcher(ComponentA, useFetchDataForEndpointOne); +const composedB = withLoaderAndFetcher(ComponentB, useFetchDataForEndpointTwo); +const composedC = withLoaderAndFetcher(ComponentC, useFetchDataForEndpointThree); +``` + +我们将上例导出的函数称为 **withLoaderAndFetcher** 并使用其组合了 3 个不同的组件和 3 个不同的函数(装饰者模式)。 + +这项工作还能推进得更远,但我想展示的是达到这种状态的可能性并增加趋向函数式组合方式的方法数量。这只是示例代码,也可能不会工作得很好,但这种想法和概念才是要义。 + +干杯 :) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/big-data-lambda-architecture-in-a-nutshell.md b/article/2020/big-data-lambda-architecture-in-a-nutshell.md new file mode 100644 index 00000000000..f2b2f8f3b7f --- /dev/null +++ b/article/2020/big-data-lambda-architecture-in-a-nutshell.md @@ -0,0 +1,125 @@ +> * 原文地址:[Big Data: Lambda Architecture in a nutshell](https://levelup.gitconnected.com/big-data-lambda-architecture-in-a-nutshell-fd5e04b12acc) +> * 原文作者:[Trung Anh Dang](https://medium.com/@dangtrunganh) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/big-data-lambda-architecture-in-a-nutshell.md](https://github.com/xitu/gold-miner/blob/master/article/2020/big-data-lambda-architecture-in-a-nutshell.md) +> * 译者:[jackwener](https://github.com/jackwener) +> * 校对者:[zenblo](https://github.com/zenblo)、[bljessica](https://github.com/bljessica) + +# 大数据:简述 Lambda 架构 + +#### 我们如何对抗 CAP 理论? + +![CAP 理论](https://cdn-images-1.medium.com/max/2730/1*ZyXE41bENSEUP29slqpQyQ.png) + +计算机科学中有一个 CAP 定理,分布式数据存储不可能同时提供以下三个保证中的两个以上。 + +* **一致性**:每个节点读取的是最新结果或者是报错。 +* **可用性**:每个请求都会收到一个(非错误)响应,但不保证它包含最新的写入。 +* **分区容错**:尽管节点之间的网络丢弃(或延迟了)任意数量的消息,系统仍继续运行。 + +## 简史 + +2011年,内森·马兹(Nathan Marz)在他的博客中提出了一种解决 CAP 定理局限性的重要方法,即 Lambda 架构。 + +![Lambda架构](https://cdn-images-1.medium.com/max/2730/1*RX4WviL_wF7vVChcQUgyzg.png) + +## 工作原理 + +让我们仔细看看 Lambda 架构。Lambda 架构分为三层: 批处理层(batch layer),加速层(speed layer),和服务层(serving layer)。 + +> 它结合了对同一数据的实时(real-time)和批量(batches)处理。 + +**首先**,传入的实时数据流在批处理层(batch layer)存储在主数据集中,并在加速层(speed layer)存储在内存缓存中。**然后**对批处理层中的数据建索引,且通过批处理视图使之可用。加速层(speed layer)中的实时数据通过实时视图(real-time views)暴露出来。 **最后**,批处理视图和实时视图都可以独立查询,也可以一起查询,以回答任何历史的或实时的问题。 + +#### 批处理层(Batch layer) + +该层负责管理主数据集。主数据集中的数据必须具有以下三个属性。 + +- 数据是原始的 +- 数据是不可变的 +- 数据永远是真实的 + +主数据集是正确性的保证(source of truth)。即使丢失所有服务层数据集和加速层数据集,也可以从主数据集中重建应用程序。 + +批处理层还将主数据集预计算到批处理视图(batch views)中,以便能进行低延迟查询。 + +![批处理视图的预计算](https://cdn-images-1.medium.com/max/2730/1*0fEm3ceh7KurPVJ027S2TA.png) + +由于我们的主数据集在不断增长,因此我们必须制定一种策略,以便在有新数据可用时管理批处理视图(batch views)。 + +* **重新计算法**:抛弃旧的批处理视图,重新计算整个主数据集的函数。 +* **增量算法**:当新数据到达时,直接更新视图。 + +#### 加速层(Speed layer) + +加速层批处理视图建立索引便于能快速的即席查询(Ad hoc queries),它存储实时视图并处理传入的数据流,以便更新这些视图。基础存储层必须满足以下场景。 + +* **随机读**:支持快速随机读取以快速响应查询。 +* **随机写**:为了支持增量算法,必须尽可能的以低延迟修改实时视图。 +* **可伸缩性**:实时视图应随它们存储的数据量和应用程序所需的读/写速率进行缩放。 +* **容错性**:当机器故障,实时视图应还能继续正常运行。 + +#### 服务层(Serving layer) + +该层提供了主数据集上执行的计算结果的低延迟访问。读取速度可以通过数据附加的索引来加速。与加速层类似,该层也必须满足以下要求,例如随机读取,批量写入,可伸缩性和容错能力。 + +## Lambda 架构几乎可以满足所有属性 + +Lambda 体系结构基于几个假定:容错、即席查询、可伸缩性、可扩展性。 + +* **容错:** Lambda 架构为大数据系统提供了更友好的容错能力,一旦发生错误,我们可以修复算法或从头开始重新计算视图。 +* **即席查询:** 批处理层允许针对任何数据进行临时查询。 +* **可伸缩性:** 所有的批处理层、加速层和服务层都很容易扩展。因为它们都是完全分布式的系统,我们可以通过增加新机器来轻松地扩大规模。 +* **扩展:** 添加视图是容易的,只是给主数据集添加几个新的函数。 + +## 一些问题 + +#### 层之间的代码如何同步 + +解决此问题的方法之一是通过使用通用库或引入流之间共享的某种抽象来为各层提供通用代码库。譬如 Summingbird or Lambdoop,Casado 这些框架 + +#### 我们可以移除速度层(speed layer)吗? + +是的,在许多应用程序中都不需要速度层(speed layer)。如果我们缩短批处理周期,则可以减少数据可用性中的延迟。另一方面,用于访问存储在 Hadoop 上的数据的新的更快的工具(例如 Impala , Drill 或 Tez 的新版本等),使在合理时间内对数据执行某些操作成为可能。 + +#### 我们可以丢弃批处理层(batch layer)并处理速度层(speed layer)中的所有内容吗? + +是的,一个例子是 Kappa Kreps 架构,它的示例建议在流中处理传入的数据,并且每当需要更大的历史记录时,它将从 Kafka 缓冲区中重新流化,或者如果我们必须进一步追溯到历史数据集群。 + +## 如何实现 Lambda 架构? + +我们可以使用 Hadoop 数据湖在现实世界中实现此架构,在该数据湖中,HDFS 用于存储主数据集, Spark(或 Storm)可构成速度层(speed layer), HBase(或 Cassandra)作为服务层,由 Hive 创建可查询的视图。 + +![Lambda 架构实现的一个例子](https://cdn-images-1.medium.com/max/2730/1*4oItXvPnvE04LCB9Z2-BZw.png) + +## 使用 Lambda 架构的公司 + +#### Yahoo + +为了在广告数据仓库上进行分析,雅虎采取了类似的方法,也使用了 Apache Storm,Apache Hadoop 和 Druid²。 + +#### Netflix + +Netflix Suro 项目是 Netflix 数据管道的主干,该管道有独立的数据处理路径,但不严格遵循 lambda 体系结构,因为这些路径可能用于不同的目的,不一定提供相同类型的视图(views)。 + +**LinkedIn** + +使用 Apache Calcite 来桥接离线和近线计算。 + +## 总结 + +请记住: batch view = function (all data) realtime view = function (real-time view new data) and query = function (batch view real-time view). + +很容易,对吧? + +## 参考文献 + +- [1] [http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html](http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html) +- [2] [http://www.slideshare.net/Hadoop_Summit/interactive-analytics-in-human-time?next_slideshow=1](http://www.slideshare.net/Hadoop_Summit/interactive-analytics-in-human-time?next_slideshow=1) +- [3] [https://netflixtechblog.com/announcing-suro-backbone-of-netflixs-data-pipeline-5c660ca917b6](https://netflixtechblog.com/announcing-suro-backbone-of-netflixs-data-pipeline-5c660ca917b6) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/build-a-graphql-server-with-spring-boot-and-mysql.md b/article/2020/build-a-graphql-server-with-spring-boot-and-mysql.md new file mode 100644 index 00000000000..2be16faa246 --- /dev/null +++ b/article/2020/build-a-graphql-server-with-spring-boot-and-mysql.md @@ -0,0 +1,518 @@ +> * 原文地址:[Build a GraphQL Server With Spring Boot and MySQL](https://medium.com/better-programming/build-a-graphql-server-with-spring-boot-and-mysql-df427cbba26d) +> * 原文作者:[Yasas Sandeepa](https://medium.com/@yasassandeepa007) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/build-a-graphql-server-with-spring-boot-and-mysql.md](https://github.com/xitu/gold-miner/blob/master/article/2020/build-a-graphql-server-with-spring-boot-and-mysql.md) +> * 译者:[samyu2000](https://github.com/samyu2000) +> * 校对者:[zenblo](https://github.com/zenblo), [regon-cao](https://github.com/regon-cao) + +# 使用 SpringBoot 和 MySQL 构建 GraphQL 服务端应用程序 + +![Photo modified by me using resources of [John Peel](https://unsplash.com/@johnpeel?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/3840/1*zttc2YOayk-LuiTYy18c9A.png) + +你是否考虑过客户端直接控制 API 请求?客户端能否请求其实际需要的数据并精确获取?如果你对这些问题感到惊讶,我敢肯定你从来没听说过 GraphQL。 + +上述问题的答案是肯定的,因为使用 GraphQL 就可以实现。如果你没听说过,不必担心。我将带领你走进最新的、令人惊叹的 GraphQL 世界,并且如果本文给你带来巨大的收益,你就不会感到遗憾。 + +一般来说,你需要熟悉 Java 语言、Spring Boot 框架和 REST APIs 相关知识。不需要你有过使用 GraphQL 的经历。你可能对这个话题非常有兴趣。那还等什么呢?但在上手实践之前,我会大致介绍 GraphQL,以及它独具特色的原因。 + +## 入手 GraphQL 的第一步 + +我想,你可能在努力寻找关于 GraphQL 的相关信息吧。GraphQL 到底是什么呢?深呼吸一下,听我道来。简单的来说,它是一种数据查询和操作语言,可以在 API 中使用。 + +GraphQL 提供了一个简易的终端,可以用于从前端接收查询请求,并返回相应的查询结果,而且可以根据需要,精准获取部分数据。所以我不得不说:不要低估这个通用客户端的功能。 + +看了这幅 GIF 图片,就清晰明了了。这也是我们将要实现的应用程序的一部分功能。 + +![GraphQL 如何运行](https://cdn-images-1.medium.com/max/3472/1*aXd1Atpt9B8QI2s9r3r_Ew.gif) + +GraphQL 如今在数以百计、大大小小的公司广泛使用,包括 Facebook(GraphQL 本来就是由 Facebook 于2012年发明的,并于2015年开源)、Credit Karma、GitHub、Intuit、PayPal、the New York Times 等等。 + +嘿,等等。需要介绍一下 REST。难道它还不够有用吗?我们来了解一下这个。 + +## GraphQL 与 REST 的对比 + +由于 REST API 的广泛使用,我们都对它很熟悉。但如今,使用 GraphQL 是大势所趋,因为它更灵活、性能更好。 + +那么,REST 和 GraphQL 本质上有什么不同呢?REST 是一种开发网络应用程序的架构思想。而 GraphQL 是一种查询语言、一种技术规范和一系列单点操作工具的集合。我来举个例子,让大家更好地了解这些内容。 + +假定你需要查询书本信息。同时,你还要查询作者信息(书本和作者是两个不同的实体)。典型的方法是发送两个 GET 类型的请求。 + +``` +localhost:8080/book/:id +localhost:8080/author/:id +``` + + +但使用 GraphQL 就可以通过一个单一的 API 端点获取到所有信息。 + +``` +localhost:8080/graphql +``` + +正如前面的那幅 GIF 图片中那样,如果你要在一个终端把一些信息归集起来,可以过滤某些不需要的字段。但如果使用 REST,只能得到全部的数据集,无法过滤某些数据。 + + +有时候,响应的数据不能直接使用(比如嵌套的数据),你为了获取实际需要的数据只得另行请求。但另一方面,响应的数据有很多是你并不需要的,你只需要一两个字段。 + +这种现象称为读取不足和过度读取。GraphQL 可以解决这些问题,优化你的程序。REST 跟 GraphQL 相比,REST 就像是一家没有服务员的餐厅。 + +无论如何,使用 GraphQL 必然存在学习曲线,它与 REST API 固然存在一些差别,但是它确实值得学习。如果你能开发用户友好的大型应用程序,用户只获取到他需要的数据,没有其他多余的东西,也是令人满意的。 + +使用 GraphQL 的一个额外好处是,由于不需要处理大量数据,应用程序的性能将会大幅度提升。任何性能上的提升都是巨大的胜利。 + +许多编程语言,比如 Java、JavaScript、Python、Scala 等等,都支持 GraphQL。你可以访问[GraphQL 官网](https://graphql.org/code/)了解各种服务端和客户端语言的相关信息。 + +由于我比较熟悉 Java 和 JavaScript,关于这些技术的文章较少,我考虑写一个 Spring Boot 应用程序。也有一些关于 Node.js 的文章和手册,实现它并不难。 + +如果你需要了解如何使用 Node.js 实现 GraphQL 服务端,请在评论区留言,我也很愿意就此话题写一篇文章。 + +好,讨论够了。我们进入实践环节。没有什么比亲自动手实践更好的方法了。 + +## 基础:创建项目 + +我正着手开发一个 APP,实现获取用户和他们发的帖子的功能。我把这个项目命名为 **WriteUp**,以后还要进行二次开发。 + +我从头开始开发这个 APP。如果你熟悉 Spring Boot,可以快速浏览这部分基础的内容。第一步,我们需要使用 [Spring Initializr](https://start.spring.io/) 或IntelliJ idea 新建 Spring Boot 工程。 + +![](https://cdn-images-1.medium.com/max/3190/1*DEPldJV7a6gZfG_VGlr1HQ.png) + +![Screenshots provided by the author.](https://cdn-images-1.medium.com/max/3384/1*ZueIgy3oLM7lND_Eo-4leQ.png) + +确保项目中添加了这些依赖。 + + +1. Spring Data JPA: 用于处理大多数基于 JDBC 的数据库访问操作,减少 JPA 中的模板文件代码 +2. MySQL Driver: 用于管理 Java 程序与 MySQL 数据库的连接 +3. Lombok: 减少模型对象类中的代码,使用 Lombok 注解可以自动创建 get/set 方法。 + +![Screenshot provided by the author.](https://cdn-images-1.medium.com/max/2740/1*gj881gOHnanEEmyWoStkEw.png) + +一切就绪。我们休息一会儿,等待 IntelliJ 为项目配置依赖。 + +## 要点:配置基础 + +至于初始化设置,我们可以创建实体模型并向 MySQL 数据库添加一些虚拟数据。 + +我创建了一个包,命名为 model,在这个包中定义了 User 和 Post 两个类,代码较为简洁,由于有注解,get/set 方法会自动生成,就不需要定义了。但切记,你必须创建一个不包含 ID 字段的构造方法,这个构造方法在实例化时会被调用。 + +![User and Post Entities](https://cdn-images-1.medium.com/max/3840/1*rSxPRxwWgyq1ZF5AiwF2OQ.png) + +```Java +package com.example.writeup.model; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import javax.persistence.*; +import java.util.Date; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "USER") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "USER_ID") + private Integer userId; + + @Column(name = "FIRST_NAME") + private String firstName; + + @Column(name = "LAST_NAME") + private String lastName; + + @Column(name = "DOB") + private Date dob; + + @Column(name = "ADDRESS") + private String address; + + @Column(name = "POST_ID") + private Integer postId; + + public User(String firstName, String lastName, Date dob, String address, Integer postId) { + this.firstName = firstName; + this.lastName = lastName; + this.dob = dob; + this.address = address; + this.postId = postId; + } +} +``` + +我们来创建 repository 层,它是用于与数据库建立连接的。我新建一个名为 repository 的包,在此包中创建两个 JpaRepository 的子接口,分别对应于 User 和 Post。 + +可以继承 CrudRepository,但我更倾向于继承 JpaRepository,因为它的 find 方法返回一个普通列表对象,不像 CrudRepository 那样返回可迭代列表对象。(欲详细了解这些 Repository 接口,可以点击查看[这里](https://stackoverflow.com/questions/14014086/what-is-difference-between-crudrepository-and-jparepository-interfaces-in-spring))。 + +```Java +package com.example.writeup.repository; + +import com.example.writeup.model.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + +} + +``` + +接着,我写一个组件类,向数据库添加虚拟数据。还需要创建 service 包,在这个包里定义一个 DataLoader 类。这个类负责在应用程序初始化时添加某些虚拟数据。 + +```Java +package com.example.writeup.service; + +import com.example.writeup.model.Post; +import com.example.writeup.model.User; +import com.example.writeup.repository.PostRepository; +import com.example.writeup.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.ThreadLocalRandom; + +@Service +public class DataLoader { + + @Autowired + private UserRepository userRepository; + + @Autowired + private PostRepository postRepository; + + @PostConstruct + public void loadData(){ + + User user1 = new User("Yasas" ,"Sandeepa",DataLoader.getRandomDate(),"Mount Pleasant Estate Galle",1); + User user2 = new User("Sahan" ,"Rambukkna",DataLoader.getRandomDate(),"Delkanda Nugegoda",2); + User user3 = new User("Ranuk" ,"Silva",DataLoader.getRandomDate(),"Yalawatta gampaha",3); + + Post post1 = new Post("Graphql with SpringBoot",DataLoader.getRandomDate()); + Post post2 = new Post("Flutter with Firebase",DataLoader.getRandomDate()); + Post post3 = new Post("Nodejs Authentication with JWT",DataLoader.getRandomDate()); + + postRepository.save(post1); + postRepository.save(post2); + postRepository.save(post3); + + userRepository.save(user1); + userRepository.save(user2); + userRepository.save(user3); + + } + + + public static Date getRandomDate(){ + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, 1990); + calendar.set(Calendar.MONTH, 1); + calendar.set(Calendar.DATE, 2); + Date date1 = calendar.getTime(); + calendar.set(Calendar.YEAR, 1996); + Date date2 = calendar.getTime(); + long startMillis = date1.getTime(); + long endMillis = date2.getTime(); + long randomMillisSinceEpoch = ThreadLocalRandom + .current() + .nextLong(startMillis, endMillis); + + return new Date(randomMillisSinceEpoch); + } + +} + +``` + +好了。现在你需要在 application.properties 文件中进行配置。同时也要确保已经创建了数据库,并且在应用程序中设置了可与 MySQL 数据库建立连接的凭证。 + +```Java Properties +server.port=7000 + +#mysql properties +spring.jpa.generate-ddl=true +spring.datasource.url=jdbc:mysql://localhost/writeup +spring.datasource.username=user +spring.datasource.password=password +spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver +spring.jpa.hibernate.ddl-auto=create +``` + +已经完成了基础的架构。嘿,控制器呢?如果你认为需要有控制器而我忘了,你就完全错了。在 REST API 中,我们使用控制器是为了处理多个端点。但在 GraphQL 中,你也了解的,只需要一个 API 端点,所以控制器是不需要的。 + +好,我们来做一个例子,检验是否一切正常。 + +![](https://cdn-images-1.medium.com/max/3630/1*ntnM4Gn6fdr7kIthZbGvWw.png) + +![Screenshots provided by the author.](https://cdn-images-1.medium.com/max/2016/1*MSaXfP1WhsFaMrPT94A8FA.png) + +好,你可以看到,项目的基础架构正常运行。我们继续后面的步骤。 + +## 重点环节:为项目装配 GraphQL 相关功能 + +先做重要的事!你需要为项目添加 GraphQL 依赖。 +在 pom.xml 文件的 dependencies 节点中加入这两个依赖包,并点击右上角的 **m** 图标,更新项目。 + +``` + + + com.graphql-java + graphql-spring-boot-starter + 5.0.2 + + + com.graphql-java + graphql-java-tools + 5.2.4 + +``` + +![Screenshot provided by the author.](https://cdn-images-1.medium.com/max/3406/1*I6ecTzyeFI8UQL4ica3lcg.png) + +GraphQL 有两个主要的构建模块:模式和解析程序。在应用程序中实现 GraphQL 的第一步是定义一个模式。 + +GraphQL 模式中最基础的组件是 type, 它代表一个对象(类似于学生、动物等)和对象的属性,你可以从你开发的程序中获取这些对象。 + +``` +type Director { + name: String! + age: Int + films: [Film] +} +``` + +在 Java 等语言中,有很多原始的和非原始的数据类型。但在这里我们只需要了解这几个数据类型(也可称为 Scalar 类型)。 + +* Int: 有符号的 32 位整型 +* Float: 有符号的双精度浮点值 +* String: 使用 UTF-8 编码的字符串 +* Boolean: 取值范围为 true/false +* ID: 唯一性的标识符 + +当然,你也可以根据你的需要定义 Scalar 类型。 +(例如 Date, Currency 等等) + +在模式中大多数数据类型不过是普通的类型,但有两种类型较为特殊。 + +1. Query: 获取数据的入口 +2. Mutation: 更新数据的入口 + +关于这些概念,你可以访问 [GraphQL 官网](https://graphql.org)了解更多。 + +OK,我们来定义模式。需要在资源目录下创建 graphql 目录,并在 graphql 目录中创建一个 schema.graphqls 文件。(需要确保文件的扩展名为 .graphqls,它是一个模式文件) + + +如果你在 IntelliJ 中已经安装了 GraphQL 插件,你创建文件后就能看到 GraphQL 的图标。通过在插件面板中搜索,就可以安装这个插件。它对 GraphQL 模式文件的开发很有用。 + +![Screenshot provided by the author.](https://cdn-images-1.medium.com/max/3308/1*9m9djB1PukLtoQCU348zbQ.png) + +以下是我定义的模式文件。首先我定义了 query 属性,这些代码很容易理解。后面我还会讲解 Mutation 类型。 + +``` +schema { + query: Query, +} + +type Query{ + # Fetch All Users + getAllUsers:[User] +} + +type User { + userId : ID!, + firstName :String, + lastName :String, + dob:String, + address:String, + postId : Int, +} +``` + +请确保在代码种添加这些注释。这样做的目的是为了使用第三方工具测试服务端时可以查看相关的描述信息。(我们在大多数情况下会使用 Altair 客户端来测试,不会使用 Postman) + +现在我们需要定义解析器。(如果你不理解这里的 `getAllUsers` 是什么(它不是方法,而是一个字段)以及它代表什么,等会儿会解释) + +解析器是给定了父对象、参数和执行上下文的函数字段。他们负责返回对应函数的结果给这个字段。 + +实现解析器的方法有若干种。很多行业级的大型项目的做法是在根目录创建一个名为 `graphql` 的包,在这个包中定义解析器接口和相应的实现。请求和响应的映射类型也可以在这些包中定义。 + +![Industry Standard for defining resolvers](https://cdn-images-1.medium.com/max/3840/1*eqGqp_oqVxsE1at4tSwFVA.png) + +因为这是为了帮助大家理解概念,我就在项目的 service 包内实现它。 + +```Java +package com.example.writeup.service; + +import com.coxautodev.graphql.tools.GraphQLQueryResolver; +import com.example.writeup.model.User; +import com.example.writeup.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.List; + +@Service +public class UserService implements GraphQLQueryResolver { + + @Autowired + private UserRepository userRepository; + + public List getAllUsers() { + return userRepository.findAll(); + } + +} +``` + +我新建一个名为 `UserService` 的类,在这个类中提供 `GraphQLQueryResolver` 的具体实现,GraphQLQueryResolver 是 `graphql-java-tools` 库中的接口。 + +然后,为了获取数据库连接,我把 UserRepository 类的对象自动注入到 UserService 中。(当然这种注入方式不建议在最终版本中使用。你应该点击 Autowired 注解,接着代码区域左侧会出现黄色图标,再点击这个黄色图标,会弹出推荐的做法,然后根据系统推荐的做法修改代码) + +现在你应该想到 GraphQL 模式文件中的 `getALlUsers` 字段。它跟 UserService 类中的方法名一样。所以我在这个类中定义此方法,并像模式文件中声明的那样返回 User 对象的列表。 + +![Folder structure and the service layer](https://cdn-images-1.medium.com/max/2672/1*dFmcMBaBBUTF8YAJkKweYg.png) + +最后,我们需要在 `application.properties` 中配置 GraphQL 相关属性。 + +``` +#graphql properties +graphql.servlet.corsEnabled=true +graphql.servlet.mapping=/graphql +graphql.servlet.enabled=true +``` + +从配置中可以看出, `/graphql` 端点可以接收请求。所以不需要定义控制器。 + +一切都准备就绪了。我们的服务器在等待访问。测试一下,你应该看到类似于这样的信息:**Started WriteupApplication...(JVM running…)**。 + +现在继续进行测试。我前面提到过,可以使用 Altair 客户端对那些端点进行测试。Altair 既有桌面版,也有相应的浏览器插件,都可以用来进行测试。你可以点击[这里](https://altair.sirmuel.design/docs/)下载安装 Altair 客户端。 + +我们现在使用 Altair 访问服务器上的端点。 + +![[http://localhost:7000/graphql](http://localhost:7000/graphql)](https://cdn-images-1.medium.com/max/3316/1*nbDmknJv8-rYGJo2u9N2gA.png) + +如果你重新加载文档部分,可以看到带注释的字段。点击它可以了解更多详细信息。在左侧输入查询语句,可以发现 Altair 提供了输入内容自动完成。点击运行查询或发送请求按钮,就可以得到查询结果。 + +![Screenshot provided by the author.](https://cdn-images-1.medium.com/max/3264/1*-BT7ol2I85_R2NtYeCRoBQ.png) + +看,多么酷炫。使用 GraphQL,我们能得到所需要的信息。我估计现在你应该理解相关概念,并能够使用它们了。下面我要介绍 Mutation 类型了。 + +第一步,你可以在模式文件中添加一个 Mutation 类型字段。我已经开发了更新地址的功能,作为示例。如下所示,我已经在模式文件中添加了 mutation。下面是完整的模式文件代码。 + +```GraphQL +schema { + query: Query, + mutation: Mutation, +} + +type Query{ + # Fetch All Users + getAllUsers:[User] + +} + +type Mutation { + # Update the user address + updateUserAddress(userId:Int,address:String): User +} + +type User { + userId : ID!, + firstName :String, + lastName :String, + dob:String, + address:String, + postId : Int, +} +``` + +我在 UserRepository 中加入了更新用户的查询操作,相应的 SQL 语句带有输入参数,由方法的参数代入。 + +```Java +package com.example.writeup.repository; + +import com.example.writeup.model.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +@Repository +public interface UserRepository extends JpaRepository { + + @Transactional + @Modifying + @Query(value = "UPDATE user SET address = ?1 WHERE user_id = ?2 ", nativeQuery = true) + int updateUserAddress(String address, Integer user_id); + +} +``` + +在 UserService 中,需要实现 GraphQLMutationResolver 接口声明的方法。我们在这个类中还定义了 updateUserAdress 方法。所有的方法的访问权限都是 public,无访问限制。UserService 类的代码如下。 + +```Java +package com.example.writeup.service; + +import com.coxautodev.graphql.tools.GraphQLMutationResolver; +import com.coxautodev.graphql.tools.GraphQLQueryResolver; +import com.example.writeup.model.User; +import com.example.writeup.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserService implements GraphQLQueryResolver, GraphQLMutationResolver { + + @Autowired + private UserRepository userRepository; + + public List getAllUsers() { + return userRepository.findAll(); + } + + public User updateUserAddress(Integer userId, String address) throws Exception { + try { + userRepository.updateUserAddress(address, userId); + User user = userRepository.findById(userId).get(); + return user; + } catch (Exception e) { + throw new Exception(e); + } + + } + +} +``` + +好了。我们也定义了 mutation。现在进行测试。可以通过查看数据库确认相关功能是否实现。 + +![Screenshot provided by the author.](https://cdn-images-1.medium.com/max/3456/1*voqYoBAxQ6UyQdvfiX2SDw.png) + +太好了。你已经掌握了 GraphQL 中的大多数概念。但值得我们探索的还有很多。等等,我还有些东西要补充。 + +除了 Query 和 Mutation,GraphQL 还支持一种操作类型,叫做 **subscriptions**。 + +与 Query 类似,subscription 提供数据查询功能。但它跟 Query 又有所不同,它跟 GraphQL 服务端保持着连接(通俗的来说是使用 Web Socket 维持连接)。它能提供服务端主动推送更新消息的功能。 + +如果需要把后台更新的数据实时通知到客户端,比如用户通知、重要更新、文件修改等,subscription 很有用。 + +关于 GraphQL 的使用,还有很多话题可以讨论,比如错误处理、跟 spring-security 的整合、文本验证等等。关于这些话题,我也会发一些文章,供大家学习参考。 + +## 总结 + +这是关于本文内容的一个[小型示范项目](https://youtu.be/D_YDhxLtjpI),项目完整的源代码见下面的 Github 仓库。 + +资源:[WriteUp 项目源代码](https://github.com/Yasas4D/WriteUp)。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/building-a-design-system-and-a-component-library.md b/article/2020/building-a-design-system-and-a-component-library.md index eb886ba156e..27909b49cae 100644 --- a/article/2020/building-a-design-system-and-a-component-library.md +++ b/article/2020/building-a-design-system-and-a-component-library.md @@ -2,112 +2,112 @@ > * 原文作者:[Bruno Sampaio](https://medium.com/@bensampaio) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/building-a-design-system-and-a-component-library.md](https://github.com/xitu/gold-miner/blob/master/article/2020/building-a-design-system-and-a-component-library.md) -> * 译者: -> * 校对者: +> * 译者:[Charlo](https://github.com/Charlo-O),[lsvih](https://github.com/lsvih) +> * 校对者:[贺雪 Amy](https://github.com/Shirley-He-Maker),[Chorer](https://github.com/Chorer) -# Building a design system and a component library +# 构建设计系统和组件库 ![](https://cdn-images-1.medium.com/max/3200/0*d_TQ28ARHmOchSvG) -This post is based on the series of posts: **Modernizing a jQuery frontend with React**. If you want to get a better overview of the motivation for this post we recommend you first read our [initial post](https://medium.com/@bensampaio/8598b252ceb3). +本文基于系列文章:**用 React 重构 jQuery 前端项目**。如果你想更好地了解我们写这篇文章的动机,建议先阅读[前一篇文章](https://medium.com/@bensampaio/8598b252ceb3)。 -When we started rebuilding our frontend in React it wasn’t yet part of our design and development workflow to think about reusable UI components. Our jQuery frontend was built mainly out of Twitter bootstrap components, which were adapted for specific use cases or extended with additional functionality. New designs were created for each new feature by copying some design elements from older designs and improving or adapting them there. As the team and the application kept growing, our components evolved in multiple directions. This resulted in multiple variants of text sizes, colors, buttons and links which led to a disjointed user experience across our application. +当我们开始在 React 中重构前端项目时,可复用 UI 组件还不在我们设计和开发工作流程之内。我们的 jQuery 前端项目主要是基于 Twitter 的 bootstrap 组件构建的,这些组件针为特定的用例进行了调整,或通过附加功能进行了扩展。我们通过从旧设计中汲取精华并加以改进,让每个特性都有了新的设计。随着团队和应用的不断发展,我们的各个组件朝着不同的方向改进,导致了文本大小、配色、按钮和链接出现了各种各样的变化,最终使得整个应用的用户体验脱节。 -Rebuilding our frontend in React was an opportunity for us to rethink our design and development workflow and focus on a more cohesive experience for the user. This was especially important since we knew we needed to make our app more accessible and responsive. This led to the creation of a component library which motivated the need for a design system. That process was difficult and slow at first but became exciting and useful over time. +在 React 中重构前端项目,给了我们重新思考设计和开发工作流的机会,也让我们有机会将重点放在为用户提供更统一的体验上。这一点非常重要,因为我们所需要做的,就是让应用程序更容易访问和能更快速地响应。这也促使了新的组件库的诞生,并继而驱动了设计系统的需求。这个迭代过程一开始非常困难且缓慢,但随着时间的推移,新的组件库和设计系统变得越来越实用,让开发人员和设计师兴奋不已。 -## What is a design system? +## 什么是设计系统? -A design system is a comprehensive guide on how to create, document and use UI components. It defines a collection of rules, constraints, principles and best practices that apply to all designs. The core element of a design system is a collection of UI components, such as buttons, links and tables. For each designed component you can have usage guidelines that document choices made during design, the rules that define the component, behavior and constraints, use cases and any other details that are easy to communicate through words. +设计系统是关于如何创建、组织存档和使用 UI 组件的综合指南。它定义了一组适用于所有设计的规则、约束、原则和最佳实践。设计系统的核心元素是一组 UI 组件,如按钮、链接和列表。对每个组件,你都可以为其附上说明,描述在设计期间为这个组件所做选择;以及为每个组件撰写文档,用以定义组件的规则、行为和约束,提供用例和其它可以通过文本描述的细节。 -## What is a component library? +## 什么是组件库? -A component library is a collection of reusable UI components implemented in a programming language. When supported by a design system it can also be seen as an interactive implementation of the designs and their guidelines. +组件库是用编程语言实现的可复用 UI 组件的集合。当得到设计系统的支持时,它也可以被视为设计及其指导方针的交互式实现。 -## Why should you care? +## 为什么要关心这个? -As [Airbnb’s Karri Saarinen](https://medium.com/airbnb-design/224748775e4e) stated: “A unified design system is essential to building better and faster; better because a cohesive experience is more easily understood by our users, and faster because it gives us a common language to work with”. +如 [Airbnb 的 Karri Saarinen](https://medium.com/airbnb-design/224748775e4e) 所言,统一的设计系统对于实现更好更快的构建来说,非常重要;更好的原因是用户更容易理解统一的体验,更快的原因是它为我们提供了一种共同的语言来进行协作。 -At Karify, it helps us to create and follow our own constraints. It helps us to create a cohesive user experience on a multitude of platforms and devices. And finally, it helps our team work smarter, faster and closer together. These are some of the advantages we found in more detail: +在 Karify 看来,设计系统可以帮助我们创建并遵循自己的设计准则,也可以帮助我们在多种平台和设备上创建出一个统一的用户体验。最后,它还可以帮助我们的团队更高效、更敏捷、更紧密地合作。以下是我们发现的一些更详细的优势: -* **Communication**: designers understand developers and vice-versa. Concepts that were previously difficult to understand for both sides are now much clearer. Talking about components and using the rules we defined in communication make the process of designing and developing much easier. -* **Consistency**: the look and feel of the application’s pages became the same. We know exactly what text size we should use for a heading or for normal text, what type of button we should use for a primary action, what colors to use to communicate the type of a certain action or piece of information, and how much spacing there should be between each type of element. If we decide to change any of those, then they can easily be changed across the entire design system, component library and application. -* **Collaboration**: designers and developers work closer together and are able to share ideas and insights more easily. Since it is easier to communicate it becomes easier to talk about functional constraints and to incorporate those in designs at an earlier phase. The use of a tool like [Zeplin](https://zeplin.io/) makes this process especially faster because it allows you to start a discussion in the context of any kind of detail in a design. -* **Documentation**: component guidelines provide clear information on how a component should look, be used, behave and why that is. If in the future a component design or implementation raises questions, it becomes easier to find the reasoning behind it and to prevent rethinking what has already been thought through before (unless it no longer makes sense). -* **Modularity**: all components represent small pieces of design and code with their limited set of rules and concerns. This enforces separation of concerns in both design and code. -* **Maintainability**: it becomes easier to keep designs and code up to date because when a component is touched all other components that use it are updated. This can also lead to extra work on older components but gives you visibility of the impact of your change. +* **沟通**:让设计师理解开发人员,也让开发人员理解设计师。以前对双方都很难理解的概念现在清晰多了。讨论组件和使用我们在沟通中约定的规则,会使得设计和开发过程更加容易。 +* **一致性**:应用程序页面的外观和体验变得统一。我们会知道一个标题或正常的文本应该使用的大小、应该为主要操作配置什么类型的按钮、什么颜色用来传达特定操作的类型或信息,以及每种类型的元素之间应该有多少间距。如果我们决定更改其中任何一个规范,就可以很容易地在整个设计系统、组件库和应用程序中对它们进行更改。 +* **协作**:设计师和开发人员工作得更紧密,能够更容易地分享想法和见解。由于沟通变得更容易,因此讨论功能限制以及在早期阶段将它们合并到设计中也变得更容易了。使用 [Zeplin](https://zeplin.io/) 之类的工具会使这个过程更加高效,因为它可以让设计师和开发人员针对设计的任何一处细节进行讨论。 +* **文档**:组件指南提供了关于组件的外观、使用、行为以及为什么这样做的详细信息。如果将来某个组件的设计或实现出现了问题,就更容易找到背后的原因,并避免了再次考虑之前已经考虑过的问题(除非它不再有意义)。 +* **模块化**:所有的组件都使用有限的规则和关注点来表示设计和代码的一小部分。这样就可以在设计和代码中实现关注点分离。 +* **可维护性**:这使设计和代码的更新变得更加容易,因为当一个组件被修改时,使用它的所有其它组件都会更新。虽然在旧组件上需要做一些额外的处理,但可以立竿见影地让你看到自己的修改造成的影响。 -As with any other approach we also found some disadvantages to the process of working with a design system: +与任何其它方法一样,我们在设计系统的开发中也发现了一些缺点: -* **Time consuming**: this was especially true in the beginning. Defining all the rules, constraints and base components like text, color and spacing can take quite a lot of discussion. Over time it becomes faster. It depends on how many new components you need to create before designing a new feature. But once you have a few it becomes super fast to reuse them in existing or new designs. The same applies to the development of the application. -* **Less creativity**: due to all the rules and constraints there is less space to be creative. However, this could also be seen as an advantage since that often leads to consistency. -* **Steep learning curve**: this applies mainly to new people joining the team because they will need to get acquainted with a lot of rules before being able to apply them consistently. On the other hand, it also makes it easier for them since the design system communicates the rules. -* **Complexity**: if there are components with too many dependencies on other components it can also become complex to maintain and reuse them. +* **耗费时间**:开始的时候尤其如此。定义所有规则、约束和基本组件(如文本、颜色和间距)需要进行大量讨论。随着时间的推移,这个过程会加快。这取决于在设计新特性之前需要创建多少新组件。但是一旦你有了一些组件,在现有的或新的设计中重用它们就会变得非常快。这同样适用于应用程序的开发。 +* **缺乏创造力**:由于受限于所有的规则和约束,创作空间减少了。不过,这也可以被视为一种优势,因为它带来了一致性。 +* **陡峭的学习曲线**:这主要是团队里新人面临的问题,因为他们将需要熟悉许多规则,才能熟练地应用它们。从另一个角度来说,这也使他们的学习更容易,因为设计系统本身已经传达了规则。 +* **复杂性**:如果有太多依赖于其他组件的组件,那么维护和重用它们也会变得很复杂。 -Don’t let these disadvantages scare you, though. It is part of the process to learn to minimize them. Over time, the advantages become more apparent than the disadvantages. +不过,不要让这些缺点吓到你。学习如何让这些缺点最小化,也是我们设计过程的一部分。随着时间的推移,优势变得比劣势更明显。 -## How can you get started? +## 如何开始呢? -First of all, we recommend you get acquainted with the concept of [Atomic Design](https://bradfrost.com/blog/post/atomic-web-design/) alongside with [design system best practices](https://airbnb.design/systems-thinking-unlocked/) and examples of design systems like [the one of Airbnb](https://airbnb.design/building-a-visual-language). Additionally, you should also choose a tool where to build your design system. We chose [Sketch](https://www.sketch.com/) but there are other alternatives like [Figma](https://www.figma.com/). +首先,我们建议你了解[原子设计](https://bradfrost.com/blog/post/atomic-web-design/)的概念以及[设计系统的最佳实践](https://airbnb.design/systems-thinking-unlocked/)和诸如 [Airbnb](https://airbnb.design/building-a-visual-language) 这样的设计系统的例子。此外,你还应该选择用于构建设计系统的工具。我们选择了 [Sketch](https://www.sketch.com/),但也有其它选择,比如 [Figma](https://www.figma.com/)。 -From there you can start defining your set of colors, typography styles and spacing sizes which will be your first atoms. This will allow you to start defining your first molecules like buttons, links, surfaces and so on. It’s likely that you will miss some use cases in this first iteration which will lead to a few more iterations until it all feels right and future proof. +接着,你就可以开始定义属于你的一套色彩、排版样式和间距尺寸,这将是你的第一个“原子”。它将允许你开始定义你的第一个“分子”,如按钮、链接和页面等。在第一次迭代中,你很可能会遗漏一些用例,因此需要多轮迭代来逐步完善,直到一切都没问题并能经得起时间的考验。 -If you already have an application in place and can’t change it all at once then we recommend you base your design system on what you have. For each component, analyze what you have, pick the parts you like and work on improving the ones you don’t. When even this is too much work, split the future components from the legacy components. This way, you can stop yourself from using the legacy components in new components. Slowly, this will allow you to reach your goals. +如果你已经有了一个应用程序,但不能一次全部更改,那么我们建议你基于现有的设计系统去对它进行改进。对于每个部分,分析你所拥有的,选择你喜欢的部分,改进你不喜欢的部分。即使这个工作很繁琐,也应该将未来的组件从遗留组件中分离出来。这样,你就可以避免在新组件中使用遗留组件。慢慢地,这会让你达到你的目标。 -## How did we do it? +## 我们是怎么做到的? -Our team was composed of two designers and one frontend developer. Later on, one more developer joined the team. This team size was and still is enough to get things done with enough time to care about details. However, we would say the team size depends on the size of the project and the pace of the company. +我们的团队最初由两名设计师和一名前端开发人员组成,后来又有一名开发人员加入了这个团队。这个团队的规模无论是过去还是现在,都足够完成工作,并且也有充足的时间来处理细节问题。不过,我们认为团队的大小应取决于项目的规模和公司的节奏。 -The opportunity to rebuild our frontend from scratch also had the benefit that we could learn from past mistakes. Therefore, we based the design of our new components on the feedback from our users, who frequently mentioned accessibility and responsiveness issues. To tackle those issues we concluded that we needed to redesign our navigation system first and then redesign every page in the application. +从头开始重构前端项目的机会也让我们可以从过去的错误中吸取教训。因此,我们根据用户的反馈来设计新组件。他们经常提到可访问性和响应性问题,为了解决这些问题,我们认为首先需要重新设计导航系统,然后再重新设计应用程序中的每个页面。 -We started by designing our new navigation system as a whole and as it became more solid we started breaking it down into smaller components. This resulted in the intended Atomic Design division between atoms, molecules and organisms. Ideally you should start with the atoms but that was difficult without first knowing exactly which direction we wanted to take. Nowadays, since we already defined several atoms and molecules, it is easier to start composing them into new organisms or pages. +我们先将新的导航作为一个整体设计,在它的设计稳定下来之后,我们开始将其分解为更小的组件,这就产生为原子设计所分割好的的原子、分子和有机体。虽然在理想情况下,我们应该从原子开始设计,但如果没有明确的方向,这将是非常困难的事;而现在,我们已经通过拆分整体设计定义好了几个原子和分子,再将它们组合成新的有机体或页面就比较容易了。 -While creating components, we define them as `symbols` and split them in Sketch library files for `Atoms`, `Molecules` and `Organisms`. Sketch facilitates the reuse of our `Atom` components as a symbol in other `Molecule` or `Organism` components. In Sketch they are then called `nested symbols`. We make sure we use our components in a cascading order, so updates are propagated in one direction only. +在创建组件时,我们将它们定义为`符号`(`symbols`),并在 Sketch 库文件中把它们分割为`原子`、`分子`和`有机体`。Sketch 有助于将我们的`原子`组件作为符号在其它`分子`或`有机体`组件中使用。在 Sketch 中,它们被称为`嵌套符号`(`nested symbols`)。我们确保按级联顺序使用组件,以保证更新只能是单向进行的。 ![](https://cdn-images-1.medium.com/max/3200/0*oXhrNGXE1iLKgoBL) -**Our Sketch `Molecules` library: the icon component inside the button component is reused from the `Atoms` Sketch library.** +**我们的 Sketch `分子`库:按钮组件中的图标组件是从 Sketch `原子`库中复用的。** -To document our choices we create guidelines for each component (regardless of whether it’s an atom, molecule or organism) inspired in the Material UI component guidelines. Next to the component guidelines, we also have some generic guidelines which apply to all components because some guidelines are transcending, like accessibility and tone of voice. These guidelines work as our single source of truth. They ensure that nothing can be left to the imagination. To give an impression, they are a simple document with the following sections: +为了记录我们的选择,我们在 Material UI 组件指南的启发下,为每个组件(不管它是原子、分子还是有机体)创建了设计指南。紧接着,为不同的组件设定不同指导方针,以及定义一些适用于所有组件的通用方针,其中有些通用指导方针是非常重要的(比如可访问性和风格定位)。这些指导方针是我们唯一的事实来源,它们确保很多细节是一览无余的。为了给人留下印象,它们是一份包含以下部分的简单文档: -* Usage -* Anatomy -* Placement on different viewports -* Behavior -* Accessibility +* 使用 +* 分解 +* 不同的视图的布局 +* 行为 +* 可访问性 -We use our components in `Template` or `Page` files which we create per feature/project we work on. When a component or a page is ready, we share its designs with developers and other stakeholders via [Zeplin](https://zeplin.io/). This tool allows them to extract information from designs like colors, sizes and assets. It also allows for communication per component, which can drastically improve collaboration since it becomes very easy to discuss details for which normally a meeting would be necessary. +我们在根据每一个功能或者项目而创建的`模板`或`页面`文件中使用组件。当一个组件或页面准备好了,我们通过 [Zeplin](https://zeplin.io/) 与开发人员和其他参与者分享设计。这个工具允许他们从设计中提取信息,比如颜色、大小和资源。它还允许对任一组件发起讨论,这可以极大地提高协作效率,因为这些细节通常是需要通过开会来进行讨论的。 ![](https://cdn-images-1.medium.com/max/3200/0*rp1keWbCPclqMTwx) -**Collaborating on developing button components in Zeplin** +**在 Zeplin 中协作开发的按钮组件。** -From this point onwards, developers can use the information in Zeplin to start building the corresponding React components. Ideally there should be one React component per design component so that the relation between design and code is as close as possible. For inspiration we often look at how other component libraries did it like [Material-UI](https://material-ui.com/), for instance. +现在,开发人员可以使用 Zeplin 中的信息来开始构建相应的 React 组件了。理想情况下,每个设计组件都应该只有一个 React 组件,以保证设计和代码之间的关系尽可能地紧密一些。为了获得灵感,我们经常会看看其他组件库是怎么做的,比如 [Material-UI](https://material-ui.com/)。 -To ease in this process we use [Storybook](https://storybook.js.org/), which facilitates the development of components in isolation. It also offers a way of visualizing and interacting with all components in our library which can then be used by designers to validate the final implementations. +为了简化这个过程,我们使用了 [Storybook](https://storybook.js.org/),它促进了组件的独立开发。它还提供了一种与库中所有组件可视化交互的方法,设计师可以使用这些组件来验证最终的实现。 ![](https://cdn-images-1.medium.com/max/3200/0*QII0QzNhlLMhXNCX) -**The same buttons in Storybook: ready to be reviewed** +**Storybook 中相同的按钮:准备审核** -In both our design system and our component library we group components by categories like buttons, color, form elements, layout, links, typography and so on. This helps with grouping different atoms, molecules and organisms but also helps, once more, with the communication between designers and developers. +在我们的设计系统和组件库中,我们都按照类别将组件进行分组,例如按钮、颜色、表单元素、布局、链接、排版等。 -In essence these tools helped us develop feedback loops in our work process, which improved communication and collaboration: designers can easily give feedback on the component library through looking at Storybook and developers can easily comment on designs or download assets from Zeplin. +从本质上讲,这些工具帮助我们在工作过程中建立起反馈循环机制:设计师可以通过查看 Storybook 轻松地对组件库给出反馈,开发人员可以轻松地在 Zeplin 对设计进行评论或者下载资源。 -## What could we have done better? +## 还有哪些可以做得更好的地方? -In general, we feel that we did quite well in this process but we know that there are some things we could have done differently. Below are some of the pain points we came across along the way: +总的来说,我们觉得现在这个过程已经足够好了,但有些事情还可以做一些变通。下面是我们一路上遇到的痛点: -* **Accessibility guidelines**: we completely underestimated accessibility. There are lots of [WCAG guidelines](https://www.w3.org/TR/WCAG21/) and there’s no way you can implement them all with such a small team. We had to choose which ones were the most important for our users. However, we made this choice very late in the process because it had an impact in our atom components, mainly typography and color, which forced us to rethink several molecules and organisms. -* **Complex components**: we tried too often to create components with too many responsibilities or too many dependencies on other components. It is better to break them down into smaller components than to try to make them too customizable. It might require some repetition both in design and code but it is easier to understand. -* **Lack of planning and limitless scope**: for a while the scope of the project only kept on growing. Some things were very important but others not so much. It was difficult to draw a line since there was no end date for the project. Eventually, we started discussing these issues more often in order to prioritize what was really important. +* **可访问性指南**:我们完全低估了可访问性。[WCAG guidelines](https://www.w3.org/TR/WCAG21/) 有很多指导方针,但你不可能在这么小的团队中全部实现。我们必须选择哪些是对我们的用户最重要的。然而,我们在这个过程中很晚才做出这个选择,因为它对我们的原子组件(主要是字体和颜色)产生了影响,这迫使我们重新考虑一些分子和有机体。 +* **复杂组件**:我们经常尝试创建职责过多或对其它组件有太多依赖的组件。最好将它们分解成更小的组件,而不是盲目提高它们的可定制性。拆分也许会导致设计和代码上出现一些冗余,但这种方式是更容易被理解的。 +* **缺乏计划和无限的范围**:有一段时间,项目的范围只是持续增长。有些事情很重要,但有些就不那么重要了。由于这个项目没有结束日期,很难划定界限。最终,我们开始更频繁地讨论这些问题,以确定哪些是真正重要的。 -In the end, we managed to learn and improve upon these issues after finishing redesigning our navigation system. We still come across some complex components now and then but I think it is part of the process to make that mistake and identify it before it’s too late. +最终,在重新设计完导航系统之后,我们对这些问题进行了学习和改进。我们仍然不时地遇到一些复杂的组件,但我认为尽快地发现并指出错误也是其中的一个过程。 -## Conclusion +## 总结 -In our opinion, building a design system and a component library was worth the effort. It brought the consistency in design that we were looking for from the beginning. This doesn’t mean we would recommend it for everyone. Before you get started we truly recommend you make sure this is the right solution for your project. We would say you only need to do it if you know or expect the product to require a lot of different pages with complex interactions that reuse the same components. This is especially relevant to evaluate when you are still a startup or small company and you expect to scale up in the coming years. However, if you expect your product to be a simple website that won’t change much over the years then this would probably be overkill. +在我们看来,构建一个设计系统和一个组件库是值得的。它带来了我们从一开始就在寻找的一致性设计。这并不意味着我们会把这套方案推荐给所有人。在开始之前,我们建议你先确认这对于你的项目而言是否是正确的解决方案。我们认为,只有当你知道或期望产品需要大量不同的页面,并且这些页面具有复用同一组件的复杂交互时,才需要这样做。如果是一家初创公司或小公司,并希望在未来几年扩大规模时,这一点尤其重要。然而,如果你的产品是一个简单的网站,在几年之内不会有太大的变化,那么这可能是过分的。 -I hope this article helps you in the process of making better design decisions. If you have questions, feedback, or suggestions regarding what you read here I would be happy to hear from you in the comment section below. +我希望本文能够帮助您做出更好的设计决策。如果你对你在这里读到的内容有问题、反馈或建议,我很乐意在下面的评论部分听到你的意见。 > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/article/2020/building-and-monitoring-your-first-github-actions-workflow.md b/article/2020/building-and-monitoring-your-first-github-actions-workflow.md new file mode 100644 index 00000000000..4fb970d8e9a --- /dev/null +++ b/article/2020/building-and-monitoring-your-first-github-actions-workflow.md @@ -0,0 +1,78 @@ +> * 原文地址:[Building and Monitoring Your First Github Actions Workflow](https://blog.bitsrc.io/building-and-monitoring-your-first-github-actions-workflow-b9cad4a1014d) +> * 原文作者:[Meercode](https://medium.com/@meercode) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/building-and-monitoring-your-first-github-actions-workflow.md](https://github.com/xitu/gold-miner/blob/master/article/2020/building-and-monitoring-your-first-github-actions-workflow.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[plusmultiply0](https://github.com/plusmultiply0)、[HurryOwen](https://github.com/HurryOwen) + +# Github Actions 工作流的创建与跟踪 + +![](https://cdn-images-1.medium.com/max/2400/1*BZ_jv-xjX_FfJR5fQH_6UQ.png) + +**Github Actions** 是 Github 对 CI/CD 的原生解决方案,自 2019 年推出以来,它就可供社区开发者使用。**Action** 简单、灵活和低成本等特性使许多团队从现有的 **CI/CD** 解决方案中迁移过来,并且探索新平台的无限可能。 + +我的团队是 **Github Actions** 的早期使用者。作为一群大量使用 **Javascript** 的开发人员,我们能够自动化处理前端和后端项目的数十条工作流。由于平台支持 **Javascript/Typescript**,我们创建了大量 **Actions**(就像传统构建工具中的**插件**),以便根据我们的需要扩展功能。 + +在使用 Github Actions 一年之后,我们发现该工具与之前测试的 CI/CD 解决方案相比具有以下优势: + +* 零管理成本(不需要任何代理或主节点)。 +* 容易学习和掌握。 +* 可以在源代码中保留工作流。 +* 丰富的 **Action**(插件)库,易于开发自定义 **Action**。 +* 合理的定价模式:为私有存储库的高级用户提供 3000 分钟的免费时间。公共存储库是完全免费的! +* 它有一个丰富的 action 库,很容易开发自定义 Action。 +* 支持 **Linux**、**Windows** 和 **macOS** 平台。(支持 **macOS** 在竞争对手中是罕见的)。 +* 借助自托管运行工具,可以在自己的设备上运行免费版本。 + +该平台的一个小瑕疵是缺少可以跟踪工作流状态的监控工具。随着我们必须管理的项目库和工作流数量的增加,问题变得更棘手。最后,我们决定开发自己的仪表盘作为解决方案。 + +借助 **React** 前端和 **NestJS** 后端,使用相关的 Github API 并以简洁的方式显示。这个工具在我们的团队成员中很受欢迎,我们会为其继续开发新的功能。 + +最近,我们将仪表盘工具作为 **SaaS** 项目发布,然后启动一个公开的测试程序,并且分享在开发者社区。如果你感兴趣,你可以阅读 Meercode 的[关于此博客文章的故事](https://dev.to/pankod/public-beta-meercode-a-beautiful-dashboard-and-monitoring-tool-for-github-actions-466g)或访问 [meercode.io](http://meercode.io) 试用产品。 + +为了演示如何简单地在 Github Actions 上创建工作流,我们想展示一个真实的例子。 + +任务很简单,对于 Github 上的一个项目库,我们需要 [AppCenter](https://appcenter.ms/) 在发出 pull request 时触发构建。幸运的是,AppCenter 有一个公开的 REST API,可以用来启动构建。 + +我们要创建的操作应该在以下场景触发: + +1. pull request 被打开或重新打开。 +2. 通过了单元测试。 + +如果满足所有条件,我们将在 AppCenter 上开始构建。下面开始创造我们的 action。 + +从 GitHub 上的存储库中,在 .**github/workflows** 目录中创建一个名为 **app_center_pull_request.yml.** 的文件。 + +![](https://cdn-images-1.medium.com/max/2684/0*iyCUtUXoh8MF11Rm) + +通过使用 **“name:”** 属性,我们将 action 命名为 “Pull Request Opened [App]”。 + +为了在 pull request 时触发我们的 action,我们将使用原生 Github 工作流事件。当然,也可以使用 **“on:”** 语法将工作流配置为针对一个或多个事件运行。还可以把 action 中可以使用的工作流事件完整列表记录在[参考页](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows)。 + +接下来我们将说明,当触发 `pull_request` 事件时,action 要做什么 + +![](https://cdn-images-1.medium.com/max/2684/0*upqVeOmReybteXcC) + +在 “**jobs:**” 属性下,我们可以添加任意数量的要运行的作业。我们用 **“build:”** 属性标记第一个作业,并按上面所示进行配置。 + +**“runs-on:”** 和 **“matrix:”** 属性指定 action 将运行的环境。“**steps**:” 定义了同时运行的步骤: + +* 第一步,从 Action 仓库(Actions Marketplace)调取[其它 action](https://github.com/mdecoleman/pr-branch-name) 检索 **“pull request name”** 以便下一步使用。 +* 第二步,我们将初始化应用程序并运行测试。如果测试运行成功,则继续下一步 action。 +* 接着使用 curl 命令调用 **AppCenter API**,为相应的分支名称配置构建。我们使用第一步中的分支名称来构建相应的 **URI**。 + +![](https://cdn-images-1.medium.com/max/2684/0*Pppq6J46U6HfxvIS) + +* 最后,我们为 iOS 和 Android 版本触发构建: + +![](https://cdn-images-1.medium.com/max/2684/0*jazO_rGHuFgFg4y0) + +要运行和测试工作流,只需打开一个 pull request。这将自动触发并运行 action。要查看结果,则可以转到项目库的 **“Actions”** 选项卡,选择相应的工作流并运行。 + +如果想更深入地使用 Github Actions 或者需要在多个项目库中管理大量工作流,那么可以随时尝试之前提到过的仪表盘解决方案 [Meercode](https://meercode.io/)。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/clamp-for-responsive-design.md b/article/2020/clamp-for-responsive-design.md new file mode 100644 index 00000000000..49d405b6175 --- /dev/null +++ b/article/2020/clamp-for-responsive-design.md @@ -0,0 +1,41 @@ +> * 原文地址:[clamp() for Responsive Design](https://calebhearth.com/clamp-for-responsive-design) +> * 原文作者:[Caleb Hearth](https://calebhearth.com/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/clamp-for-responsive-design.md](https://github.com/xitu/gold-miner/blob/master/article/2020/clamp-for-responsive-design.md) +> * 译者:[Alfxjx](https://github.com/Alfxjx) +> * 校对者:[z0gSh1u](https://github.com/z0gSh1u)、[HurryOwen](https://github.com/HurryOwen) + +# 使用 clamp() 进行响应式设计 + +新的 CSS 函数 `clamp()` 提供了一种通过给目标值设置最大最小值的范围来计算实际值方法。它的语法是 `clamp([min], [calculated], [max])`。当你基于屏幕尺寸,使用长度单位 `vw` 来缩放一些值时,这个函数很有用。 + +该项技术很适用于跨多种屏幕尺寸的设计。常规的方法是根据屏幕的宽度使用媒体查询的方法来对样式做不同的调整,但是这么做导致我们在开发的时候要么以“移动端优先”为原则,开发小屏幕的应用,再按比例增加;要么是以“桌面端优先”为原则,开发适用于大屏幕的应用,再按比例缩小。通过使用 `clamp()` 函数,用一个已知的最大最小值来约束变化的范围,我们开发人员可以减少对于样式响应式断点的依赖,这样就无需为了一致性检查很多种不同的宽度了。 + +![image](https://user-images.githubusercontent.com/5164225/95879008-7562ad00-0da8-11eb-9b5a-01dd31d575d8.png) +运河闸可以使船通过不同水位的水域 + +为了理解 `clamp()` 是如何工作的,我喜欢用运河闸的比喻。运河闸使用两个可以升高和降低的船闸,以使船只可以越过它们。一旦船在闸板之间,则从高水位侧添加水或将水排到低水位侧,以分别升高或降低闸板之间的水位。这使船可以随水位轻轻浮动并在最小和最大水位之间移动。 + +更具体地说,`clamp(100%, calc(1em + 1vw), 200%)` 的效果与 `max(100%, min(calc(1em + 1vw), 200%))` 相同。最神奇的就是中间的这个参数 `calc(1em + 1vw)`,将浏览器的宽度(或者说,视口的宽度)代入了计算之中。`1vw` 相当于视口宽度的 1%,因此 1em 加上视口宽度的 1% 的计算结果会随着浏览器的大小调整而变动。 + +让我们来看看我们是怎样通过此方法来调整字号大小的。下面的这个例子和我在我的个人网站上使用的方式非常相近: + +```css +body { + font-size: clamp(100%, calc(1rem + 2vw), 1.375rem); +} +``` + +拆分下来看,`100%` 通常表示着“当前页面的基本尺寸”,对于字号而言就是 16px。`calc(1rem + 2vw)` 使用 `rem`(同样是 16px )加上视口宽度的 2% 来进行计算。`1.375rem` 则是我理想情况下的最大字号,为 22px。 + +`clamp()` 以及相关的 `min()` 和 `max()` 函数在本文写作之时都有了很好的浏览器支持: + +![来自 caniuse.com 的跨主要浏览器的 css-math-functions 功能支持数据](https://caniuse.bitsofco.de/image/css-math-functions.jpg) + +[在 MDN 中](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp),`clamp()` 适用于任何使用了数字、百分数以及其他长度单位的样式中。但奇怪的是,当我尝试将其应用到[ `line-height` ](https://blog.typekit.com/2016/08/17/flexible-typography-with-css-locks/)时,我发现 Safari 14 应该是支持 `line-height: clamp(...)` 这样的写法的(我尝试了 `@supports`),但是实际情况却是回退到了基准的 `line-height` ,非常令人费解。最终我使用 `line-height: min(calc(1.1em + 1vw), 32px)` 从而实现了 `line-height` 响应式地根据我的内容高度来确定。这里不需要设置一个最小值,因为我测试的宽度都不是很小,但是如果有最小值的需求的话,可以在最外层包裹一个 `max()`:`line-height: max(100%, min(calc(1.1em + 1vw), 32px))`。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/code-coverage-vue-cypress.md b/article/2020/code-coverage-vue-cypress.md index 565b3396a99..de6d7dba82a 100644 --- a/article/2020/code-coverage-vue-cypress.md +++ b/article/2020/code-coverage-vue-cypress.md @@ -2,18 +2,18 @@ > * 原文作者:[Gleb Bahmutov]() > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/code-coverage-vue-cypress.md](https://github.com/xitu/gold-miner/blob/master/article/2020/code-coverage-vue-cypress.md) -> * 译者: -> * 校对者: +> * 译者:[tonylua](https://github.com/tonylua) +> * 校对者:[FateZeros](https://github.com/FateZeros) -# Code Coverage for Vue Applications +# Vue 应用的代码覆盖率 ![](https://vuejsdevelopers.com/images/posts/versions/code_coverage_1200.webp) -Let's take a Vue application scaffolded with [Vue CLI](https://cli.vuejs.org/) like this [bahmutov/vue-calculator](https://github.com/bahmutov/vue-calculator) app. In this blog post, I will show how to instrument the application's source code to collect the code coverage information. We then will use the code coverage reports to guide the end-to-end test writing. +让我们像 [bahmutov/vue-calculator](https://github.com/bahmutov/vue-calculator) 应用一样,借助 [Vue CLI](https://cli.vuejs.org/) 来搭建一个 Vue 应用脚手架。在本文中,我将展示如何检测应用的源代码以收集其代码覆盖率信息。其后我们将利用该代码覆盖率报告来引导端到端测试的编写。 -## The application +## 应用 -The example application can be found in [bahmutov/vue-calculator](https://github.com/bahmutov/vue-calculator) repo that was forked from [kylbutlr/vue-calculator](https://github.com/kylbutlr/vue-calculator) which used Vue CLI default template during scaffolding. The code is transformed using the following `babel.config.js` file: +示例应用可在 [bahmutov/vue-calculator](https://github.com/bahmutov/vue-calculator) 仓库中找到,该仓库 fork 自使用 Vue CLI 默认模版构建的 [kylbutlr/vue-calculator](https://github.com/kylbutlr/vue-calculator) 项目。其代码使用如下 `babel.config.js` 文件转译: ```js // babel.config.js @@ -24,7 +24,7 @@ module.exports = { } ``` -When we start the application with `npm run serve`, we execute the NPM script +当我们用 `npm run serve` 启动应用时,其实是执行了这条 NPM script ```json { @@ -34,15 +34,15 @@ When we start the application with `npm run serve`, we execute the NPM script } ``` -The application runs at port 8080 by default. +应用默认运行在 8080 端口上。 -![Vue calculator application](https://vuejsdevelopers.com/images/posts/code_coverage/calculator.png) +![Vue 计算器应用](https://vuejsdevelopers.com/images/posts/code_coverage/calculator.png) -Tada! You can calculate anything you want. +搞定!你可以计算任何想要的东西了。 -## Instrument source code +## 检测源代码 -We can instrument the application code by adding the `plugins` list to the exported Babel config.The plugins should include the [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul). +我们可以通过向导出的 Babel 配置文件中添加 `plugins` 列表来检测应用代码。该插件列表应包含 [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul) 。 ```js // babel.config.js @@ -56,13 +56,13 @@ module.exports = { } ``` -The application runs, and now we should find the `window.__coverage__` object with counters for every statement, every function, and every branch of every file. +现在,当应用运行时,我们应该能找到 `window.__coverage__` 对象,该对象包含了每条语句、每个函数,及每个文件的每一个分支的各种计数。 -![Application coverage object](https://vuejsdevelopers.com/images/posts/code_coverage/coverage.png) +![应用覆盖率对象](https://vuejsdevelopers.com/images/posts/code_coverage/coverage.png) -Except the coverage object as shown above, includes only a single entry `src/main.js`, and the coverage object is missing both `src/App.vue` and `src/components/Calculator.vue` files. +不过上面展示的覆盖率对象,仅包含了单一条目 `src/main.js`,却缺失了 `src/App.vue` 和 `src/components/Calculator.vue` 两个文件。 -Let's tell `babel-plugin-istanbul` that we want to instrument both `.js` and `.vue` files. +让我们来告诉 `babel-plugin-istanbul` 我们想要同时检测 `.js` 和 `.vue` 文件吧。 ```js // babel.config.js @@ -78,19 +78,19 @@ module.exports = { } ``` -**Tip:** we can place `istanbul` settings in a separate file `.nycrc`, or add them to `package.json`. For now, let's just keep these settings together with the plugin itself. +**提示:** 我们可以将 `istanbul` 设置放在一个单独的 `.nycrc` 文件中(译注:[nyc](https://github.com/istanbuljs/nyc) ,Istanbul 提供的命令行接口工具),或将它们添加到 `package.json`。目前而言,还是先将这些设置一起保留在插件列表本身中吧。 -When we restart the application, we get a new `window.__coverage__` object with entries for `.js` and for `.vue` files. +当我们重启应用后,得到了一个包含 `.js` 和 `.vue` 文件条目的新 `window.__coverage__` 对象。 -![Instrumented JS and Vue files](https://vuejsdevelopers.com/images/posts/code_coverage/vue-covered.png) +![被检测的 JS 和 Vue 文件](https://vuejsdevelopers.com/images/posts/code_coverage/vue-covered.png) -## Conditional instrumentation +## 条件性检测 -If you look at the application's bundle, you will see what the instrumentation does. It inserts counters around every statement, keeping track how many times a statement was executed. There are separate counters for every function and every branch path. +如果你观察应用的打包代码,就会看到测量所做的事情。其围绕每条语句都插入了计数器,用以保持跟踪一条语句被执行了多少次。对于每一个函数和每一个分支路径,也有单独的计数器。 -![Instrumented source code](https://vuejsdevelopers.com/images/posts/code_coverage/instrumented.png) +![被检测的源代码](https://vuejsdevelopers.com/images/posts/code_coverage/instrumented.png) -We do not want to instrument the production code. Let's only instrument the code when `NODE_ENV=test` since we will use the collected code coverage to help us write better tests. +我们并不想测量生产环境代码。应仅在 `NODE_ENV=test` 时测量代码,好利用收集到的代码覆盖率帮助我们编写更好的测试。 ```js // babel.config.js @@ -98,8 +98,8 @@ const plugins = [] if (process.env.NODE_ENV === 'test') { plugins.push([ "babel-plugin-istanbul", { - // specify some options for NYC instrumentation here - // like tell it to instrument both JavaScript and Vue files + // 在此为 NYC 测量工具指定一些选项 + // 如告知其同时测量 JavaScript 和 Vue 文件 extension: ['.js', '.vue'], } ]) @@ -112,17 +112,17 @@ module.exports = { } ``` -We can start the application with instrumentation by setting the environment variable. +可以通过设置环境变量启动带测量的应用。 ```shell $ NODE_ENV=test npm run serve ``` -**Tip:** for cross-platform portability use the [cross-env](https://github.com/kentcdodds/cross-env) utility to set an environment variable. +**提示:** 对于跨平台可移植性,可使用 [cross-env](https://github.com/kentcdodds/cross-env) 工具设置一个环境变量。 -## End-to-end Tests +## 端到端测试 -Now that we have instrumented our source code, let us use it to guide us in writing tests. I will install Cypress Test Runner using the official Vue CLI plugin [@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html). Then I will install the [Cypress code coverage plugin](https://github.com/cypress-io/code-coverage) that will convert the coverage objects into human- and machine-readable reports at the end of the test run. +现在我们测量了源代码,使用其引导编写测试吧。我将用官方的 Vue CLI 插件 [@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html) 安装 Cypress Test Runner。而后我将安装 [Cypress 代码覆盖率插件](https://github.com/cypress-io/code-coverage) 以在测试运行结束时将覆盖率对象转换为人和机器皆可读的报告。 ```shell $ vue add e2e-cypress @@ -130,23 +130,21 @@ $ npm i -D @cypress/code-coverage + @cypress/code-coverage@3.8.1 ``` -The [@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html) has created folder `tests/e2e` where I can load the code coverage plugin from both the support and the plugins files. +[@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html) 已经创建了 `tests/e2e` 文件夹,在其 support 和 plugins 子目录的文件中都可以加载代码覆盖率插件。 ```js -// file tests/e2e/support/index.js +// 文件 tests/e2e/support/index.js import '@cypress/code-coverage/support' -// file tests/e2e/plugins/index.js +// 文件 tests/e2e/plugins/index.js module.exports = (on, config) => { require('@cypress/code-coverage/task')(on, config) - // IMPORTANT to return the config object - // with the any changed environment variables + // 重要:须返回包含任何改变过的环境变量的配置对象 return config } ``` -Let's set the environment variable `NODE_ENV=test` to the NPM script command `test:e2e` inserted into `package.json` by the [@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html). - +让我们为被 [@vue/cli-plugin-e2e-cypress](https://cli.vuejs.org/core-plugins/e2e-cypress.html) 插入到 `package.json` 中的 NPM script 命令 `test:e2e` 设置环境变量 `NODE_ENV=test` 。 ```json { "scripts": { @@ -157,7 +155,7 @@ Let's set the environment variable `NODE_ENV=test` to the NPM script command `te } ``` -We can place our first end-to-end spec file in `tests/e2e/integration` folder +可将我们的首个端到端规格文件置于 `tests/e2e/integration` 文件夹: ```js /// @@ -182,40 +180,39 @@ describe('Calculator', () => { }) ``` -Locally, I will use `npm run test:e2e` command to start the application and open Cypress. The above test passes quickly. Our calculator seems to add and divide numbers just fine. +本地运行时,我将使用 `npm run test:e2e` 命令启动应用并打开 Cypress 。以上测试很快通过了。我们的计算器看起来加法除法运行良好。 -![Calculator test](https://vuejsdevelopers.com/images/posts/code_coverage/calculator.gif) +![计算器测试](https://vuejsdevelopers.com/images/posts/code_coverage/calculator.gif) -The code coverage plugin automatically generates code coverage reports at the end of the run, as you can see from the messages in the Command Log on the left of the Test Runner. The reports are stored in the folder `coverage`, and by default there are several output formats. +正如你能从来自于 Test Runner 命令行日志信息的左侧看到的,测试覆盖率插件在运行结束时自动生成了代码覆盖率报告。报告被存储在 `coverage` 文件夹中,且默认有多种输出格式。 ```text coverage/ lcov-report/ - index.html # human HTML report + index.html # 人类可读的 HTML 报告 ... - clover.xml # coverage report for Clover Jenkins reporter - coverage-final.json # plain JSON output for reporting - lcov.info # line coverage report - # for 3rd party reporting services + clover.xml # 面向 Clover Jenkins reporter 的覆盖率报告 + coverage-final.json # 纯 JSON 输出 + lcov.info # 面向第三方报告服务的行覆盖率 ``` -While working with tests locally, I prefer opening the HTML coverage report +在本地运行测试时,我更喜欢打开 HTML 覆盖率报告: ```shell $ open coverage/lcov-report/index.html ``` -The `index.html` is a static page that shows a table for each source folder with coverage information. +`index.html` 是一个展示了每个源代码文件夹覆盖率信息表格的静态页面。 -![Coverage report](https://vuejsdevelopers.com/images/posts/code_coverage/coverage-report.png) +![覆盖率报告](https://vuejsdevelopers.com/images/posts/code_coverage/coverage-report.png) -**Tip:** store the entire `coverage/lcov-report` folder as a test artifact on your Continuous Integration (CI) server. Then browse or download the report to see the collected code coverage after the test run. +**提示:** 将整个 `coverage/lcov-report` 文件夹作为一个测试产物存储在你的持续集成(CI - Continuous Integration)服务器上。然后就能在测试运行后浏览或下载报告以查看收集到的代码覆盖率了。 -End-to-end tests are **effective**. With a single test that loads and interacts with the entire application we have covered 60% of the source code. Even better, by drilling down to the individual files, we discover in `src/components/Calculator.vue` the features we have not tested yet. +端到端测试是 **有效的**。通过一个加载整个应用并与之交互的单一测试,我们覆盖了近 60% 的源代码。更棒的是,通过点开单独的文件,我们发现了在 `src/components/Calculator.vue` 中那些未曾被测试到的特性。 -![Covered lines in Calculator.vue file](https://vuejsdevelopers.com/images/posts/code_coverage/covered-lines.png) +![Calculator.vue 中已覆盖/未覆盖的行](https://vuejsdevelopers.com/images/posts/code_coverage/covered-lines.png) -The source lines highlighted in red are the lines missed by the test. We can see that we still need to write a test that clears the current number, changes the sign, sets the decimal point, multiplies, etc. But we did test entering and dividing numbers. The test writing thus becomes following the code coverage as a guide to writing end-to-end; add tests until you hit all lines marked in red! +源码中高亮为红色的行正是测试中遗漏的。可以看到,虽然我们已经测试了录入数字和除法等,但仍需编写一个测试以覆盖“清除当前数字”、“改变正负号”、“设置小数点”、“乘法”等功能。代码覆盖率因此变为了编写端到端测试的向导;增加测试,直到所有红色标记的行都被干掉为止! ``` Calculator @@ -225,11 +222,11 @@ The source lines highlighted in red are the lines missed by the test. We can see ✓ % operator (246ms) ``` -As we write more tests we quickly gain coverage and confidence in our application. In the last test we will cover the `decimal () { ... }` method that remained red so far. +随着编写更多的测试,我们在应用中快速收获了覆盖率和信心。在最后一项测试中我们将覆盖仍保留了红色的 `decimal () { ... }` 方法。 -![Decimal method without any coverage](https://vuejsdevelopers.com/images/posts/code_coverage/decimal.png) +![没有被覆盖到的 Decimal 方法](https://vuejsdevelopers.com/images/posts/code_coverage/decimal.png) -The test below types a single digit number and clicks the "." button. The display should show "5.". +以下测试键入了一个单数位数字并点击了 "." 按钮。显示结果应为 "5." 。 ```js it('decimal', () => { @@ -239,11 +236,11 @@ it('decimal', () => { }) ``` -Hmm, this is weird, the test fails. +嘿,怪了,测试失败了。 -![Decimal test fails](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-fails.png) +![Decimal 测试失败](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-fails.png) -A power of Cypress test is that it runs in the real browser. Let's debug the failing test. Put a breakpoint in the `src/components/Calculator.vue` +Cypress 测试的一个强大之处就在于其运行在真实浏览器中。让我们来调试失败的测试。在 `src/components/Calculator.vue` 放置一个断点。 ```js decimal() { @@ -254,26 +251,26 @@ decimal() { }, ``` -Open the DevTools in the browser and run the test again. It will run until it hits the `debugger` keyword in the application code. +打开浏览器的 DevTools 并再次运行测试。测试将运行,直到遇见应用代码中的 `debugger` 关键字。 -![Debugging decimal method](https://vuejsdevelopers.com/images/posts/code_coverage/debugger.png) +![调试 decimal 方法](https://vuejsdevelopers.com/images/posts/code_coverage/debugger.png) -Ohh, the `this.display` is a Number, not a String. Thus `.indexOf()` does not exist and the expression `this.display.indexOf(".")` throws an error. +噢,`this.display` 是个数字,而非一个字符串。因此 `.indexOf()` 并不存在且 `this.display.indexOf(".")` 表达式抛出了一个错误。 -**Tip:** if you want Cypress tests to fail any time Vue catches an error, set the following in your code application code: +**提示:** 如果想要在任何一次 Vue 捕获错误时都让 Cypress 测试失败,在你的应用代码中做如下设置: ```js -// exclude these lines from code coverage +// 从代码覆盖率中排除这些行 /* istanbul ignore next */ if (window.Cypress) { - // send any errors caught by the Vue handler - // to the Cypress top level error handler to fail the test + // 将 Vue handler 捕获的任何错误发送给 + // Cypress 顶级错误处理器以使测试失败 // https://github.com/cypress-io/cypress/issues/7910 Vue.config.errorHandler = window.top.onerror } ``` -Let's fix the logical error in our code: +让我们来修复代码中的错误逻辑: ```js decimal() { @@ -283,43 +280,43 @@ decimal() { }, ``` -The test passes. Now the code coverage report tells us that the "Else" path of the condition has not been taken yet. +测试通过了。现在代码覆盖率报告又告诉我们条件语句的 "Else" 路径并未被考虑到。 -![Else path not taken](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-else.png) +![没有 Else 路径](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-else.png) -Extend the test to click the "." operator twice during the test and it will cover all code paths and turn the entire method coverage green. +扩展测试以在测试中两次点击 "." 操作符,这将覆盖所有代码路径并将整个方法覆盖率变为绿色。 ```js it('decimal', () => { cy.contains('.button', '5').click() cy.contains('.button', '.').click() cy.contains('.display', '5.') - cy.log('**does not add it twice**') + cy.log('**不会加两次**') cy.contains('.button', '.').click() cy.contains('.display', '5.') }) ``` -![Decimal test passes](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-test-passes.png) +![Decimal 测试通过](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-test-passes.png) -![All code paths covered](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-covered.png) +![全覆盖的代码路径](https://vuejsdevelopers.com/images/posts/code_coverage/decimal-covered.png) -Now let's run all tests again. All tests pass in less than 3 seconds +现在再次运行所有测试。所有测试在 3 秒钟之内通过了。 -![All tests passing](https://vuejsdevelopers.com/images/posts/code_coverage/all-tests.gif) +![所有测试都通过了](https://vuejsdevelopers.com/images/posts/code_coverage/all-tests.gif) -And the tests together cover our entire code base. +这些测试一起覆盖了我们整个的代码库。 -![Full code coverage](https://vuejsdevelopers.com/images/posts/code_coverage/full-cover.png) +![完整的代码覆盖率](https://vuejsdevelopers.com/images/posts/code_coverage/full-cover.png) -## Conclusions +## 总结 -* adding code instrumentation to Vue projects is simple if the project is already using Babel to transpile the source code. By adding the `babel-plugin-istanbul` to the list of plugins you get the code coverage information under `window.__coverage__` object. -* you probably want to only instrument the source code while running tests to avoid slowing down the production build -* end-to-end tests are very effective at covering a lot of code because they exercise the full application. -* the code coverage reports produced by `@cypress/code-coverage` plugin can guide you in writing tests to ensure all features are tested +* 向已经使用了 Babel 转译源代码的 Vue 项目添加代码测量工具很简单。向插件列表中添加 `babel-plugin-istanbul` 就能在 `window.__coverage__` 对象中获知代码覆盖率信息。 +* 为了避免减慢生产环境代码的打包速度,你可能只想在测试时检测源代码。 +* 因为运行了完整的应用,端到端测试对于覆盖大量代码非常有效。 +* 由 `@cypress/code-coverage` 插件产生的代码覆盖率报告可以引导你编写测试以确保所有特性都被测试到 -For more information read the [Cypress code coverage guide](https://on.cypress.io/code-coverage) and [@cypress/code-coverage](https://github.com/cypress-io/code-coverage) documentation. +要获得更多信息,请参阅 [Cypress code coverage guide](https://on.cypress.io/code-coverage) 和 [@cypress/code-coverage](https://github.com/cypress-io/code-coverage) 文档。 > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 diff --git a/article/2020/color-scales-in-javascript-with-chroma-js.md b/article/2020/color-scales-in-javascript-with-chroma-js.md new file mode 100644 index 00000000000..a06aef155f0 --- /dev/null +++ b/article/2020/color-scales-in-javascript-with-chroma-js.md @@ -0,0 +1,94 @@ +> * 原文地址:[Color Scales in JavaScript with Chroma.js](https://levelup.gitconnected.com/color-scales-in-javascript-with-chroma-js-b9f59d2a68d7) +> * 原文作者:[Joe T. Santhanavanich](https://medium.com/@joets) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/color-scales-in-javascript-with-chroma-js.md](https://github.com/xitu/gold-miner/blob/master/article/2020/color-scales-in-javascript-with-chroma-js.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者: + +# JavaScript 颜色处理库 Chroma.js 的应用 + +![Photo by [Daniele Levis Pelusi](https://unsplash.com/@yogidan2012?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/10806/0*8vuqBAz5TLSVD38h) + +许多开发人员用 CSS 设计颜色代码和比例,从一些在线调色板中选择颜色。然而,它并不是每个人都喜欢的工具。好消息是我们有 Chroma.js,这是一个很小的库,对于在 JavaScript 代码中生成色阶有很大帮助。这意味着您可以直接将其插入到 JavaScript 代码框架中! + +#### 让我们开始吧! + +## 启动安装 + +在 web 应用程序中,可以在 HTML 文档中使用 CDNJS 的链接。 + +```html + +``` + +或者,也可以使用 NPM 安装它。 + +```bash +$ npm install chroma-js +``` + +## 示例用法 + +您只需在 JavaScript 代码中使用 chroma.scale([\,\, ... , \]) 函数,将在指定的颜色之间创建色阶。 + +例如,可以使用以下 JavaScript 代码创建从黄色到红色的颜色比例: + +```js +var color_scale = chroma.scale([‘yellow’, ‘red’]); +``` + +然后,您可以通过以下方式访问 RGB 或十六进制代码中的颜色: + +```js +color_scale(0).rgb() // [255, 255, 0] +color_scale(0.1).rgb() // [255, 230, 0] +color_scale(0.2).rgb() // [255, 204, 0] +color_scale(0.3).rgb() // [255, 179, 0] +... +color_scale(1.0).rgb() // [255, 0, 0] + +=================================== + +color_scale(0).hex() // "#ffff00" +color_scale(0.1).hex() // "#ffe600" +color_scale(0.2).hex() // "#ffcc00" +color_scale(0.3).hex() // "#ffb300" +... +color_scale(1.0).hex() // "#ff0000" +``` + +![**10 classes of Color Scale output from chroma.scale([‘yellow’, ‘red’])** (by Author)](https://cdn-images-1.medium.com/max/2112/1*RJ74UXMa6nqmEUyGIZI4Pg.png) + +您可以使用色阶执行更多选项,例如,基于 [ColorBrewer](https://colorbrewer2.org/#type=sequential&scheme=BuGn&n=3) 的色阶,混合更多颜色代码。 + +以下是更多示例: + +```js +chroma.scale('Spectral'); +``` + +![**10 classes of Color Scale output from chroma.scale(‘Spectral’)** (by Author)](https://cdn-images-1.medium.com/max/2000/1*PpS1nMb_piYOuk4ENWWBWA.png) + +```js +chroma.scale('RdPu'); +``` + +![**10 classes of Color Scale output from chroma.scale(‘RdPu’)** (by Author)](https://cdn-images-1.medium.com/max/2116/1*11Y1xrUSthjj1yNvMMJyzA.png) + +```js +chroma.scale('RdPu').domain([1,0]); // 反转色阶 +``` + +![**10 classes of Color Scale output from chroma.scale(‘RdPu’).domain([1,0])** (by Author)](https://cdn-images-1.medium.com/max/2118/1*zqTLSKzHFpZ4VhYBhW7s4w.png) + +#### 应用总结 + +如果您喜欢这个颜色处理库,可以在 [https://gka.github.io/chroma.js/](https://gka.github.io/chroma.js/) 查找更多高级教程,例如在缩放方法中结合颜色处理等等。总的来说,我希望您喜欢本文,并能够将此颜色处理库应用到您的应用程序或项目中。 + +保持健全安康!快乐写代码! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc.md b/article/2020/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc.md new file mode 100644 index 00000000000..0d70138c215 --- /dev/null +++ b/article/2020/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc.md @@ -0,0 +1,240 @@ +> * 原文地址:[Comparing API Architectural Styles: SOAP vs REST vs GraphQL vs RPC](https://www.altexsoft.com/blog/soap-vs-rest-vs-graphql-vs-rpc/) +> * 原文作者:[AltexSoft Inc](https://www.altexsoft.com/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc.md](https://github.com/xitu/gold-miner/blob/master/article/2020/comparing-api-architectural-styles-soap-vs-rest-vs-graphql-vs-rpc.md) +> * 译者: +> * 校对者: + +# Comparing API Architectural Styles: SOAP vs REST vs GraphQL vs RPC + +![](https://cdn-images-1.medium.com/max/2800/0*ZwL-A9WTss2u3Pti.jpg) + +Two separate applications need an intermediary to talk to each other. So, developers often build bridges — [Application Programming Interfaces ](https://www.altexsoft.com/blog/engineering/what-is-api-definition-types-specifications-documentation/?utm_source=MediumCom&utm_medium=referral&utm_campaign=shared)— to allow one system to access the information or functionality of another. + +In order to integrate applications quickly and at scale, APIs are realized using protocols and/or specifications to define the semantics and syntax of the messages passed across the wire. These specifications make up the API architecture. + +Over time, different API architectural styles have been released. Each of them has its own patterns of standardizing data exchange. A pull of choices raises endless debates as to which architectural style is best. + +![**API styles over time, Source: [Rob Crowley](https://twitter.com/robdcrowley?lang=en)**](https://cdn-images-1.medium.com/max/2000/0*FjEhEvgBVHUPbO2o.png) + +Today, many API consumers refer to REST as “**REST in peace**“ and cheer for GraphQL, while ten years ago it was a reverse story with REST as the winner to replace SOAP. The problem with these opinions is that they are one-sided picking a technology itself instead of considering how its actual properties and characteristics match the situation at hand. + +In this article, we’ll stay objective and discuss the four major API styles in the order of their appearance, compare their strong and weak sides, and highlight the scenarios where each of them fits best. + +![**Four major API styles compared**](https://cdn-images-1.medium.com/max/2000/0*48GrlLTgVHuOsqRu.png) + +## Remote Procedure Call (RPC): invoking a function on another system + +A **Remote Procedure Call** is a specification that allows for remote execution of a function in a different context. RPC extends the notion of local procedure calling but puts it in the context of an HTTP API. + +Initial XML-RPC was problematic because ensuring data types of XML payloads is tough. So, later an RPC API started using a more concrete [JSON-RPC](https://www.jsonrpc.org/) specification which is considered a simpler alternative to SOAP. [gRPC](https://grpc.io/) is the latest RPC version developed by Google in 2015. With pluggable support for load balancing, tracing, health checking, and authentication, gRPC is well-suited for connecting microservices. + +#### How RPC works + +A client invokes a remote procedure, serializes the parameters and additional information into a message, and sends the message to a server. On receiving the message, the server deserializes its content, executes the requested operation, and sends a result back to the client. The server stub and client stub take care of the serialization and deserialization of the parameters. + +![**Remote Procedure Calling Mechanism, Source: [Guru99](https://www.guru99.com/remote-procedure-call-rpc.html#1)**](https://cdn-images-1.medium.com/max/2000/0*MGMkYwMzzIGG0imi.png) + +#### RPC Pros + +**Straightforward and simple interaction.** RPC uses GET to fetch information and POST for everything else. The mechanics of the interaction between a server and a client come down to calling an endpoint and getting a response. + +**Easy-to-add functions.** If we get a new requirement for our API, we can easily add another endpoint executing this requirement: 1) Write a new function and throw it behind an endpoint and 2) now a client can hit this endpoint and get the info meeting the set requirement. + +**High performance.** Lightweight payloads go easy on the network providing high performance, which is important for shared servers and for parallel computations executing on networks of workstations. RPC is able to optimize the network layer and make it very efficient with sending tons of messages per day between different services. + +#### RPC Cons + +**Tight coupling to the underlying system.** An API’s abstraction level contributes to its reusability. The tighter it is to the underlying system, the less reusable it will be for other systems. RPC’s tight coupling to the underlying system doesn’t allow for an abstraction layer between the functions in the system and the external API. This raises security issues as it’s quite easy to leak implementation details about the underlying system into the API. An RPC’s tight coupling makes scalability requirements and loosely coupled teams hard to achieve. So, the client either worries about any possible side effects of calling a particular endpoint or tries figuring out what endpoint to call because it doesn’t understand how the server is naming its functions. + +**Low discoverability.** In RPC there’s no way to introspect the API or send a request and start understanding what function to call based on its requests. + +**Function explosion.** It’s so easy to create new functions. So, instead of editing the existing ones, we create new ones ending up with a huge list of overlapping functions that are hard to understand. + +#### RPC use cases + +The RPC pattern started being used around the 80s, but this doesn’t automatically make it obsolete. Big companies like Google, Facebook ([Apache Thrift](https://thrift.apache.org/)), and Twitch ([Twirp](https://twitchtv.github.io/twirp/docs/intro.html)) are using RPC high-performance variates internally to perform extremely high-performance, low-overhead messaging. Their massive microservices systems require internal communication to be clear while arranged in short messages. + +**Command API.** An RPC is the proper choice for sending commands to a remote system. For instance, a Slack API is very command-focused: Join a channel, leave a channel, send a message. So, the designers of the Slack API modeled it in an RPC-like style making it small, tight, and easy to use. + +**Customer-specific APIs for internal microservices**. Having direct integration between a single provider and consumer, we don’t want to spend a lot of time transmitting a lot of metadata over the wire, like a REST API does. With high message rate and message performance, gRPC and Twirp are strong cases for microservices. Using HTTP 2 under the hood, gRPC is able to optimize the network layer and make it very efficient with sending tons of messages per day between different services. However, if you’re not aiming at high network performance, but rather at a stable API contact between teams publishing highly distinctive microservices, REST will ensure that. + +## Simple Objects Access Protocol (SOAP): making data available as services + +[**SOAP**](https://www.altexsoft.com/blog/engineering/what-is-soap-formats-protocols-message-structure-and-how-soap-is-different-from-rest/?utm_source=MediumCom&utm_medium=referral&utm_campaign=shared#soap-use-cases) is an XML-formatted, highly standardized web communication protocol. Released by Microsoft a year after XML-RPC, SOAP inherited a lot from it. When REST followed, they were first used in parallel, but soon REST won the popularity contest. + +#### How SOAP works + +XML data format drags behind a lot of formality. Paired with the massive message structure, it makes SOAP the most verbose API style. + +A SOAP message is composed of: + +* an envelope tag that begins and ends every message, +* a body containing the request or response +* a header if a message must determine any specifics or extra requirements, and +* a fault informing of any errors that can occur throughout the request processing. + +![**An example of the SOAP message. Source: [IBM](https://www.ibm.com/support/knowledgecenter/en/SSMKHH_10.0.0/com.ibm.etools.mft.doc/ac55780_.htm)**](https://cdn-images-1.medium.com/max/2000/0*MOADcAI4Y3hPfsDP.png) + +The SOAP API logic is written in Web Service Description Language (WSDL). This API description language defines the endpoints and describes all processes that can be performed. This allows different programming languages and IDEs to quickly set up communication. + +SOAP supports both stateful and stateless messaging. In a stateful scenario, the server stores the received information that can be really heavy. But it’s justified for operations involving multiple parties and complex transactions. + +#### SOAP pros + +**Language- and platform-agnostic.** The built-in functionality to create web-based services allows SOAP to handle communications and make responses language- and platform-independent. + +**Bound to a variety of transport protocols.** SOAP is flexible in terms of transfer protocols to accommodate for multiple scenarios. + +**Built-in error handling.** SOAP API specification allows for returning the Retry XML message with error code and its explanation. + +**A number of security extensions.** Integrated with the WS-Security protocols, SOAP meets an enterprise-grade transaction quality. It provides privacy and integrity inside the transactions while allowing for encryption on the message level. + +![**SOAP message-level security: authentication data in the header element and encrypted body**](https://cdn-images-1.medium.com/max/2800/0*R8dmtvOpZsld72RN.png) + +#### SOAP cons + +These days, many developers shudder at the idea of having to integrate a SOAP API for several reasons. + +**XML only.** SOAP messages contain a lot of metadata and only support verbose XML structures for requests and responses. + +**Heavyweight.** Due to the large size of XML-files, SOAP services require a large bandwidth. + +**Narrowly specialized knowledge.** Building SOAP API servers requires a deep understanding of all protocols involved and their highly restricted rules. + +**Tedious message updating.** Requiring additional effort to add or remove the message properties, rigid SOAP schema slows down adoption. + +#### SOAP use cases + +Right now, the SOAP architecture is most commonly used for internal integration within enterprises or with their trusted partners. + +**Highly secured data transmission.** SOAP rigid structure, security and authorization capabilities make it the most suitable option for enforcing a formal software contract between API and client while complying with the legal contract between the API provider and API consumer. That’s why financial organizations and other corporate users opt for SOAP. + +## Representational state transfer (REST): making data available as resources + +**REST** is a self-explanatory API architectural style defined by a set of architectural constraints and intended for wide adoption with many API consumers. + +The most common API style today was originally described in 2000 by Roy Fielding in his [doctoral dissertation](https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm). REST makes server-side data available representing it in simple formats, often JSON and XML. + +#### How REST works + +REST isn’t as strictly defined as SOAP. RESTful architecture should comply with six architectural constraints: + +* **uniform interface:** permitting a uniform way of interacting with a given server regardless of device or application type +* **stateless**: the necessary state to handle the request as contained within the request itself and without the server storing anything related to the session +* **caching** +* **client-server architecture:** allowing for independent evolution of either side +* **layered system** of the application +* the ability for servers to **provide executable code** to the client + +In fact, some services are RESTful only to a degree. They have RPC style at the core, break down larger services into resources, and use HTTP infrastructure efficiently. But the key part is using hypermedia aka HATEOAS, short for [Hypertext As The Engine of Application State](https://en.wikipedia.org/wiki/HATEOAS). Basically, it means that with each response, a REST API provides metadata linking to all the related info about how to use the API. That’s what enables decoupling the client and the server. As a result, both API provider and API consumer can evolve independently without hindering their communication. + +![**Richardson Maturity Model as a goalpost to achieving truly complete and useful APIs, Source: [Kristopher Sandoval](https://nordicapis.com/what-is-the-richardson-maturity-model/)**](https://cdn-images-1.medium.com/max/2048/0*fjasRE4pFM8mjTEA.png) + +**“HATEOAS is a key feature of REST. It’s really what makes REST REST. Since most people don’t use HATEOAS, they are actually using HTTP RPC,”** that’s some radical opinion expressed on [Reddit](https://www.reddit.com/r/golang/comments/7qvi0w/twirp_a_sweet_new_rpc_framework_for_go_twitch_blog/dstkrnm/). Indeed, HATEOAS is the most mature version of REST. However, it’s difficult to achieve requiring much more advanced and intelligent API clients than those typically used and built today. So, even really good REST APIs today don’t always do it. This is why HATEOAS mainly serves as a vision for the long term development of a RESTful API design. + +There really may be a gray zone between REST and RPC, when a service implements some features of REST and some of RPC. REST is based on the resource or noun instead of action or verb-based. + +![**Opposing operations in verb-centric RPC to the ones in noun-centric REST**](https://cdn-images-1.medium.com/max/2000/0*gyxh_zIFA2jU0DG4.png) + +In REST, things are done using HTTP methods such as GET, POST, PUT, DELETE, OPTIONS, and, hopefully, PATCH. + +![**Source: Thomas Davis**](https://cdn-images-1.medium.com/max/2000/0*5-VuvD8xxV0VrNjs.png) + +#### REST pros + +**Decoupled client and server.** Decoupling the client and the server as much as possible, REST allows for a better abstraction than RPC. A system with abstraction levels is able to encapsulate its details to better identify and sustain its properties. This makes a REST API flexible enough to evolve over time while remaining a stable system. + +**Discoverability.** Communication between the client and server describes everything so that no external documentation is required to understand how to interact with the REST API. + +**Cache-friendly.** Reusing a lot of HTTP tools, REST is the only style that allows caching data on the HTTP level. In contrast, caching implementation on any other API will require configuring an additional cache module. + +**Multiple formats support.** The ability to support multiple formats for storing and exchanging data is one of the reasons REST is currently a prevailing choice for building public APIs. + +#### REST cons: + +**No single REST structure.** There’s no exact right way to build a REST API. How to model resources and which resources to model will depend on each scenario. This makes REST simple in theory, but difficult in practice. + +**Big payloads.** REST returns a lot of rich metadata so that the client can understand everything necessary about the state of the application just from its responses. And this chattiness is no big deal for a big network pipe with lots of bandwidth capacity. But that’s not always the case. This was the key driving factor for Facebook coming up with the description of GraphQL style in 2012. + +**Over- and under-fetching problems.** Containing either too much data or not enough of it, REST responses often create the need for another request. + +#### REST use cases + +**Management APIs.** APIs focused on managing objects in a system and intended for many consumers are the most common API type. REST helps such APIs to have strong discoverability, good documentation, and it fits this object model well. + +**Simple resource-driven apps.** REST is a valuable approach for connecting resource-driven apps that don’t need flexibility in queries. + +## GraphQL: querying just the needed data + +It takes a number of calls to the REST API for it to return the needed staff. So GraphQL was invented to be a game-changer. + +[**GraphQL**](https://www.altexsoft.com/blog/engineering/graphql-core-features-architecture-pros-and-cons/?utm_source=MediumCom&utm_medium=referral&utm_campaign=shared) is a syntax that describes how to make a precise data request. Implementing GraphQL is worth it for an application’s data model with a lot of complex entities referencing each other. + +![**How to retrieve only the needed data from the GraphQL endpoint, Source: [Mohit Tikoo](https://medium.com/@mohittikoo/rest-vs-graphql-will-graphql-do-to-rest-what-xml-did-to-json-c99e4fa639c3)**](https://cdn-images-1.medium.com/max/2800/0*Xl1F4riGJN4RaHBC.png) + +These days the GraphQL ecosystem is expanding with libraries and powerful tools like Apollo, GraphiQL, and GraphQL Explorer. + +#### How GraphQL works + +GraphQL starts with building a **schema,** which is a description of all the queries you can possibly make in a GraphQL API and all the **types** that they return. Schema-building is hard as it requires strong typing in the Schema Definition Language (SDL). + +Having the schema before querying, a client can validate their query against making sure the server will be able to respond to it. On reaching the backend application, a GraphQL operation is interpreted against the entire schema, and resolved with data for the frontend application. Sending one massive query to the server, the API returns a JSON response with exactly the shape of the data we asked for. + +![**Query execution in GraphQL, Source: [Jonas Helfer](https://www.apollographql.com/blog/graphql-explained-5844742f195e)**](https://cdn-images-1.medium.com/max/2004/0*xQQ-afmLh4Yxq2P9.png) + +In addition to the RESTful CRUD operations, GraphQL has **subscriptions** allowing for real-time notifications from the server. + +#### GraphQL pros + +**Typed schema.** GraphQL publishes in advance what it can do, which improves its discoverability. By pointing a client at the GraphQL API, we can find out what queries are available. + +**Fits graph-like data very well.** Data that goes far into linked relations but not good for flat data. + +**No versioning.** The best practice with versioning is not to version the API at all. + +While REST offers multiple API versions, GraphQL uses a single, evolving version that gives continuous access to new features and contributes to cleaner, more maintainable server code. + +**Detailed error messages.** In a similar fashion to SOAP, GraphQL provides details to errors that occurred. Its error message includes all the resolvers and refers to the exact query part at fault. + +**Flexible permissions.** GraphQL allows for selectively exposing certain functions while preserving private information. Meanwhile, REST architecture doesn’t reveal data in portions. It’s either all or nothing. + +#### GraphQL cons + +**Performance issues.** GraphQL trades off complexity for its power. Having too many nested fields in one request can lead to system overload. So, REST remains a better option for complex queries. + +**Caching complexity.** As GraphQL isn’t reusing HTTP caching semantics, it requires a custom caching effort. + +**A lot of pre-development education.** Not having enough time to figure out GraphQL niche operations and SDL, many projects decide to follow the well-known path of REST. + +#### GraphQL use cases + +**Mobile API.** In this case, network performance and single message payload optimization is important. So, GraphQL offers a more efficient data loading for mobile devices. + +**Complex systems and microservices.** GraphQL is able to hide the complexity of multiple systems integration behind its API. Aggregating data from multiple places, it merges them into one global schema. This is particularly relevant for [legacy infrastructures](https://www.altexsoft.com/whitepapers/legacy-system-modernization-how-to-transform-the-enterprise-for-digital-future/?utm_source=MediumCom&utm_medium=referral&utm_campaign=shared) or third-party APIs that have expanded over time. + +## Which API pattern fits your use case best? + +Every API project has different requirements and needs. Usually, the architectural choice depends on + +* the programming language in use, +* the environment in which you’re developing, and +* the resources you have to spare, both human and financial. + +Knowing all the tradeoffs that go into each design style, API designers can pick the one that’s going to fit the project best. + +With its tight coupling, RPC works for internal microservices but it’s not an option for a strong external API or an API service. + +SOAP is troublesome but its rich security features remain irreplaceable for billing operations, booking systems, and payments. + +REST has the highest abstraction and best modeling of the API. But it tends to be heavier on the wire and chattier — a downside if you’re working on mobile. + +GraphQL is a big step forward in terms of data fetching but not everyone has enough time and effort to get the hang of it. + +At the end of the day, it makes sense to try a few small use cases with a particular style, and see if it fits your use case and solves your problems. If it does, try expanding and see if it fits more use cases. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/create-a-private-postgresql-database-for-your-development-environment-in-seconds.md b/article/2020/create-a-private-postgresql-database-for-your-development-environment-in-seconds.md new file mode 100644 index 00000000000..aaab04b5029 --- /dev/null +++ b/article/2020/create-a-private-postgresql-database-for-your-development-environment-in-seconds.md @@ -0,0 +1,281 @@ +> - 原文地址:[Create a Private PostgreSQL Database for Your Development Environment in Seconds](https://medium.com/better-programming/create-a-private-postgresql-database-for-your-development-environment-in-seconds-b781640ed01b) +> - 原文作者:[Doron Chosnek](https://medium.com/@doronchosnek) +> - 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> - 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/create-a-private-postgresql-database-for-your-development-environment-in-seconds.md](https://github.com/xitu/gold-miner/blob/master/article/2020/create-a-private-postgresql-database-for-your-development-environment-in-seconds.md) +> - 译者:[YueYong](https://github.com/YueYongDev) +> - 校对者:[zenblo](https://github.com/zenblo),[hncboy](https://github.com/hncboy) + +# 在几秒钟内为你的开发环境创建一个私有 PostgreSQL 数据库 + +![Photo by [Roi Dimor](https://unsplash.com/@roi_dimor?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/5948/0*msfDTPGlbTAD6DCs) + +很多开发者在开始一个新项目的时候,通常会使用 JSON,CSV 或者其他 Flat File 来模拟真实存放在数据库中的数据。这是因为他们总是在没有真实的数据库环境限制和是否需要自己创建模拟数据库之间左右为难。既然这样,为什么不使用 Docker Compose 定义一个可以在几秒钟内创建、销毁和重新创建的 PostgreSQL 数据库**和监视工具**? + +![Image source: Author](https://cdn-images-1.medium.com/max/2068/0*DHWuzy6UNQ4T1_zl) + +正确创建配置两个容器的 Docker 命令过于冗长。而使用 Docker Compose,你只需要记住 `up` 命令和 `down` 命令! + +`Up` 命令将创建指定版本的 PostgreSQL 数据库和一个 GUI 管理工具。`Down` 命令会将其关闭并删除。 + +## 基于私有容器的数据库的好处 + +- 不同版本的 PostgreSQL 在行为和功能上存在差异,因此开发人员应针对一个数据库版本进行长期开发。你可以选择的一个版本是 9.6.12,另一个可以是 12.4。 +- 大多数程序员都不是数据库管理员或 SQL 专家。可视化工具可以让他们直观地验证其代码的运行效果并支持手动修改数据。 +- 项目的不同阶段需要不同类型的存储方案。在项目早期,非持久型数据库可以最大程度地减少麻烦。在项目的后期阶段,持久型数据库提供了更实际的方案。 + +![Create and recreate a database with simple commands](https://cdn-images-1.medium.com/max/2000/0*oFz9LrOPfZNQdhcw) + +## 建立开发堆栈 + +下面所展示的这份 `docker-compose.yml` 文件定义了一个运行特定版本 PostgreSQL 和 pgAdmin 4(Postgres 最常用的管理工具)的 PostgreSQL 容器。该文件的内容值得我们详细的探讨。 + +```YAML +version: "3.8" +services: + postgres: + image: postgres:9.6.12-alpine + container_name: some-postgres + volumes: + - "~/Documents/docker_pgsql_init:/docker-entrypoint-initdb.d" + - "~/Documents/docker_pgsql_volume:/var/lib/postgresql/data" + ports: + - 5432:5432 + environment: + - POSTGRES_PASSWORD=mysecret + deploy: + restart_policy: + condition: on-failure + max_attempts: 3 + + pgadmin: + image: dpage/pgadmin4 + container_name: some-pgadmin + volumes: + - ${PWD}/servers.json:/pgadmin4/servers.json + ports: + - 8080:80 + environment: + - PGADMIN_DEFAULT_EMAIL=user@domain.com + - PGADMIN_DEFAULT_PASSWORD=admin + deploy: + restart_policy: + condition: on-failure + max_attempts: 3 +``` + +#### Docker Compose 的文件结构 + +该文件定义了两个要创建的“服务”:Postgres 和 pgAdmin。每个服务都包含一个从 Docker Hub 拉取的容器。Postgres 和 pgAdmin 将分别开放 5432 端口和 8080 端口。将你写的任何程序指向主机名“localhost”,然后用浏览器访问 [http://localhost:8080](http://localhost:8080/) 即可访问 pgAdmin。 + +继续阅读有关如何将 pgAdmin 指向 Postgres 的说明。 + +#### PostgreSQL 的版本 + +在定义 Postgres 容器的这一行中,你需要准确指定所需的 Postgres 版本。在这里,版本是一个标签,而 `9.6.12-alpine` 就是示例中使用的版本。点击[这里查看其他可用的版本](https://hub.docker.com/_/postgres?tab=tags)。 + +#### Postgres 的存储 + +上面的 `docker-compose.yml` 文件为 Postgres 指定了两个 volume 映射。这两个映射将使 Postgres 可以访问你计算机上的目录。 + +1. 被映射到 `/docker-entrypoint-initdb.d` 的文件夹包含了初始化 Postgres 将会用到的 SQL 文件。将所需的 SQL 文件和 Shell 脚本放在该目录中,它们将会按字母顺序自动执行。 +2. 被映射到 `/var/lib/postgresql/data` 的文件夹存放了数据库持久化存储所需要的实际文件。 + +当 Postgres 启动时,他的简单运行流程如下图所示。如果数据库中没有数据,那么它将执行被映射到 `/docker-entrypoint-initdb.d` 目录中的每个 SQL 文件和 Shell 脚本(按字母顺序)。如果被映射到 `/var/lib/postgresql/data` 目录的文件夹中有数据,那么它将会忽略掉这些文件。 + +![](https://cdn-images-1.medium.com/max/2024/0*nMQaPxUKmYq67hAa) + +你是否需要挂载这两个目录?这个得视情况而定。下表描述了通过 Postgres 的两个不同映射得到的一个预期结果。 + +![](https://cdn-images-1.medium.com/max/3492/1*gsuTB2Ge04sCccMKLzW6ww.png) + +我的建议是对这两个文件目录都做映射。如果你不想再初始化你的数据库,你可以从 init 目录中删除文件。你也可以在你的计算机上删除任何可能已经持久化的数据(当你下一次运行 `docker-compose up` 命令时,Docker 将会在其位置重新创建一个空文件夹)。 + +**专业提示**:你可以将 CSV 文件放在计算机的 init 文件夹中,然后在 init 目录中通过适当的 SQL 命令将 CSV 文件中的数据填充到数据表中。 + +``` +CREATE TABLE Employee(id, first_name, last_name, salary); +COPY Employee FROM '/docker-entrypoint-initdb.d/emp.csv' + WITH (FORMAT CSV, HEADER); +``` + +#### pgAdmin 的存储 + +![](https://cdn-images-1.medium.com/max/2000/1*pXNa6oSZ72IOr6DCodBWsQ.png) + +尽管 pgAdmin 只是一个用于查看和配置数据库的工具,但必须配置其与数据库的连接。这可以通过可视化工具中的 `add server`指令完成。这里需要注意的是,主机名(the hostname)是我们在 YML 文件中配置的 `container_name` 这一参数的名称,即 `some-postgres`。同样地,密码也已经在 YML 文件中指定了,即 `mysecret`。 + +另一种方法是通过在 JSON 文件中指定这些配置(除了密码之外的所有配置),通过这种方式可以免去大量的单击和输入操作。为了避免手动配置 pgAdmin 到 Postgres 的连接,我们需要将该 JSON 文件映射到容器 `/pgadmin4/servers.json` 上(在示例 YML 文件中的第 22 行)。 + +设置文件可以指定 pgAdmin 和 Postgres 之间的多个连接(以不同用户的身份连接或者连接到多个不同的数据库)。下面是只有一个数据库连接的示例。 + +```JSON +{ + "Servers": { + "1": { + "Name": "my-postgres", + "Group": "Servers", + "Port": 5432, + "Username": "postgres", + "Host": "some-postgres", + "SSLMode": "prefer", + "MaintenanceDB": "postgres" + } + } +} +``` + +#### 网络 + +`container_name` 参数仅仅只表示一个名字。但是 pgAdmin 将使用这个名称访问 5432 端口上的数据库。原因如下图所示。这两个容器通过私有网络相互连接,因此可以通过它们的主机名(容器名)也就是 `some-postgres` 和 `some-pgadmin` 相互访问。然而,你的主机(也就是你的计算机和 web 浏览器)只能访问容器对外暴露的 5432 端口和 8080 端口,因此你可以通过 `localhost:5432` 和 `localhost:8080` 访问它们。 + +![](https://cdn-images-1.medium.com/max/2000/0*U5ZE2OtxU4JKmWTq) + +内部网络的名称可以在 compose 文件中指定,但是为一个从未被代码引用的网络命名没有任何价值!如果你还是好奇,可以随时查看你的私人及临时网络的名称。在下面的代码片段中,我从桌面运行了 Docker Compose,因此将该网络命名为 `desktop_default`。 + +``` +$ docker network ls +NETWORK ID NAME DRIVER SCOPE +23a6be9b8021 bridge bridge local +49a120440f88 desktop_default bridge local +44a949b56fa7 host host local +3892b16dca2d none null local +``` + +## Docker 和 docker-compose 命令 + +在这里,我必须承认我在前言中过于简化了命令操作,但只是稍微简化了一点。 + +**为了启动容器**,可以使用 `docker-compose up -d`。`-d` 参数指定这是一个 `detached` 模式,它将会在后台运行,并且不会影响你在命令提示符中执行其他命令。 + +``` +$ docker-compose up -d +Creating network "desktop_default" with the default driver +Creating some-postgres ... done +Creating some-pgadmin ... done +$ +``` + +**为了关闭并删除容器**,你可以使用 `docker-compose down -v`。`-v` 参数表示删除容器在运行时使用的 volume。这个**不会**删除计算机映射到容器上的目录。 + +``` +$ docker-compose down -v +Stopping some-pgadmin ... done +Stopping some-postgres ... done +Removing some-pgadmin ... done +Removing some-postgres ... done +Removing network desktop_default +``` + +随着时间的推移,如果不使用 `-v` 标志,就会累积不必要的 volume。你可以使用 `docker volume ls` 来验证这一点。 + +如果要调试一个没有正确启动的容器,请使用 `docker logs [container_name]`。例如,由于 init 目录中的一个 SQL 文件中出现错误,数据库可能无法正确初始化。通过执行 `docker logs some-postgres` 命令,可以生成容器启动时记录的日志,通过对该日志的查阅,我在一个特殊命名的 SQL 文件中发现一个错误: + +``` +/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/broken.sql +ERROR: syntax error at end of input at character 34 +STATEMENT: CREATE TABLE Songs(id, name, year +psql:/docker-entrypoint-initdb.d/broken.sql:1: ERROR: syntax error at end of input +LINE 1: CREATE TABLE Song(id, name, year +``` + +日志告诉我在 `broken.sql` 文件的第 1 行有一个错误。该命令缺少右括号和分号。我可以修复这个错误,并使用 `down` 和 `up` 来验证。 + +--- + +## 使用 Python + +使用 localhost 作为 YML 文件中指定的主机名和密码,连接到数据库很容易。 + +```Python +import psycopg2 + +# connect to DB +conn = psycopg2.connect(host="localhost", dbname="postgres", user="postgres", + password="mysecret") +cursor = conn.cursor() + +# execute SQL commands in SQL file +cursor.execute(open("emp.sql", "r").read()) + +# retrieve data from the database +cursor.execute("SELECT * FROM Employee") +print(cursor.fetchall()) +``` + +## 使用 pgAdmin + +简单的访问 [http://localhost:8080](http://localhost:8080) 即可进入登录界面,使用你在 `docker-compose.yml` 文件中定义的用户名和密码登录即可(在我们的示例中是 `user@domain.com` 和 `admin`)。 + +![](https://cdn-images-1.medium.com/max/2248/1*-OLNPQfPVcaVcm55_endYQ.png) + +如果你使用的是本文之前讨论的 `servers.json` 文件来指定连接细节,你将会在展开用户界面左侧的导航树时,收到系统要求你输入 Postgres 数据库的密码的提示。在我们示例的 `docker-compose.yml` 文件中,这个密码是 `mysecret`。如果你并没有创建 `servers.json` 文件或文件中有错误,你就必须手动添加服务器。 + +![](https://cdn-images-1.medium.com/max/2000/1*sMq0Cmnkvn35uUO3pImD4A.png) + +现在,你应该能够查看和操作数据库了。 + +![](https://cdn-images-1.medium.com/max/2248/1*DRpjQBkotrGn8QryDRjQ7w.png) + +## 进入 PSQL + +有时候,开发者需要一个熟悉的命令行。Docker 使得访问 PSQL 和执行高级用户命令等操作变得更加容易。执行下面的命令进入 PSQL 命令行。 + +![](https://cdn-images-1.medium.com/max/2156/0*yYxwukbBZY7poPVw) + +连接后,你就可以执行所有 PSQL 命令,例如,输入 `\i` 用于导入外部数据库,输入 `\dt` 显示数据表的描述,输入 `\df` 显示函数的描述。想要退出,可以使用 `\q` 命令。 + +``` +$ docker exec -it some-postgres psql -U postgres + +psql (9.6.12) +Type "help" for help. + +postgres=# \dt +List of relations +Schema | Name | Type | Owner +--------+--------------+-------+---------- +public | peak | table | postgres +public | climb | table | postgres +public | climber | table | postgres +``` + +## pgAdmin 的替代品 + +![Adminer is a much simpler interface](https://cdn-images-1.medium.com/max/2248/1*m5zp3RSC4VN9_0-IaeSjBg.png) + +pgAdmin 是 PostgreSQL 最常见的 GUI 管理工具,但我们还有其他选择。Adminer 的使用更加简单,并且你可能已经拥有使用它的经验了,因为它支持多种风格的 SQL。如果你是刚开始使用 PostgreSQL 或者只有非常简单的需求,那么它可能是一个更合适你的工具。 + +在登录界面上,设置主机名为 `some-postgres` ,密码为 `mysecret`。 + +![](https://cdn-images-1.medium.com/max/2000/1*iTf4Z6_ATNyE1VW3CTI5dg.png) + +要在你的环境中用 Adminer 替换 pgAdmin,你需要在 `docker-compose.yml` 中替换几行有关 pgAdmin 容器的定义。 + +```YAML + adminer: + image: adminer + container_name: some-adminer + ports: + - 8080:8080 + deploy: + restart_policy: + condition: on-failure + max_attempts: 3 +``` + +## 参考资料 + +所有优秀的开发者都依赖于产品文档和其他人员的经验。这是我在创建工作流程和编写本文时引用的参考资料。 + +- [https://hub.docker.com/\_/postgres](https://hub.docker.com/_/postgres) +- [https://hub.docker.com/\_/adminer](https://hub.docker.com/_/adminer) +- [https://docs.docker.com/compose/compose-file/](https://docs.docker.com/compose/compose-file/) +- [https://www.pgadmin.org/docs/pgadmin4/latest/container_deployment.html](https://www.pgadmin.org/docs/pgadmin4/latest/container_deployment.html) +- [https://technology.amis.nl/2020/01/02/pgadmin-in-docker-provision-connections-and-passwords/](https://technology.amis.nl/2020/01/02/pgadmin-in-docker-provision-connections-and-passwords/) +- [https://stackoverflow.com/questions/42248198/how-to-mount-a-single-file-in-a-volume](https://stackoverflow.com/questions/42248198/how-to-mount-a-single-file-in-a-volume) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2020/creating-a-menu-image-animation-on-hover.md b/article/2020/creating-a-menu-image-animation-on-hover.md index 1c1c46f39e4..54bfc327a97 100644 --- a/article/2020/creating-a-menu-image-animation-on-hover.md +++ b/article/2020/creating-a-menu-image-animation-on-hover.md @@ -2,41 +2,41 @@ > * 原文作者:[Mary Lou](http://www.codrops.com) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/creating-a-menu-image-animation-on-hover.md](https://github.com/xitu/gold-miner/blob/master/article/2020/creating-a-menu-image-animation-on-hover.md) -> * 译者: -> * 校对者: +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[qq1037305420](https://github.com/qq1037305420) 和 [rachelcdev](https://github.com/rachelcdev) -# Creating a Menu Image Animation on Hover +# 如何在悬停时创建菜单图像动画 -[![rapid_feat](https://codropspz-tympanus.netdna-ssl.com/codrops/wp-content/uploads/2020/07/rapid_feat.jpg)](http://tympanus.net/Tutorials/RapidImageHoverMenu/ "Creating a Menu Image Animation on Hover Demo") +![rapid_feat](https://codropspz-tympanus.netdna-ssl.com/codrops/wp-content/uploads/2020/07/rapid_feat.jpg) -- [View demo](http://tympanus.net/Tutorials/RapidImageHoverMenu/) -- [Download Source](https://github.com/codrops/RapidImageHoverMenu/archive/master.zip) +- [查看演示](http://tympanus.net/Tutorials/RapidImageHoverMenu/) +- [下载源码](https://github.com/codrops/RapidImageHoverMenu/archive/master.zip) -At Codrops, we love experimenting with playful hover effects. Back in 2018, we explored a set of fun hover animations for links. We called that [Image Reveal Hover Effects](https://tympanus.net/codrops/2018/11/27/image-reveal-hover-effects/) and it shows how to make images appear with a fancy animation when hovering items of a menu. After seeing the fantastic [portfolio of Marvin Schwaibold](https://www.marvinschwaibold.com/projects/), I wanted to try this effect again on a larger menu and add that beautiful swing effect when moving the mouse. Using some filters, this can also be made more dramatic. +在 `Codrops`,我们喜欢尝试有趣的悬停效果。早在 `2018` 年,我们就探索了一组有趣的悬停动画以获取链接。我们将其称为“图像显示悬停效果”,它展示了如何在悬停菜单项时使图像以精美的动画出现。看完 `Marvin Schwaibold` 出色的[作品集](https://www.marvinschwaibold.com/projects/)之后,我想在更大的菜单上再次尝试这种效果,并在移动鼠标时添加漂亮的摇摆效果。使用一些过滤器,这也可以变得更加生动。 -If you are interested in other similar effect, have a look at these: +如果您对其他类似效果感兴趣,请查看以下内容: -* [Image Trail Effects](https://tympanus.net/codrops/2019/08/07/image-trail-effects/) -* [Image Distortion Effects with SVG Filters](https://tympanus.net/codrops/2019/03/12/image-distortion-effects-with-svg-filters/) -* [Image Dragging Effects](https://tympanus.net/codrops/2020/02/03/image-dragging-effects/) +* [图像轨迹效果](https://tympanus.net/codrops/2019/08/07/image-trail-effects/) +* [滤镜的图像失真效果](https://tympanus.net/codrops/2019/03/12/image-distortion-effects-with-svg-filters/) +* [图像拖拽效果](https://tympanus.net/codrops/2020/02/03/image-dragging-effects/) -So, today we’ll have a look at how to create this juicy image hover reveal animation: +因此,我们今天来看看如何创建这种图像悬停展示动画: -![ezgif-1-49e5dab6c59e](https://user-images.githubusercontent.com/5164225/90801365-659a8f80-e348-11ea-9d32-ff9c90c5836f.gif) +![images](https://user-images.githubusercontent.com/5164225/90801365-659a8f80-e348-11ea-9d32-ff9c90c5836f.gif) -## Some Markup and Styling +## 若干标记和样式 -We’ll use a nested structure for each menu item because we’ll have several text elements that will appear on page load and hover. +我们将为每个菜单项使用嵌套结构,因为我们将在页面加载和悬停时显示几个文本元素。 -But we’ll not go into the text animation on load or the hover effect so what we are interested in here is how we’ll make the image appear for each item. The first thing I do when I want to make a certain effect is to write up the structure that I need using no JavaScript. So let’s take a look at that: +但是我们不会在加载或悬停效果上使用文本动画,因为我们感兴趣的是如何使图像显示在每个菜单项目上。当我想实现某种效果时,我要做的第一件事就是使用 HTML 编写所需的简单结构。让我们看一下代码: ```html Maria Costa - Style Reset 66 Berlin - + Style Reset 66 Berlin +
@@ -45,9 +45,9 @@ But we’ll not go into the text animation on load or the hover effect so what w
``` -In order to construct this markup for the image, we need to save the source somewhere. We’ll use a data attribute on the **menu__item**, e.g. `data-img="img/1.jpg"`. We’ll go into more detail later on. +为了构造图像的标记,我们需要将源图保存在某个地方。我们将在 `menu__item` 上使用 `data` 属性,例如 `data-img="img/1.jpg"`。稍后我们将详细介绍。 -Next, we’ll have some styling for it: +接下来,我们将对其进行一些样式设置: ```css .hover-reveal { @@ -78,19 +78,21 @@ Next, we’ll have some styling for it: } ``` -Any other styles that are specific to our effect (like the transforms) we’ll add dynamically. +我们将继续添加其他特定于我们想要的的动态效果样式(如变换)。 -Let’s take a look at the JavaScript. +接下来,让我们看看 `JavaScript` 部分代码。 -## The JavaScript -We’ll use [GSAP](https://greensock.com/gsap/) and besides our hover animation, we’ll also use a [custom cursor](https://tympanus.net/codrops/2020/03/24/animated-custom-cursor-effects/) and smooth scrolling. For that we’ll use the [smooth scroll library](https://github.com/locomotivemtl/locomotive-scroll) from the amazing folks of Locomotive, the Agency of the year. Since those are both optional and out of the scope of the menu effect we want to showcase, we’ll not be covering it here. +## 使用 JavaScript -First things first: let’s preload all the images. For the purpose of this demo we are doing this on page load, but that’s optional. +我们将使用 [GSAP](https://greensock.com/gsap/),除了悬停动画外,还将使用[自定义光标](https://tympanus.net/codrops/2020/03/24/animated-custom-cursor-effects/)和平滑滚动。为此,我们将使用获得年度最佳代理荣誉的Locomotive开发的[平滑滚动库](https://github.com/locomotivemtl/locomotive-scroll)。由于这些都是可选的,并且超出了我们要展示的菜单效果范围,所以在这里就不再赘述。 -Once that’s done, we can initialize the smooth scroll instance, the custom cursor and our **Menu** instance. +首先,我们要预加载所有图像。出于本演示目的,我们在页面加载时执行此操作,但这是可选的。 + +完成后,我们可以初始化平滑滚动实例、自定义光标和我们的 `menu` 实例。 + +接下来是`JavaScript` 部分代码(index.js),如下所示: -Here’s how the entry JavaScript file (index.js) looks like: ```js import Cursor from './cursor'; @@ -107,7 +109,7 @@ preloader('.menu__item').then(() => { }); ``` -Now, let’s create a class for the **Menu** (in menu.js): +现在,让我们为 `menu` 创建一个类(在 menu.js 中): ```js import {gsap} from 'gsap'; @@ -126,10 +128,9 @@ export default class Menu { } ``` -So far we have a reference to the main element (the menu `
+ + + +``` + +JavaScript 代码如下。跟 REST API 交互的关键代码在于两个获取数据的请求。第一个请求通过访问 `/jokes?_embed=ratings` 获取数据库中所有的笑话,第二个请求是 POST 类型的,它通过访问 `/ratings` 提交对某个笑话的评分。 + +```JavaScript +const jokeContent = document.querySelector('.jokeContent') +const jokeRatingValue = document.querySelector('.jokeRatingValue') +const nextJokeButton = document.querySelector('#nextJoke') + +const jokes = [] +let currentJokeIndex = -1 + +const displayNextJoke = () => { + currentJokeIndex++ + if (currentJokeIndex >= jokes.length) { + currentJokeIndex = 0 + } + + const joke = jokes[currentJokeIndex] + + jokeContent.textContent = joke.content + + const totalScore = joke.ratings.reduce( + (total, rating) => (total += rating.score), + 0 + ) + const numberOfRatings = joke.ratings.length + const averageRating = totalScore / numberOfRatings + + jokeRatingValue.textContent = averageRating.toFixed(1) +} + +const submitJokeRating = () => { + const ratingInput = document.querySelector('input[name="yourRating"]:checked') + + if (ratingInput && ratingInput.value) { + const score = Number(ratingInput.value) + const jokeId = jokes[currentJokeIndex].id + const postData = { jokeId, score } + + fetch('/ratings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(postData), + }) + .then(response => response.json()) + .then(responseData => { + const jokeToUpdate = jokes.find(joke => joke.id === responseData.jokeId) + jokeToUpdate && jokeToUpdate.ratings.push(responseData) + }) + .finally(() => { + ratingInput.checked = false + displayNextJoke() + }) + } else { + displayNextJoke() + } +} + +nextJokeButton.addEventListener('click', submitJokeRating) + +fetch('/jokes?_embed=ratings') + .then(response => response.json()) + .then(data => { + jokes.push(...data) + displayNextJoke() + }) + +``` + +![Dad joke “dadabase” user interface allows you to rate each joke](https://cdn-images-1.medium.com/max/2860/1*vYef9XCI0zejzbFj7lzEPg.png) + +## 安装并使用 Apollo Server + +这样,我们已经完成了项目的架构:它有一个简单的页面,该页面通过 REST API 跟数据库通信。那么,我们如何使用 GraphQL?使用 GraphQL 之前需要哪些准备工作呢?第一步,我们安装 `[apollo-server-express](https://www.npmjs.com/package/apollo-server-express)`,它是一个程序包,用于实现 [Apollo Server](https://www.apollographql.com/docs/apollo-server/getting-started/) 和 Express 的集成。也需要安装 `[apollo-datasource-rest](https://www.npmjs.com/package/apollo-datasource-rest)` 包,用于 REST API 和 Apollo Server 的集成。然后,我们来配置服务器,需要编写以下代码: + +```JavaScript +const express = require('express') +const path = require('path') +const { ApolloServer } = require('apollo-server-express') +const JokesAPI = require('./jokesAPI') +const RatingsAPI = require('./ratingsAPI') +const typeDefs = require('./typeDefs') +const resolvers = require('./resolvers') + +const app = express() +const server = new ApolloServer({ + typeDefs, + resolvers, + dataSources: () => ({ + jokesAPI: new JokesAPI(), + ratingsAPI: new RatingsAPI(), + }), +}) + +server.applyMiddleware({ app }) + +app + .use(express.static(path.join(__dirname, 'public'))) + .get('/', (req, res) => { + res.sendFile('index.html', { root: 'public' }) + }) + .get('/script.js', (req, res) => { + res.sendFile('script.js', { root: 'public' }) + }) + .get('/style.css', (req, res) => { + res.sendFile('style.css', { root: 'public' }) + }) + +app.listen({ port: process.env.PORT || 4000 }, () => { + console.log(`🚀 Server ready at port ${process.env.PORT || 4000}`) +}) + +``` + +你可以看到,我们配置了 Apollo Server 的三个属性:`typeDefs`, `resolvers` 和 `dataSources`。其中,`typeDefs` 属性包含了与我们的 GraphQL API 相关的 [schema](https://www.apollographql.com/docs/apollo-server/schema/schema/),我们在相应的包中定义笑话和评分的数据类型,以及如何查询和更新数据;`resolvers` 告诉服务器如何处理各种各样的查询和更新需求,以及如何连接[数据源](https://www.apollographql.com/docs/apollo-server/data/data-sources/);最后,`dataSources` 大致描述了 GraphQL API 与 REST API 的关联关系。 + +下面的代码定义了 `Joke` 和 `Rating` 数据类型,以及如何查询和更新数据。 + +```JavaScript +const { gql } = require('apollo-server-express') + +const typeDefs = gql` + type Joke { + id: Int! + content: String! + ratings: [Rating] + } + type Rating { + id: Int! + jokeId: Int! + score: Int! + } + type Query { + joke(id: Int!): Joke + jokes: [Joke] + rating(id: Int!): Rating + ratings: [Rating] + } + type Mutation { + rating(jokeId: Int!, score: Int!): Rating + } +` + +module.exports = typeDefs +``` + +下面是 JokesAPI 类的代码,主要定义了笑话数据创建、查询、更新、删除的方法,这些方法分别调用相应的 REST API 实施相关的数据操作。 + +```JavaScript +const { RESTDataSource } = require('apollo-datasource-rest') + +class JokesAPI extends RESTDataSource { + constructor() { + super() + this.baseURL = 'https://dad-joke-dadabase-rest-api.herokuapp.com/' + } + + async getJoke(id) { + return this.get(`jokes/${id}?_embed=ratings`) + } + + async getJokes() { + return this.get('jokes?_embed=ratings') + } + + async postJoke(jokeContent) { + return this.post('jokes', jokeContent) + } + + async replaceJoke(joke) { + return this.put('jokes', joke) + } + + async updateJoke(joke) { + return this.patch('jokes', { id: joke.id, joke }) + } + + async deleteJoke(id) { + return this.delete(`jokes/${id}`) + } +} + +module.exports = JokesAPI +``` + +评分数据跟笑话相似,只是在每个实例中把 “joke” 变为 “rating”。欲获取这部分代码,可以[参考 GitHub 上的代码仓库](https://github.com/thawkin3/dad-joke-dadabase/blob/master/src/ratingsAPI.js)。 + +最后,我们设置解析器,在其中定义如何使用数据源。 + +```JavaScript +const resolvers = { + Query: { + joke: async (_source, { id }, { dataSources }) => + dataSources.jokesAPI.getJoke(id), + jokes: async (_source, _args, { dataSources }) => + dataSources.jokesAPI.getJokes(), + rating: async (_source, { id }, { dataSources }) => + dataSources.ratingsAPI.getRating(id), + ratings: async (_source, _args, { dataSources }) => + dataSources.ratingsAPI.getRatings(), + }, + Mutation: { + rating: async (_source, { jokeId, score }, { dataSources }) => { + const rating = await dataSources.ratingsAPI.postRating({ jokeId, score }) + return rating + }, + }, +} + +module.exports = resolvers +``` + +完成这些步骤,我们一切准备就绪,可以通过 Apollo Server 调用 GraphQL API 了。为了把新的前端页面和 GraphQL API 托管在 Heroku 上,我们需要创建并部署第二个应用程序: + +``` +# 创建 Heroku 应用程序 +heroku create dad-joke-dadabase + +# 把代码部署在 Heroku 上 +git push heroku master + +# 在本地打开 Heroku 应用程序 +heroku open +``` + +## 把 API 端点功能改为获取笑话的代码 + +你应当回忆下,我们有两个 API 端点供前端页面调用:它们的功能分别是获取笑话和提交评分。现在我们把 REST API 中获取笑话的代码改为 GraphQL API 形式: + +```JavaScript +fetch('/jokes?_embed=ratings') + .then(response => response.json()) + .then(data => { + jokes.push(...data) + displayNextJoke() + }) +``` + +我们把上述代码改为: + +```JavaScript +fetch('/graphql', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: ` + query GetAllJokesWithRatings { + jokes { + id + content + ratings { + score + id + jokeId + } + } + } + `, + }), +}) + .then(res => res.json()) + .then(res => { + jokes.push(...res.data.jokes) + displayNextJoke() + }) +``` + +现在,我们可以在本地运行应用程序了。实际上,从用户的角度来说,没有发生任何变化。但假如你在浏览器的开发者工具中查看网络请求,你会发现,现在获取笑话是通过访问 `/graphql` 端点来实现的了。真棒! + +![The Network tab shows a request is being made to the /graphql endpoint now](https://cdn-images-1.medium.com/max/2520/0*ketnaG9b4tR0O0O4.png) + +## 把 API 端点功能改为提交评分的代码 + +一个 API 请求已完成,还有一个!我们现在对评分功能的代码进行修改。提交评分的代码原来类似于: + +```JavaScript +fetch('/ratings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(postData), +}) + .then(response => response.json()) + .then(responseData => { + const jokeToUpdate = jokes.find(joke => joke.id === responseData.jokeId) + jokeToUpdate && jokeToUpdate.ratings.push(responseData) + }) + .finally(() => { + ratingInput.checked = false + displayNextJoke() + }) +``` + +现在我们作如下的改动,让它使用我们的 GraphQL API: + +```JavaScript +fetch('/graphql', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: ` + mutation CreateRating { + rating(jokeId: ${jokeId}, score: ${score}) { + id + score + jokeId + } + } + `, + }), +}) + .then(res => res.json()) + .then(res => { + const rating = res.data.rating + const jokeToUpdate = jokes.find(joke => joke.id === rating.jokeId) + jokeToUpdate && jokeToUpdate.ratings.push(rating) + }) + .finally(() => { + ratingInput.checked = false + displayNextJoke() + }) +``` + +经过快速测试,这段代码符合需求。再次说明,用户体验没有变,但现在我们请求数据使用的都是 `/graphql` 端点。 + +## 结论 + +我们做到了。我们以已有的 REST API 为基础,成功地实现了一个 GraphQL API 端点。因此,我们也能使用 GraphQL 来实现一些核心功能,而且已有的功能和原来的 REST API 都不需要修改。如今我们可以弃用 REST API,它将来也可能会退出历史舞台。 + +虽然 dad joke 数据库是完全虚拟的项目,但几乎所有的在 2015 年 GraphQL 发布会之前成立的科技公司都发现:如果他们改变技术路线,使用 GraphQL,他们自身的情况跟 dad jokes 一样,也是可行的。另外,还有个好消息,Apollo Server 属于较灵活的产品,它也可以从包括 REST API 端点在内的各种数据源获取数据。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/how-to-slow-down-a-for-loop-in-javascript.md b/article/2021/how-to-slow-down-a-for-loop-in-javascript.md new file mode 100644 index 00000000000..ec56199ac53 --- /dev/null +++ b/article/2021/how-to-slow-down-a-for-loop-in-javascript.md @@ -0,0 +1,107 @@ +> * 原文地址:[How To Slow Down A For-Loop in JavaScript](https://medium.com/javascript-in-plain-english/javascript-slow-down-for-loop-9d1caaeeeeed) +> * 原文作者:[Louis Petrik](https://medium.com/@louispetrik) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/how-to-slow-down-a-for-loop-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/article/2021/how-to-slow-down-a-for-loop-in-javascript.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Usualminds](https://github.com/Usualminds)、[samyu2000](https://github.com/samyu2000) + +# 如何让 JavaScript 中的循环慢下来 + +![图源 [Charlotte Coneybeer](https://unsplash.com/@she_sees?utm_source=medium&utm_medium=referral),上传于 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/10368/0*kcAWzuiAUolF3Zkr) + +For 循环在 JavaScript 中是必不可少的。使用 For 循环,我们可以写出与列表有关的程序。但是这里存在一个问题 —— For 循环是尽可能快地执行。当然如果我们只是用它来遍历数组那绝对是没有问题的。 + +但是如果我们在循环中执行请求,那就可能会出现一些问题(例如过高的请求速度让服务器封锁 IP 之类的我们不想看到的情况就会纷至沓来了)。如果我们能实现每隔一段时间才执行一次循环(例如,每秒只执行一次循环操作),也就是使 For 循环的执行放慢一些,那该会有多棒啊! + +在下文中,我们将一起开启探索之旅~ + +## 首先:无效的方法 + +如果你正在寻找直接解决问题的方法,请直接跳过这里吧。而如果你想学习更多有关 JavaScript 的知识,那么就请留步~ + +我想在这里先解释一下为什么常见的解决方案不起作用。 + +首先还是先要感谢 JavaScript 为我们提供的 `setTimeout` 方法,让我们能够实现在一定时间后执行某些代码的功能。咦?这似乎能够满足我们题目的要求啊 —— 我们只需要将 `setTimeout` 加入 For 循环体中,循环速度就会变慢: + +```js +for (let i = 0; i < 100; i++) { + setTimeout(() => { + console.log(i); + }, 1000); +} +``` + +但我们运行上面的代码,却会发生以下情况: + +* 起初先卡顿了一下,随后所有日志同时被打印在控制台上。 + +这完全就不是我们想要的结果呢~ + +造成这个结果的原因是我们陷入了误区。似乎这里 For 循环也并没有为每一个元素设置 `timeout`(但实际上,程序设置了)。 + +我们只是忘记了 JavaScript 是如何执行代码的。循环是会立即创建所有的 `timeout`,而不是顺序创建。这非常快,也因此所有的 `timeout` 都具有几乎相同的**开始时间**。 + +而一旦设置的时间到了,所有的任务都会立即执行 —— 同时打印日志。 + +即便我们按照下面的代码去重写代码,我们仍会看到相同的效果。 + +```js +for (let i = 0; i < 100; i++) { + setTimeout(() => { + }, 1000); + console.log(i); +} +``` + +如果以这个想法为出发点,其实我们可以在其他一些编程语言中达到我们的目标 —— 循环创建 `timeout`,且只有当这些任务执行后,循环才继续执行 —— 至少在其他编程语言中是这样的。但是,在 JavaScript 中,程序可不会停下来,只会继续创建 `timeout`。代码也只会继续执行下去不会停留。因此,JavaScript 可以看作是创建了两个并行运行的线程同时处理 For 循环和 For 循环创建的 `timeout`。 + +## 如何正确地降低 For 循环的执行速度 + +显然,如果我们只使用 **`setTimeout`**,将永远无法达到我们的预期,那我们应该怎么做呢? + +其实解决方案很简单,只需要用一段简单的 `Promise` 语句就行了。 + +```js +const sleep = (time) => { + return new Promise((resolve) => { + return setTimeout(function () { + resolve() + }, time) + }) +} +``` + +我们通过函数调用 `Promise`,而它会获取 **setTimeout** 应该被设置的时间(以毫秒为单位)。在一定时间后,所有 `timeout` 都会执行 `resolve` 函数。这意味着 `Promise` 被我们执行了。我们可以简化上面显示的代码: + +```js +const sleep = (time) => { + return new Promise(resolve => setTimeout(resolve, time)) +} +``` + +使用 `Promise` 可以实现我们需要的功能。现在让我们将它添加到 For 循环中: + +```js +const sleep = (time) => { + return new Promise((resolve) => setTimeout(resolve, time)) +} + +const doSomething = async () => { + for (let i = 0; i < 100; i++) { + await sleep(1000) + console.log(i) + } +} + +doSomething() +``` + +程序每秒执行一次日志打印操作。因此,要输出循环的所有数字,我们需要等待 100 秒。现在我们已经成功的放缓了 For 循环的执行速度! + +感谢你的阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/how-to-use-indexeddb-a-nosql-db-on-the-browser.md b/article/2021/how-to-use-indexeddb-a-nosql-db-on-the-browser.md new file mode 100644 index 00000000000..ff42dd22527 --- /dev/null +++ b/article/2021/how-to-use-indexeddb-a-nosql-db-on-the-browser.md @@ -0,0 +1,214 @@ +> * 原文地址:[How to Use IndexedDB — A NoSQL DB on the Browser](https://blog.bitsrc.io/how-to-use-indexeddb-a-nosql-db-on-the-browser-f845da3caf35) +> * 原文作者:[Viduni Wickramarachchi](https://medium.com/@viduniwickramarachchi) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/how-to-use-indexeddb-a-nosql-db-on-the-browser.md](https://github.com/xitu/gold-miner/blob/master/article/2021/how-to-use-indexeddb-a-nosql-db-on-the-browser.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[Chorer](https://github.com/Chorer) + +# 如何在浏览器上使用 NoSQL 数据库 IndexedDB + +![](https://cdn-images-1.medium.com/max/5760/1*w6RCiqFjxootFGuWpCnkRw.jpeg) + +你听说过浏览器上的 NoSQL 数据库吗? + +> **IndexedDB** 是一个大型的 NoSQL 存储系统。它允许你在用户的**浏览器**中存储任意内容。除了通常的查找、读取和更新操作外,**IndexedDB** 还支持事务。 +> +> 来源:[developers.google.cn](https://developers.google.cn/web/ilt/pwa/working-with-indexeddb) + +你可以在下面找到 IndexedDB 的示例。 + +![[Source](https://developers.google.com/web/ilt/pwa/working-with-indexeddb)](https://cdn-images-1.medium.com/max/3488/1*2XRdyD3uHCnjK-5WXpAfQw.png) + +在本文中,我们将重点介绍以下内容: + +* 为什么我们需要 IndexedDB +* 如何在应用程序中使用 IndexedDB +* IndexedDB 的功能 +* IndexedDB 的局限 +* IndexedDB 是否适合你的应用程序 + +## 为什么我们需要 IndexedDB + +> IndexedDB 被认为比本地存储(`localStorage`)更强大! + +你知道背后的原因吗?让我们一起找出答案。 + +* **可以存储比本地存储(`localStorage`)大得多的数据量** + +IndexedDB 没有像本地存储(`localStorage`)那样的特殊存储限制(介于 2.5MB 和 10MB 之间)。IndexedDB 存储的最大限制取决于浏览器和磁盘空间。例如,Chrome 和基于 Chromium 的浏览器最多允许 80% 的磁盘空间可供使用。如果你有 100GB,则 IndexedDB 最多可以使用 80GB 的空间,单个来源最多可以使用 60GB。 Firefox 允许每个来源最多 2GB,而 Safari 允许每个来源最多 1GB。 + +* **可以存储基于键值对 `{ key: value }` 的任意类型值** + +IndexedDB 存储不同数据类型的灵活性更高。支持的数据类型不仅包括字符串类型,还包括二进制数据(`ArrayBuffer` 对象、`Blob` 对象等)。而 IndexedDB 在内部使用对象存储来保存数据。 + +* **提供查找接口** + +这个功能在其他浏览器存储选项(如本地存储 `localStorage` 和会话存储 `sessionStorage`)中都没有。 + +* **对于不需要持续联网的 Web 应用程序很有用** + +IndexedDB 对于在线和离线工作的应用程序都非常有用。例如,它可以用于渐进式 Web 应用程序(PWA)中的客户端存储。 + +* **可以存储应用状态** + +通过为频繁使用的用户存储应用程序状态,可以大幅提高应用程序的性能,让应用程序可以在后续与后端服务器同步,并通过懒加载来更新应用程序。 + +让我们看一下可以存储多个数据库的 IndexedDB 结构。 + +#### IndexedDB 结构 + +![](https://cdn-images-1.medium.com/max/2120/1*c0AXi5lhjUQiLxRNVJwr2w.png) + +## 如何在应用程序中使用 IndexedDB + +在以下内容中,我们将探讨如何在应用程序中使用 IndexedDB。 + +#### 1. 使用 `window.indexedDB` 打开数据库连接 + +```js +const openingRequest = indexedDB.open('UserDB', 1); +``` + +在这里,`UserDB` 是数据库名称,`1` 是数据库的版本。这将返回一个对象,该对象是 `IDBOpenDBRequest` 接口的实例。 + +#### 2. 创建对象存储 + +开启数据库连接后,将触发 `onupgradeneeded` 事件,该事件可用于创建对象存储。 + +```js +// 创建 UserDetails 对象存储和索引 + +request.onupgradeneeded = (event) => { + let db = event.target.result; + + // 创建 UserDetails 对象存储 + // 具有自动递增 id + let store = db.createObjectStore('UserDetails', { + autoIncrement: true + }); + + // 在 NIC 属性上创建索引 + let index = store.createIndex('nic', 'nic', { + unique: true + }); + }; +``` + +#### 3. 将数据插入对象存储 + +只要开启数据库连接,就可以在 `onsuccess` 事件处理程序中管理数据。插入数据分四步进行。 + +```js +function insertUser(db, user) { + // 创建新的事务 + const txn = db.transaction('User', 'readwrite'); + + // 获取 UserDetails 对象存储 + const store = txn.objectStore('UserDetails'); + + // 插入新记录 + let query = store.put(user); + + // 处理成功案例 + query.onsuccess = function (event) { + console.log(event); + }; + + // 处理错误案例 + query.onerror = function (event) { + console.log(event.target.errorCode); + } + + // 事务结束后关闭数据库 + txn.oncomplete = function () { + db.close(); + }; +} +``` + +创建插入函数后,可以使用请求的 `onsuccess` 事件处理程序插入更多记录。 + +```js +request.onsuccess = (event) => { + const db = event.target.result; + + insertUser(db, { + email: 'john.doe@outlook.com', + firstName: 'John', + lastName: 'Doe', + }); + + insertUser(db, { + email: 'ann.doe@gmail.com', + firstName: 'Ann', + lastName: 'Doe' + }); +}; +``` + +可以在 IndexedDB 上执行很多操作。包括下面这些: + +* 通过键(key)从对象存储中读取或查找数据 +* 通过索引(index)从对象存储中读取或查找数据 +* 更新记录的数据 +* 删除一条记录 +* 从旧版本的数据库迁移等 + +如果你需要关于如何实现上述操作的资料,请在下方评论区告诉我。你也可以参考[这里](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB)获得更多信息。 + +## IndexedDB 的功能 + +IndexedDB 提供了许多其它浏览器存储无法实现的特殊功能。下面简要说明一些功能。 + +* **具有异步 API** + +这样就可以在不阻塞 UI 线程的情况下执行高代价的操作,并为用户提供更好的体验。 + +* **支持可靠性事务** + +如果其中一个步骤失败,事务将被取消,数据库将回滚到以前的状态。 + +* **支持版本控制** + +你可以在创建数据库时对其进行版本控制,并在需要时对其进行升级。在 IndexedDB 中也可以从旧版本迁移到新版本。 + +* **支持私有域** + +数据库是私有域,因此任何站点都不能访问其它网站的 IndexedDB 存储。这也称为**同源策略**。 + +## IndexedDB 的局限 + +到目前为止,IndexedDB 似乎很有希望用于客户端存储。然而,有几个限制值得注意。 + +* 虽然现代浏览器支持 IndexedDB,但是 IE 等浏览器却没有完全支持。 + +![[Source](https://caniuse.com/?search=indexeddb)](https://cdn-images-1.medium.com/max/5472/1*II1BZYdl_uodU0W-6uOAwQ.png) + +* IndexedDB 在 Firefox 的无痕浏览模式下是完全禁用的 —— 通过隐身窗口访问应用程序时,接口无法使用可能导致应用程序出现故障。 + +## IndexedDB 是否适合你的应用程序 + +考虑到 IndexedDB 提供的诸多特性,这个百万美元问题(译者注:指至关重要的问题)答案可能是 Yes!然而,在得出结论之前,先问自己以下几个问题。 + +* 你的应用程序需要离线访问吗? +* 是否需要在客户端存储大量数据? +* 是否需要在大量数据中快速定位或查找数据? +* 应用程序是否使用 IndexedDB 支持的浏览器访问客户端存储? +* 需要存储包括 JavaScript 对象在内的各种类型的数据吗? +* 从客户端存储中写入或读取数据需要是非阻塞的吗? + +如果以上所有问题的答案都是肯定的,那么 IndexedDB 是你的最佳选择。但是,如果不需要这样的功能,你也可以选择本地存储(`localStorage`),因为它提供了大多数浏览器采用和易于使用的应用编程接口(API)。 + +## 总结 + +当我们考虑所有客户端存储机制时,IndexedDB 显然是胜出者。让我们来看一下不同客户端存储方法的总结比较。 + +![](https://github.com/PassionPenguin/gold-miner-images/blob/master/how-to-use-indexeddb-a-nosql-db-on-the-browser-summary-img.png) + +希望你对 IndexedDB 及其特性有一个清晰的认识。也让我们知道你的想法。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer.md b/article/2021/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer.md new file mode 100644 index 00000000000..0331523bb58 --- /dev/null +++ b/article/2021/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer.md @@ -0,0 +1,121 @@ +> - 原文地址:[I Got Into MIT, Refused the Offer, and Still Became a Highly Valued Developer](https://medium.com/better-programming/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer-a4bff1b8cac2) +> - 原文作者:[Zachary Minott](https://medium.com/@zack_minott) +> - 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> - 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer.md](https://github.com/xitu/gold-miner/blob/master/article/2021/i-got-into-mit-refused-the-offer-and-still-became-a-highly-valued-developer.md) +> - 译者:[keepmovingljzy](https://github.com/keepmovingljzy) +> - 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[regonCao](https://github.com/regon-cao) + +# 我拒绝了 MIT 的 Offer,依然是一个高价值的开发者 + +![Photo by [Anthony DELANOIX](https://unsplash.com/@anthonydelanoix?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral).](https://cdn-images-1.medium.com/max/11232/0*pqI507rUeD-sclHu) + +小时候我一直梦想进入 MIT (麻省理工学院),我敢肯定这也是大多数人在申请大学时的想法。 + +你可以能觉得我在异想天开,MIT 不仅有着世界上 [最好](https://www.businessinsider.com/best-computer-science-schools-in-the-world-2018-3#1-massachusetts-institute-of-technology-mit-50) 的计算机科学专业而且还是**** [排名最好的大学](https://news.mit.edu/2020/qs-world%E2%80%99s-no-1-university-2020-21-0609#:~:text=for%202020%2021-,QS%20ranks%20MIT%20the%20world's%20No.,first%20in%2012%20subject%20areas.)。****然后你猜怎么着?我以第一名的成绩考上了并获得奖学金,几乎可以抵掉大多数的学费。如果去了那里,我的技术事业肯定会突飞猛进,并且和许多聪明人打交道。 + +然而 [我去了一所州立学校](https://medium.com/the-ascent/4-brutally-honest-reasons-why-i-declined-my-offer-to-the-worlds-best-university-for-a-state-school-6a70d8a452e7),那地方虽然工程专业虽然算不上顶尖,但是也还行吧。现在我代表着我司 [最重要的编程宝藏之一](https://medium.com/better-programming/how-i-made-myself-a-more-valuable-programmer-in-6-months-and-how-you-can-too-97f3323f9035) ,这使我意识到并非昂贵的,最好的,甚至体面的正规教育才能成就一个有价值的程序员。 + +你们可能在听到埃隆马斯克 [发推文](https://www.inc.com/jeff-haden/if-you-want-to-work-at-tesla-elon-musk-just-tweeted-he-doesnt-care-if-you-even-graduated-high-school-it-might-be-smartest-thing-hes-ever-said.html#:~:text=Musk%20doesn't%20care%20whether,will%20have%20to%20demonstrate%20knowledge.) 告诉你不需要学位,甚至不需要高中毕业就可以为他工作时也会有这种感受。你只需要知道你有什么。 + +不过,我还是很少看到有人在真正探寻自己的学习之路,埃隆的说法并不意味着他就轻易放过了那些缺乏教育的人,恰恰相反,他想要的是一个对 AI 有足够兴趣,自己可以深入地且全面地探索 AI,并且能够 **自我激励** 和 **自力更生** 的人。 + +所以说开发人员应该有自我驱动能力,毕竟埃隆自己也是一个自我驱动型的人,当别人问他如何学习制造火箭,他简要回答:“我通过读书学习”。成为一个自我驱动型的人。 + +**从另一角度来说,你不该这么干** + +## 工程师的成长不应该局限于当前环境 + +很多时候,我们的成长都过度依赖于目前或将来可能所处的位置。 + +你可能会说: + +- “工作没有为我提供足够的资源来学习和成长。” +- “经理给我的任务不足以扩展我的能力。” +- “只有上了正确的大学,才能真正成为一名工程师。相反,我觉得我的学业阻碍了我的天赋发展。” +- “经理没有注意到我,我一直在努力工作。如果我继续努力的话,也许他们最终会注意到并提拔我。” + +邻家的草分外青,人生没有回头路,你的内心充满了悔不当初。这真的只是一个借口。 + +你不能根据自己所处的外部环境就把自己定义成开发人员或者一般人员。 + +仔细想想,工作可能是唯一能练习和扩展知识技能的地方,也许你以某家公司为参考标准,然后总是对自己的公司百般挑剔。也许你完全看不到这个世界的发展,甚至根本没有证据表明自己效率低下。 + +我本可以去 MIT,进入这样的精英大学基本上意味着我是个开发人员了。我本可以说在初创公司工作是浪费时间,我应该去微软或者谷歌实习。我可能因为我花了多年时间学习游戏开发并开发这些附带项目成为一个 Salesforce 开发人员,现状本该让我非常不满。我本可以在生活中游刃有余,而不是自学成才,最终只能想想我还有什么潜力。 + +然而我在回想起我做过的这些决定,其实都是自找的,它们是我的经历,我唯一能做的就是在每个决定中吸取教训。 + +不要抱怨,不要妄想你在其他地方就会做得更好。 + +**你需要意识到这一点** + +## 我们是自己事业的唯一负责人 + +如果你想要变得有价值,就应该自己创造价值。这不是别人的责任,而是你自己的责任。 + +我将通过三个简短的故事来阐释这个概念。 + +#### 故事 1 + +也许我上的工程课不是最好的,但是我上的水球运动课全美排名第三。虽然这与编程无关,但是请允许我讨论一下这个课程。 因为它仍然很有意义。 + +他们为我提供了全额奖学金让我在那里打球,你肯定猜不到我之前在全州最不适合这项运动的高中之一。 在这七个赛区中,我的学校排名垫底,甚至连州冠军都没有进入。 所以它不可能受到关注或着重视。 + +尽管如此,我不会让我的环境阻挡我的步伐。 + +我给自己额外加练。我每天都去参加很多次训练。我报名参加了最好的水球营。这一切都是为了让自己被人看到。 + +最终,所有这些额外的辛苦让我连续两年创造了县内进球数最多的记录。我也不会等着招聘者来找我,而是我主动联系了他们,给他们发游戏视频,让他们来找我。我被招收到全国最好的水球项目之一,这些只是我自己的目标导向行动的结果。 + +这次经历对我今后的发展影响巨大。一个人必须去做别人不愿意做的事情,才能达到自己想要达到的目标。现实是被你的决定所影响的。 + +这次经历为我未来的编程生涯和生活奠定了基础。 + +#### 故事 2 + +当我开始我的计算机科学课程时,我想成为一名游戏开发者,但整个课程都是基于 Java 编程语言。 + +也就是说我没有机会去学习电子游戏是如何制作的,所以我打算自学。利用空闲时间阅读有关游戏开发的内容,参加在线课程,并创建自己的项目。最终,我获得了在两家增强现实初创公司工作的机会,在那里我最终不再喜欢这个小众行业。然而如果我不依靠自学,我永远不会获得这些经验。 + +这种价值是我自己创造的。多亏了这些年来努力地探索其他开发领域,让我作为一名开发人员得到了更大的成长。 + +#### 故事 3 + +我目前所在的公司,最初有一个为期 9 周的培训项目。我只需要获得两个 Salesforce 认证,然后他们**可能**会把我承包给某个客户,让我和他们一起工作几个月。但我没有把自己限制在这两个认证上,而是告诉他们我想要四个认证。他们说以前从来没有这样做过,我也不能这样做。 + +不用说,我在九周内就通过了四项认证,创下了公司记录,这让我获得了全公司范围内的奖励,并立即被一家快速成长的初创公司咨询机构咨询。我向公司的 CEO 证明了自己的能力,我们正在讨论让我成为一个技术领导,并有可能让我成为他旗下公司未来的 CTO。现在还不到八个月。 + +我是通过和他们分享我的个人目标和人生哲学来做到这一点的。公开分享我认为需要改进的地方来做到这一点。不断向他们更新我的所有进展来做到这一点。为了做到这个,我完成了那些超出我当时能力所及的困难任务。 + +我暴露了野心,展现了执行力。实现了承诺。证明自己能胜任目前岗位。而不仅仅是通过汇报来让他们注意到我的成果和品质——我让他们意识到这些品质。 + +## 意义何在 + +你应该对你的将来负责。 + +如果你想升职又不想被人注意,那么把你工作周报发给经理甚至 CEO / CTO。这样他们就不会忽视你的生产力和主动性。这是 John Sonmez 在他的书 **A Complete Software Developer Career Guide** 中提到的。 + +是不是觉得你在目前的工作中成长得不够快?可以在业余时间阅读编程书籍,输出编程文章分享你学习成果,构建小的辅助项目来拓展部分技能。观看科技行业最知名大佬的网络讲座,甚至是花点时间阅读,了解一些流行的开源项目的代码功能。这是 Sonmez 书中提到的另一项倡议。 + +总有一条路可以成长。总有办法让自己变得更有价值。总有办法让自己得到认可。 + +您只需要意识到自己必须做出决定并执行计划,将这些事情变为现实。而不是等待天上掉馅饼。 + +## 总结 + +编程是一门复杂而精细的手艺,需要不断的打磨和雕琢。 + +如果你真的想创造价值,就需要做别人不愿意做的事情。 + +你需要学会时间管理,扪心自问什么对自己和自我成长是真正重要的。 + +也许你已经做到了,也许你已经把每件事都做对了。这很好。我真为你高兴。你走在正确的道路上。 + +重要的是,你要不断地尽最大努力为你所从事的项目、你所在的团队、你所在的公司,最重要的是为你自己提供最大价值。 + +提供价值是你能给任何公司、任何人和你自己的最好礼物。这一切都归结于通过你所做的行动和决定来创造价值。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +------ + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/importing-json-modules-in-typescript.md b/article/2021/importing-json-modules-in-typescript.md new file mode 100644 index 00000000000..cd0a3bd9d86 --- /dev/null +++ b/article/2021/importing-json-modules-in-typescript.md @@ -0,0 +1,123 @@ +> * 原文地址:[Importing JSON Modules in TypeScript](https://mariusschulz.com/blog/importing-json-modules-in-typescript) +> * 原文作者:[Marius Schulz](https://mariusschulz.com/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/importing-json-modules-in-typescript.md](https://github.com/xitu/gold-miner/blob/master/article/2021/importing-json-modules-in-typescript.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[regonCao](https://github.com/regon-cao) + +# 在 TypeScript 中引入 JSON 模块 + +TypeScript 2.9 版本引入了一个新的 `--resolveJsonModule` 编译选项,让我们可以在 TypeScript 模块内部引入 JSON 模块。 + +## 通过 `require` 函数的调用引入 JSON 模块 + +假设我们有一个用 TypeScript 编写的 Node 应用程序,并且假设我们要导入以下 JSON 文件: + +```json +{ + "server": { + "nodePort": 8080 + } +} +``` + +在 Node 中,我们可以调用 `require` 函数导入这一个 JSON 文件,就像是导入别的 CommonJS 模块一样: + +```typescript +const config = require("./config.json"); +``` + +这一个 JSON 文件会被自动的反序列化为普通的 JavaScript 对象,让我们可以轻松访问配置对象的属性: + +```typescript +"use strict"; + +const express = require("express"); +const config = require("./config.json"); + +const app = express(); + +app.listen(config.server.nodePort, () => { + console.log(`在端口 ${config.server.nodePort} 上监听...`); +}); +``` + +迄今为止,一切都挺棒的! + +## 通过使用静态的 `import` 声明语句导入 JSON 文件 + +现在如果说我们要使用原生的 ECMAScript 模块而不是 CommonJS 模块,那么我们必须将 `require` 的调用转换为静态的 `import` 声明: + +```typescript +// 因为所有的 ECMAScript 模块都默认使用 strict 模式 +// 我们不需要再声明 `use strict` + +import * as express from "express"; +import * as config from "./config.json"; + +const app = express(); + +app.listen(config.server.nodePort, () => { + console.log(`在端口 ${config.server.nodePort} 上监听...`); +}); +``` + +现在,程序在第 2 行中出现了类型错误。TypeScript 不允许我们按照这种方式开箱即用地导入 JSON 模块。这是 TypeScript 团队的一项明智的设计决定:获取较大的 JSON 文件可能会[消耗大量内存](https://github.com/Microsoft/TypeScript/pull/22167#issuecomment-385479553)。这就是为什么我们需要通过启用 `--resolveJsonModule` 编译器标志来选择使用该功能: + +> 让人们有意识地选择这个做法帮助着用户了解耗费的成本。 + +让我们转到 **tsconfig.json** 文件并在其中启用该选项: + +```json +{ + "compilerOptions": { + "target": "es2015", + "module": "commonjs", + "strict": true, + "moduleResolution": "node", + "resolveJsonModule": true + } +} +``` + +在声明了 `--resolveJsonModule` 以后,我们的 TypeScript 文件现在不会再出现类型错误。而且,我们现在还拥有了类型检查和自动补全功能! + +如果使用上面显示的编译器选项编译 TypeScript 文件,则会得到以下 JavaScript 输出: + +```typescript +"use strict"; + +Object.defineProperty(exports, "__esModule", {value: true}); + +const express = require("express"); +const config = require("./config.json"); + +const app = express(); + +app.listen(config.server.nodePort, () => { + console.log(`在端口 ${config.server.nodePort} 上监听...`); +}); +``` + +注意,输出与我们的第一个方法(使用 `require`) 几乎相同: + +```typescript +"use strict"; + +const express = require("express"); +const config = require("./config.json"); + +const app = express(); + +app.listen(config.server.nodePort, () => { + console.log(`在端口 ${config.server.nodePort} 上监听...`); +}); +``` + +这就是在 TypeScript 模块中导入 JSON 模块的方法!我们仅需在配置文件中通过设置 `resolveJsonModule` 这个编译器选项的值为 `true` 即可启用这个功能! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/improving-node-application-performance-with-clustering.md b/article/2021/improving-node-application-performance-with-clustering.md new file mode 100644 index 00000000000..df197fd292a --- /dev/null +++ b/article/2021/improving-node-application-performance-with-clustering.md @@ -0,0 +1,503 @@ +> * 原文地址:[Improving Node.js Application Performance With Clustering](https://blog.appsignal.com/2021/02/03/improving-node-application-performance-with-clustering.html) +> * 原文作者:[Joyce Echessa](https://echessa.com/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/improving-node-application-performance-with-clustering.md](https://github.com/xitu/gold-miner/blob/master/article/2021/improving-node-application-performance-with-clustering.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[Ashira97](https://github.com/Ashira97) + +# 通过集群提高 Node.js 应用程序性能 + +在构建应用程序产品时,我们通常会寻找一些方法来尽可能优化应用程序的性能。在本文中,我们将探讨一种能有效改善 Node.js 应用程序处理工作负载的方法。 + +Node.js 实例是在单个进程中运行的,意味着在如今大多数计算机都在使用的多核系统(multi-core system)上,该应用程序不会使用所有 CPU。要想使用其他可用 CPU,可以通过集群模式启动 Node.js 进程并在它们之间分配负载。 + +因为可以同时为多个客户端提供服务,拥有多个进程来处理请求可以有效提高服务器的吞吐量(每秒请求数)。在本文中,我们将首先探讨如何使用 Node.js 集群模块创建子进程,然后我们将探讨如何使用 PM2 进程管理器管理集群。 + +## 集群简介 + +Node.js [集群模块](https://nodejs.org/api/cluster.html)支持创建同时运行并共享同一服务器端口的子进程(工作进程)。每个衍生的子对象都有自己的事件循环、内存和 V8 实例。子进程使用进程间通信(IPC)与父进程进行通信。 + +有多个进程来处理传入请求意味着可以同时处理多个请求,如果一个工作进程上有长时间运行或阻塞操作,其他工作进程可以继续处理传入请求。即使存在阻塞操作也不影响整体任务,完成正常传入任务以及阻塞任务,整个应用程序就可以结束运行。 + +通过运行多个工作进程,我们可以在不停机情况下更新应用程序。我们可以在修改应用程序,每次只重启一个工作进程,等待一个子进程完全生成后再重启另一个子进程。这样,在我们更新应用程序时,就一直会有工作进程在维持运作。 + +传入的连接是通过以下两种方式之一在子进程之间分配的: + +* 除了 Windows 平台,所有平台默认采用主进程监听端口上的连接,并以循环方式将它们分布在工作进程中的方法。 +* 主进程创建一个监听套接字,并将其发送给相关的工作进程,然后这些工作进程将能够直接收到传入的连接。 + +## 使用集群 + +要查看集群的优势,我们将从不使用集群的 Node.js 应用程序示例开始,然后将其与使用集群的应用程序进行比较: + +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}) + +app.get('/api/:n', function (req, res) { + let n = parseInt(req.params.n); + let count = 0; + + if (n > 5000000000) n = 5000000000; + + for(let i = 0; i <= n; i++){ + count += i; + } + + res.send(`count 结果是 ${count}`); +}) + +app.listen(port, () => { + console.log(`App 监听端口 ${port}`); +}) +``` + +这有点假,在现实世界中基本不存在,但它能够满足我们的需求。这个应用程序包含两条路径 —— 一条路是由返回字符串 “Hello World”,而另一条路是由采用路由参数 `n`,在返回包含最终统计的字符串之前,将 `n` 个数字加到一个 `count` 变量中。 + +该操作是一个 `O(n)` 操作,如果我们将 n 设定为一个足够大的值,这个方法就能够简单模拟在服务器上长时间运行操作的情景。我们将 `n` 限制在 `5,000,000,000` —— 让我们的计算机不必运行如此多的操作。 + +如果你使用 `node app.js` 运行应用程序,并向它传递一个适当小的 `n` 值(例如 `http://localhost:3000/api/50`),它将快速执行并几乎立即返回响应。根路由(`http://localhost:3000`)也会快速返回响应。 + +当你传递给它一个比较大的 `n` 值的时候,你将看到在一个进程上运行应用程序所带来的问题。你可以自己试试传递一个 `5,000,000,000`(通过 `http://localhost:3000/api/5000000000`)这么大的数字给它。 + +应用程序可能需要几秒钟才能完成你的请求。而如果你打开另一个浏览器选项卡并尝试向服务器发送另一个请求(发送到 `/` 或 `/api/:n` 路由),该请求将需要几秒钟才能完成,因为单个进程将忙于处理另一个长时间运行的操作 —— 单个 CPU 内核必须先完成第一个请求,然后才能处理另一个请求。 + +现在,让我们使用应用程序中的集群模块来产生一些子进程,看一下是如何改进的。 + +以下是修改后的应用: + +```js +const express = require('express'); +const port = 3000; +const cluster = require('cluster'); +const totalCPUs = require('os').cpus().length; + +if (cluster.isMaster) { + console.log(`CPU 数量是 ${totalCPUs}`); + console.log(`正在运行 ${process.pid}`); + + // 分叉工作进程 + for (let i = 0; i < totalCPUs; i++) { + cluster.fork(); + } + + cluster.on('exit', (worker, code, signal) => { + console.log(`销毁进程 ${worker.process.pid}`); + console.log("分叉另一个工作进程!"); + cluster.fork(); + }); + +} else { + const app = express(); + console.log(`启动进程 ${process.pid}`); + + app.get('/', (req, res) => { + res.send('Hello World!'); + }) + + app.get('/api/:n', function (req, res) { + let n = parseInt(req.params.n); + let count = 0; + + if (n > 5000000000) n = 5000000000; + + for(let i = 0; i <= n; i++){ + count += i; + } + + res.send(`count 结果是 ${count}`); + }) + + app.listen(port, () => { + console.log(`App 监听端口 ${port}`); + }) + +} +``` + +这个应用程序做了和之前一样的事情,但是这一次,我们正在产生几个子进程,它们都将共用端口 `3000`,并且能够处理发送到这个端口的请求。工作进程是使用 [`child_process.fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options) 方法生成的。该方法返回一个 [`ChildProcess`](https://nodejs.org/api/child_process.html#child_process_child_process) 对象,该对象具有一个内置的通信通道,允许消息在子进程与其父进程之间来回传递。 + +我们在运行应用程序的机器上创建尽可能多的子进程。建议不要在计算机上创建超过逻辑核心数量的工作进程,因为这可能会导致进程调度方面的开销。出现这种情况是因为系统必须调度所有创建的进程,以便每个进程都能轮到在内核上运行。 + +工作进程由主进程创建和管理。当应用程序第一次运行时,我们用 `isMaster` 检查它是否是一个主进程。这是由 `process.env.NODE_UNIQUE_ID` 变量决定的。如果 `process.env.NODE_UNIQUE_ID` 是 `undefined`,则 `isMaster` 为 `true`。 + +如果进程是一个主进程,那么我们可以去调用 `cluster.fork()` 来产生几个进程。我们记录下主进程和工作进程的标识,并可以在下面的输出中看到在四核系统上运行该应用程序的输出结果。当一个子进程终止时,我们会产生一个新的进程来继续运行可用的中央处理器内核。 + +``` +Number of CPUs is 4 +Master 67967 is running +Worker 67981 started +App listening on port 3000 +Worker 67988 started +App listening on port 3000 +Worker 67982 started +Worker 67975 started +App listening on port 3000 +App listening on port 3000 +``` + +要体验使用集群获得的改进效果,请运行与之前相同的示例:首先向服务器发送一个很大的 `n` 值请求,然后在另一个浏览器选项卡中快速运行另一个请求。第二个请求将在第一个请求仍在运行时完成,而无需等待其它请求完成。由于可以使用多个工作进程来处理请求,因此服务器可用性和吞吐量都得到了提高。 + +在一个浏览器选项卡中运行一个请求,然后在第二个选项卡中快速运行另一个请求,可能会向我们展示本示例通过集群提供的改进,但这并不是适当或可靠的确定性能改进的方法。让我们看一些基准测试,这些基准测试可以更好地说明集群在多大程度上改善了我们的应用程序。 + +## 性能指标 + +让我们在两个应用程序上进行负载测试,以便了解每个应用程序如何处理大量传入连接。我们将为此使用 [loadtest](https://www.npmjs.com/package/loadtest) 依赖包。 + +通过 `loadtest` 依赖包,你可以模拟与 API 的大量并发连接,从而可以评估其性能。 + +要使用 `loadtest`,首先需要全局安装它: + +```bash +$ npm install -g loadtest +``` + +然后,使用 `node app.js` 运行要测试的应用程序。我们将首先测试不使用集群的版本。 + +在应用程序运行的情况下,打开另一个终端并运行以下负载测试: + +```bash +$ loadtest http://localhost:3000/api/500000 -n 1000 -c 100 +``` + +上面的命令会将 `1000` 个请求发送到给定的 URL,其中 `1000` 个是并发的。以下是运行上述命令的输出结果: + +``` +Requests: 0 (0%), requests per second: 0, mean latency: 0 ms + +Target URL: http://localhost:3000/api/500000 +Max requests: 1000 +Concurrency level: 100 +Agent: none + +Completed requests: 1000 +Total errors: 0 +Total time: 1.268364041 s +Requests per second: 788 +Mean latency: 119.4 ms + +Percentage of the requests served within a certain time 50% 121 ms + 90% 132 ms + 95% 135 ms + 99% 141 ms + 100% 142 ms (longest request) +``` + +我们看到,使用相同的请求(`n` = `500000`),服务器能够每秒处理 `788` 个请求,平均等待时间为 `119.4` 毫秒(完成单个请求所需的平均时间)。 + +让我们再试一次,但是这次是更多请求(并且没有集群): + +```sh +$ loadtest http://localhost:3000/api/5000000 -n 1000 -c 100 +``` + +以下是输出结果: + +``` +Requests: 0 (0%), requests per second: 0, mean latency: 0 ms +Requests: 573 (57%), requests per second: 115, mean latency: 798.3 ms + +Target URL: http://localhost:3000/api/5000000 +Max requests: 1000 +Concurrency level: 100 +Agent: none + +Completed requests: 1000 +Total errors: 0 +Total time: 8.740058135 s +Requests per second: 114 +Mean latency: 828.9 ms + +Percentage of the requests served within a certain time 50% 869 ms + 90% 874 ms + 95% 876 ms + 99% 879 ms + 100% 880 ms (longest request) +``` + +对于 `n` = `5000000` 的请求,服务器每秒可以处理 `114` 个请求,平均等待时间为 `828.9` 毫秒。 + +让我们将此结果与使用集群的应用程序进行比较。 + +停止非集群应用程序,运行集群应用程序,最后运行相同的负载测试。 + +以下是 `http://localhost:3000/api/500000` 的测试结果: + +``` +Requests: 0 (0%), requests per second: 0, mean latency: 0 ms + +Target URL: http://localhost:3000/api/500000 +Max requests: 1000 +Concurrency level: 100 +Agent: none + +Completed requests: 1000 +Total errors: 0 +Total time: 0.701446328 s +Requests per second: 1426 +Mean latency: 65 ms + +Percentage of the requests served within a certain time 50% 61 ms + 90% 81 ms + 95% 90 ms + 99% 106 ms + 100% 112 ms (longest request) +``` + +经过相同请求的测试(当 `n` = `500000` 时),使用集群的应用程序每秒可以处理 `1426` 个请求 —— 与不包含集群的应用程序每秒 `788` 个请求相比,显着增加。使用集群的应用程序平均延迟为 `65` 毫秒,而没有使用集群的应用程序的平均延迟为 `119.4`。你可以清楚地看到集群为应用程序带来的改进效果。 + +以下是对 `http://localhost:3000/api/5000000` 的测试结果: + +``` +Requests: 0 (0%), requests per second: 0, mean latency: 0 ms + +Target URL: http://localhost:3000/api/5000000 +Max requests: 1000 +Concurrency level: 100 +Agent: none + +Completed requests: 1000 +Total errors: 0 +Total time: 2.43770738 s +Requests per second: 410 +Mean latency: 229.9 ms + +Percentage of the requests served within a certain time 50% 235 ms + 90% 253 ms + 95% 259 ms + 99% 355 ms + 100% 421 ms (longest request) +``` + +在这里(当 `n` = `5000000` 时),该应用程序每秒可以运行 `410` 个请求,相比之下,没有集群的应用程序有 `114` 个,延迟为 `229.9`,而其他应用程序为 `828.9`。 + +在继续下一部分之前,让我们看一下集群可能无法提供很多性能改进的情况。 + +我们将为每个应用程序再运行两次测试。我们将测试那些不是 CPU 密集型(CPU-intensive)的、运行速度相当快的请求,而不会使事件循环过载操作。 + +在无集群应用程序运行的情况下,执行以下测试: + +```sh +$ loadtest http://localhost:3000/api/50 -n 1000 -c 100 +``` + +以下是小结的结果: + +``` +Total time: 0.531421648 s +Requests per second: 1882 +Mean latency: 50 ms +``` + +在同一集群应用程序仍在运行的情况下,执行以下测试: + +```sh +$ loadtest http://localhost:3000/api/5000 -n 1000 -c 100 +``` + +以下是小结的结果: + +``` +Total time: 0.50637567 s +Requests per second: 1975 +Mean latency: 47.6 ms +``` + +现在,停止应用程序,再次运行集群应用程序。 + +运行集群应用程序,执行以下测试: + +```sh +$ loadtest http://localhost:3000/api/50 -n 1000 -c 100 +``` + +以下是小结的结果: + +``` +Total time: 0.598028941 s +Requests per second: 1672 +Mean latency: 56.6 ms +``` + +集群应用程序每秒能够运行 `1672` 个请求,而非集群应用程序每秒只能够运行 `1882` 个请求。集群应用程序平均延迟为 `56.6` 毫秒,而非集群应用程序平均延迟为 `50` 毫秒。 + +让我们运行另一个测试。在同一集群应用程序仍在运行的情况下,执行以下测试: + +```sh +$ loadtest http://localhost:3000/api/5000 -n 1000 -c 100 +``` + +以下是小结的结果: + +``` +Total time: 0.5703417869999999 s +Requests per second: 1753 +Mean latency: 53.7 ms +``` + +在这里,集群应用程序每秒运行 `1753` 个请求,而非集群应用程序每秒运行 `1975` 个请求。集群应用程序的平均延迟为 `53.7` 毫秒,而非集群应用程序为 `47.6` 毫秒。 + +基于这些测试,可以看到集群并没有给应用程序的性能带来太大的改善。事实上,与不使用集群的应用程序相比,集群应用程序的性能稍差。怎么会这样? + +在上面的测试中,我们使用一个相当小的 `n` 值调用 API,这意味着代码将运行非常少的循环次数。该操作不会占用大量 CPU。当涉及到 CPU 密集型任务时,集群会起作用。当你的应用可能运行 CPU 密集型任务时,就一次可运行此类任务的数量而言,使用集群将提高应用程序性能。 + +但是,如果你的应用程序没有执行大量的 CPU 密集型任务,那么通过集群模式获得的性能提升可能并不足以弥补产生大量工作进程带来的开销。请记住,你创建的每个进程都有其自身的内存和 V8 实例。由于存在额外的资源分配,因此通常不建议生成大量 Node.js 子进程。 + +在我们的示例中,集群应用程序的性能要比非集群应用程序差一些,因为我们要花一些开销来创建多个子进程,而这些子进程并没有太多优势。在现实世界中,你可以使用它来确定微服务体系结构中的哪些应用程序可以从集群中受益 —— 运行测试以检查这种额外复杂性的好处是否值得。 + +## PM2 管理集群 + +在我们的应用程序中,我们使用 Node.js 集群模块(`cluster module`)手动创建和管理工作进程。我们首先确定要产生的工作进程数量(使用 CPU 内核的数量),然后手动产生这些工作进程,最后,监听任何终止的工作进程,以便我们可以产生新的工作进程。在非常简单的应用程序中,我们需要编写大量代码来处理集群。在生产应用程序中,你也需要编写更多内容。 + +有一个工具可以帮助更好地管理流程 —— [PM2](https://pm2.keymetrics.io/) 流程管理器。 PM2 是带有内置负载均衡器的 Node.js 应用程序的生产过程管理器。正确配置后,PM2 将自动在集群模式下运行你的应用程序,为你生成工作程序,并在工作程序死亡时照顾新工作程序的产生。 PM2 使得停止,删除和启动进程变得容易,它还具有一些监视工具,可以帮助你监视和调整应用程序的性能。 + +要使用 PM2,请先在全局进行安装: + +```sh +$ npm install pm2 -g +``` + +我们将使用它来运行我们的第一个未修改的应用程序: + +```js +const express = require('express'); +const app = express(); +const port = 3000; + +app.get('/', (req, res) => { + res.send('Hello World!'); +}) + +app.get('/api/:n', function (req, res) { + let n = parseInt(req.params.n); + let count = 0; + + if (n > 5000000000) n = 5000000000; + + for(let i = 0; i <= n; i++){ + count += i; + } + + res.send(`count 结果为 ${count}`); +}) + +app.listen(port, () => { + console.log(`App 监听端口 ${port}`); +}) +``` + +使用以下命令运行该应用程序: + +```sh +$ pm2 start app.js -i 0 +``` + +`-i ` 将告诉 PM2 在 `cluster_mode` (而不是 `fork_mode`)下启动应用程序。如果 `` 设置为 `0`,PM2 将自动生成与 CPU 核心数量一样多的工作进程。 + +就像这样,应用程序以集群模式运行 —— 无需修改代码。现在,可以运行与前面相同的测试,可以得到与使用集群的应用程序相同的结果。在后台,PM2 还使用 Node.js 集群模块(`cluster module`)以及其它好用的流程管理工具。 + +在终端会看到一个列表,其中显示了一些衍生进程的详细信息: + +![PM2 Cluster](https://d33wubrfki0l68.cloudfront.net/95a8689e159614b649e45f6f24bb12f1ecf6ae3a/83cd2/images/blog/2021-02/pm2_cluster.png) + +可以使用以下命令停止应用程序: + +```sh +$ pm2 stop app.js +``` + +应用程序将离线,终端输出将显示所有进程的终止(`stopped`)状态。 + +![Stopped app](https://d33wubrfki0l68.cloudfront.net/3f2289bd93daf31b044a86b88c1966da0ac07fd4/91949/images/blog/2021-02/stopped_app.png) + +可以使用 `pm2 start app.js -i 0` 运行应用程序时不必总是传递配置,你也可以将它们保存到单独的配置文件中,称为[生态系统文件(Ecosystem File)](https://pm2.keymetrics.io/docs/usage/application-declaration/#ecosystem-file)。该文件还允许你为不同的应用程序设置特定的配置,例如,这对于微服务应用程序特别有用。 + +可以使用以下命令生成生态系统文件: + +```sh +$ pm2 ecosystem +``` + +它将生成一个名为 `ecosystem.config.js` 的文件。同时,我们需要对该文件进行如下修改: + +```js +module.exports = { + apps : [{ + name: "app", + script: "app.js", + instances : 0, + exec_mode : "cluster" + }] +} +``` + +通过使用集群值(`cluster value`)设置 `exec_mode`,可以指示 PM2 在每个实例之间进行负载平衡。将实例设置为 `0`,这将产生与 CPU 内核数量一样多的工作进程。 + +`-i` 或 `instances` 选项可以设置为: + +* `0` 或 `max`(已弃用)将应用程序进程分布到所有 CPU 上 +* `-1` 将应用程序分布在所有 CPU -1 上 +* `number` 将应用程序分布在 CPU `number` 上 + +你现在可以通过以下命令运行该应用程序: + +```sh +$ pm2 start ecosystem.config.js +``` + +该应用程序将像之前那样在集群模式下运行。 + +你可以分别使用以下命令启动、重新启动、重新加载、停止和删除应用程序: + +```sh +$ pm2 start app_name +$ pm2 restart app_name +$ pm2 reload app_name +$ pm2 stop app_name +$ pm2 delete app_name + +# 使用生态系统文件时: + +$ pm2 [start|restart|reload|stop|delete] ecosystem.config.js +``` + +重新启动(`restart`)命令会立即终止并重新启动进程,而重新加载(`reload`)命令会实现零秒停机时间(0-second-downtime)重新加载,工作进程会一个接一个地重新启动,等待新的工作进程产生,然后再终止旧的工作进程。 + +你还可以检查正在运行的应用程序的状态、日志和指标。 + +以下命令是列出 PM2 管理的所有应用程序的状态: + +```sh +$ pm2 ls +``` + +以下命令是实时显示日志: + +```sh +$ pm2 logs +``` + +以下命令是在终端中显示实时仪表板: + +```sh +$ pm2 monit +``` + +有关 PM2 及其[集群模式(cluster mode)](https://pm2.keymetrics.io/docs/usage/cluster-mode/)的更多信息,请查看[文档](https://pm2.io/blog/2018/04/20/Node-js-clustering-made-easy-with-PM2)。 + +## 总结 + +首先我们讲到了,集群为我们提供了一种通过更有效地利用系统资源来提高 Node.js 应用程序性能的方法。当一个应用程序被修改为使用集群时,我们能够看到吞吐量的显著提高。然后我们在下文中简单了解了一下可以帮助你简化集群管理过程的工具。希望这篇文章对你有用。有关集群的更多信息,请查看[集群模块(cluster module)](https://nodejs.org/api/cluster.html)文档和 [PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) 的文档,你也可以看一下这个[教程](https://leanpub.com/thenodejsclustermodule/read)。 + +**我们的特约作者 Joyce Echessa 是全栈 Web 开发人员。她偶尔会在技术文章中写下自己的想法,以记录自己所学的各种知识。** + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/javascript-temporal-api-a-fix-for-the-date-api.md b/article/2021/javascript-temporal-api-a-fix-for-the-date-api.md new file mode 100644 index 00000000000..5d325a4ba54 --- /dev/null +++ b/article/2021/javascript-temporal-api-a-fix-for-the-date-api.md @@ -0,0 +1,228 @@ +> * 原文地址:[JavaScript Temporal API- A Fix for the Date API](https://blog.bitsrc.io/javascript-temporal-api-a-fix-for-the-date-api-aa8381a4234c) +> * 原文作者:[Nathan Sebhastian](https://medium.com/@nathansebhastian) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/javascript-temporal-api-a-fix-for-the-date-api.md](https://github.com/xitu/gold-miner/blob/master/article/2021/javascript-temporal-api-a-fix-for-the-date-api.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Chorer](https://github.com/Chorer)、[Usualminds](https://github.com/Usualminds) + +# JavaScript Temporal API —— Date API 问题的一个解决方案 + +![](https://cdn-images-1.medium.com/max/2024/1*iq9Xe8BZue94e2BD4ecpqA.png) + +JavaScript 的日期处理 API 比较糟糕,因为它是直接对 [Java 的 `Date` 类](https://docs.oracle.com/javase/6/docs/api/java/util/Date) 进行复制来实现了 `Date` 对象,而 Java 维护者最终弃用了许多 `Date` 类的方法,并于 1997 年创建了 `Calendar` 类以取代它。 + +但是 JavaScript 的 `Date` API 还没有进行进一步修复,这就是为什么我们今天会遇到以下问题: + +* `Date` 对象是可变的 +* 用于日期和时间计算的混乱 API(例如,天数的加减) +* 仅支持 UTC 和本地时区 +* 从字符串中解析日期的不可靠 +* 不支持公历以外的其他历法 + +但由于目前 `Date` API 被广泛地应用于各种库和浏览器引擎中,我们暂时不可能修复其错误部分。如果我们更改它的底层实现,就会很可能对许多现有的网站和库造成破坏性影响。 + +新的 `Temporal` API 提案旨在解决 `Date` API 的问题,它对 JavaScript 的日期和时间操作进行了以下改进: + +* 仅创建和处理不可变的 `Temporal` 对象 +* 用于日期和时间计算的简单 API +* 支持所有时区 +* 遵循 ISO-8601 格式进行严格的日期解析 +* 支持非公历的历法 + +> 请记住,`Temporal` 提案[当前处于第二阶段](https://github.com/tc39/proposal-temporal#status),尚未准备好用于生产环境中。 + +让我们借助代码示例理解 `Temporal` API 的功能吧。下文中的所有 `Temporal` API 代码都是使用 [Temporal Polyfill](https://www.npmjs.com/package/proposal-temporal) 创建的。 + +## 不可变的日期对象 + +使用 JavaScript 的 `new Date()` 构造器创建的 `Date` 对象是可变的,意味着你可以在初始化以后修改它的值: + +```js +let date = new Date("2021-02-20"); +console.log(date); // 2021-02-20T00:00:00.000Z +date.setYear(2000); +console.log(date); // 2000-02-20T00:00:00.000Z +``` + +尽管看似无关紧要,但这种可变的对象在处理不当时可能会导致错误,其中一种情况就是当我们尝试将天数添加到当前日期时。 + +例如,这是一个将当前日期增加一周的功能。 由于 `setDate` 会修改对象本身,因此我们会得到**两个具有相同日期值的对象**: + +```js +function addOneWeek(date) { + date.setDate(date.getDate() + 7); + return date; +} + +let today = new Date(); +let oneWeekLater = addOneWeek(today); + +console.log(today); +console.log(oneWeekLater); // 值和变量 today 一样 +``` + +`Temporal` 提供了不直接修改对象的方法,进而修复了这个问题,例如下面就是使用 `Temporal` API 添加一周的例子: + +```js +const date = Temporal.now.plainDateISO(); +console.log(date); // 2021-02-20 +console.log(date.add({days: 7})); // 2021-02-27 +console.log(date); // 2021-02-20 +``` + +如上面的代码所示,`Temporal` 为我们提供了 `.add()` 方法,让我们能将天、周、月或年添加到当前日期对象中而不会修改原始值。 + +## 用于日期和时间计算的 API + +前面的 `Temporal` 示例中我们了解到了 `.add()` 方法,它能帮助我们对日期对象执行计算。我们现在使用的 `Date` API 仅提供了获取和设置日期值的方法,不如 `Temporal` 来得简单直接。 + +`Temporal` 还为我们提供了多个 API 来计算日期值。比如说 `until()` 方法,它可以计算 `firstDate` 和 `secondDate` 之间的时间差。 + +而如果使用 `Date` API,我们需要手动计算两个日期之间的天数,如下所示: + +```js +const oneDay = 24 * 60 * 60 * 1000; +const firstDate = new Date(2008, 1, 12); +const secondDate = new Date(2008, 1, 22); + +const diffDays = Math.round(Math.abs((firstDate - secondDate) / oneDay)); +console.log(diffDays); // 10 +``` + +如果是 `Temporal` API,我们可以通过 `until()` 方法简单地计算 `diffDays`: + +```js +const firstDate = Temporal.PlainDate.from('2008-01-12'); +const secondDate = Temporal.PlainDate.from('2008-01-22'); + +const diffDays = firstDate.until(secondDate).days; +console.log(diffDays); // 10 +``` + +其他的帮助我们计算的方法还有: + +* [`.subtract()` 方法](https://tc39.es/proposal-temporal/docs/plaindate.html#subtract),用于减少当前日期的天数、月数或年数。 +* [`.since()` 方法](https://tc39.es/proposal-temporal/docs/plaindate.html#since),用于计算一个特定日期迄今为止所经历的天数、月数或年数。 +* [`.equals()` 方法](https://tc39.es/proposal-temporal/docs/plaindate.html#equals),用于比较两个日期是否相同。 + +这些 API 能够帮助我们去完成计算,而无需自己创建解决方案。 + +## 支持所有时区 + +当前的 `Date` API 在系统中以 UTC 标准跟踪时间,通常会在计算机的时区中生成日期对象,操纵时区没有简单的方法。 + +我发现操纵时区的一种方式是使用 `Date.toLocaleString()` 方法,如下所示: + +```js +let date = new Date(); +let tokyoDate = date.toLocaleString("en-US", { + timeZone: "Asia/Tokyo" +}); +let singaporeDate = date.toLocaleString("en-US", { + timeZone: "Asia/Singapore", +}); + +console.log(tokyoDate); // 2/21/2021, 1:36:46 PM +console.log(singaporeDate); // 2/21/2021, 12:36:46 PM +``` + +但是由于此方法返回一个字符串,因此进一步的日期和时间操作要求我们先将字符串转换回日期。 + +而 `Temporal` API 允许我们在使用 `zonedDateTimeISO()` 方法创建日期的时候去定义时区。我们可以使用 `.now` 对象去获取当前的日期、时间: + +```js +let tokyoDate = Temporal.now.zonedDateTimeISO('Asia/Tokyo'); +let singaporeDate = Temporal.now.zonedDateTimeISO('Asia/Singapore'); + +console.log(tokyoDate); +// 2021-02-20T13:48:24.435904429+09:00[Asia/Tokyo] +console.log(singaporeDate); +// 2021-02-20T12:48:24.429904404+08:00[Asia/Singapore] +``` + +由于返回的值仍然是 `Temporal` 日期,因此我们可以使用 `Temporal` 本身的方法进一步对其进行操作: + +```js +let date = Temporal.now.zonedDateTimeISO('Asia/Tokyo'); +let oneWeekLater = date.add({weeks: 1}); + +console.log(oneWeekLater); +// 2021-02-27T13:48:24.435904429+09:00[Asia/Tokyo] +``` + +`Temporal` API 遵循使用类型的约定,其中以 `Plain` 开头的名称是没有时区的(`.PlainDate`、`.PlainTime`、`.PlainDateTime`),而 `.ZonedDateTime` 则相反。 + +## 遵循 ISO-8601 标准进行严格的日期解析 + +现有的从字符串解析日期的方式是不可靠的,因为当我们传递 ISO-8601 格式的日期字符串时,返回值将根据是否传递了时区偏移量而有所不同。 + +考虑以下示例: + +```js +new Date("2021-02-20").toISOString(); +// 2021-02-20T00:00:00.000Z +new Date("2021-02-20T05:30").toISOString(); +// 2021-02-20T10:30:00.000Z +``` + +上面的第一个 `Date` 构造器将字符串视为 UTC+0 时区,而第二个构造器将字符串视为 UTC-5 时区(我当前所在的时区),因此返回值会被调整到 UTC+0 时区**(5:30 UTC-5 相当于 10:30 UTC+0)**。 + +`Temposal` 提案通过区分 `PlainDateTime` 和 `ZonedDateTime` 来解决此问题,如下所示: + +![来源:[临时提案文档](https://tc39.es/proposal-temporal/docs/index.html#string-persistence)](https://cdn-images-1.medium.com/max/2000/1*Y4XViVCg-Cl6KtivlWbF5A.png) + +当我们想要使日期成为包含时区的对象时,我们需要使用 [ZonedDateTime](https://tc39.es/proposal-temporal/docs/index.html#Temporal-ZonedDateTime) 对象,反之则使用 [PlainDateTime](https://tc39.es/proposal-temporal/docs/index.html#Temporal-PlainDateTime) 对象。 + +通过分开创建包含时区和不包含时区的日期,`Temporal` API 可帮助我们从提供的字符串中解析正确的日期、时间组合: + +```js +Temporal.PlainDateTime.from("2021-02-20"); +// 2021-02-20T00:00:00 + +Temporal.PlainDateTime.from("2021-02-20T05:30"); +// 2021-02-20T05:30:00 + +Temporal.ZonedDateTime.from("2021-02-20T05:30[Asia/Tokyo]"); +// 2021-02-20T05:30:00+09:00[Asia/Tokyo] +``` + +从上面的示例中可以看到,`Temporal` API 不会对你所在的时区进行预设。 + +## 支持公历以外的历法 + +尽管公历是世界上使用最广泛的日历系统,但有时我们可能需要使用其他日历系统以查看具有文化或宗教意义的特殊日期。 + +`Temporal` API 允许我们指定要用于日期、时间计算的日历系统。 + +日历的 NPM Polyfill 实现尚未完成,因此我们需要尝试使用 Browser Polyfill 中的 `withCalendar()` 方法。请访问 [Temporal 文档页面](https://tc39.es/proposal-temporal/docs/),然后将以下代码粘贴到浏览器的控制台中: + +```js +Temporal.PlainDate.from("2021-02-06").withCalendar("gregory").day; +// 6 + +Temporal.PlainDate.from("2021-02-06").withCalendar("chinese").day; +// 25 + +Temporal.PlainDate.from("2021-02-06").withCalendar("japanese").day; +// 6 + +Temporal.PlainDate.from("2021-02-06").withCalendar("hebrew").day; +// 24 + +Temporal.PlainDate.from("2021-02-06").withCalendar("islamic").day; +// 24 +``` + +一旦提案通过,[Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters) 中所有可能的日历值都将被实现。 + +## 结论 + +`Temporal` API 是针对 JavaScript 的一项新提案,有望为该语言提供现代化的日期和时间 API。而根据我基于 Polyfill 的测试,该 API 确实提供了更简单的日期和时间操作,同时也考虑到了时区和日历的差异。 + +该提案本身仍处于第二阶段,因此,如果你有兴趣了解更多信息并提供反馈,你可以访问 [Temporal 文档](https://tc39.es/proposal-temporal/docs/index.html) 并尝试其提供的 [Polyfill NPM 包](https://www.npmjs.com/package/proposal-temporal)。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/json-encoding-decoding-with-python.md b/article/2021/json-encoding-decoding-with-python.md new file mode 100644 index 00000000000..5a0a5b07d5b --- /dev/null +++ b/article/2021/json-encoding-decoding-with-python.md @@ -0,0 +1,134 @@ +> * 原文地址:[JSON encoding/decoding with Python](https://levelup.gitconnected.com/json-encoding-decoding-with-python-62a2cae63a6a) +> * 原文作者:[Martin Thoma](https://medium.com/@martinthoma) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/json-encoding-decoding-with-python.md](https://github.com/xitu/gold-miner/blob/master/article/2021/json-encoding-decoding-with-python.md) +> * 译者: +> * 校对者: + +# JSON Libraries in Python - Comparing by Speed, Maturity, and Operational Safety + +![Photo by [chuttersnap](https://unsplash.com/@chuttersnap?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/12032/0*iesq6b2IrRZHExHL) + +JSON is a cornerstone for the exchange of data on the Internet. REST APIs use the standardized message format all around the world. Being a subset of JavaScript, it got a huge initial boost in its adoption right from the start. The fact that its syntax is pretty clear and easy to read also helped. + +JSON has libraries in every language I know for serialization and deserialization. In Python, there are actually multiple libraries. In this article, I will compare them for you. + +## The libraries + +**CPython** itself has a `[json](https://docs.python.org/3/library/json.html)` module. It was originally developed by Bob Ippolito as `simplejson` and was merged into Python 2.4 ([source](https://docs.python.org/3/whatsnew/2.6.html#the-json-module-javascript-object-notation)). CPython is licensed under the Python Software Foundation License. + +**simplejson** still exists as its own library and you can install it via pip. It is a pure Python library with an optional C extension. Simplejson is licensed under the MIT and the Academic Free License (AFL) license. + +[**ujson**](https://pypi.org/project/ujson/) is a binding to the C library [Ultra JSON](https://github.com/ultrajson/ultrajson). Ultra JSON was developed by ESN ([an Electronic Arts Inc. studio](https://techcrunch.com/2012/09/26/electronic-arts-buys-online-gaming-development-studio-esn/)) and is licensed under the [3-clause BSD License](https://tldrlegal.com/license/bsd-3-clause-license-(revised)). Ultra JSON has 3k stars on Github, 305 forks, 50 contributors, the last commit is only 12 days old and the last issue was opened 5 days ago. I’ve heard that it is in “maintenance mode” ([source](https://github.com/ultrajson/ultrajson/issues/428#issuecomment-699456053)), indicating that there is no new development. + +**pysimdjson** is a binding to the C++ library [simdjson](https://github.com/simdjson/simdjson). SIMDjson received funding from Canada. simdjson has 12.2k stars on Github, 611 forks, 63 contributors, the last commit was 11 hours ago, and the last issue was opened 2 hours ago. + +**python-rapidjson** is a binding to the C++ library [RapidJSON](https://github.com/Tencent/rapidjson). RapidJSON was developed by [Tencent](https://en.wikipedia.org/wiki/Tencent). RapidJSON has 9.8k stars on GitHub, 2.7k forks, 150 contributors, the last commit was about 2 months ago and the last issue was opened 17 days ago. + +[**orjson**](https://pypi.org/project/orjson/) is a Python package that relies on Rust to do the heavy lifting. + +## Maturity and Operational Safety + +All mentioned libraries worked for the benchmark examples without issues. Switching the JSON module is not a super big deal, but still, I want to know that the module is supported. + +CPython, simplejson, ujson, and orjson consider themselves production-ready. + +python-rapidjson marks itself as alpha, but one maintainer says that is a mistake and will be fixed soon ([source](https://github.com/python-rapidjson/python-rapidjson/issues/140#issuecomment-699475354)). + +![Image by Martin Thoma](https://cdn-images-1.medium.com/max/3052/1*U5_u-RSFKJonoiyITzMzAg.png) + +## The Questions + +One indicator of how easy it might be to resolve problems is to ask questions and see how the behavior is: + +* [SimpleJSON](https://github.com/simplejson/simplejson/issues/267): I’ve got a response the next day. The response was clear, easy to follow, friendly. [Bob Ippolito](undefined) answered me — the guy who originally developed it and who also is mentioned in the Python docs for the JSON module! +* [uJSON](https://github.com/ultrajson/ultrajson/issues/428): I’ve got a clear, friendly, easy to follow answer within 30 minutes. @hugovank +* [ORJSON](https://github.com/ijl/orjson/issues/127): No reaction for 10days, then it was closed without any comment. +* [PySIMDJSON](https://github.com/TkTech/pysimdjson/issues/54): No answer after 15days. +* [Python-RapidJSON](https://github.com/python-rapidjson/python-rapidjson/issues/140): I’ve got a clear, friendly, easy to follow answer within 30 minutes. A [simple PR](https://github.com/python-rapidjson/python-rapidjson/pull/143) was merged after ten days. + +One answer I’ve got for all of the projects is that they are essentially not in contact with each other. + +## The Benchmark + +In order to benchmark the different libraries properly, I thought of the following scenarios: + +* **APIs**: Web services that exchange information. It might contain Unicode and have a nested structure. A JSON file from a Twitter API sounds good to test this. +* **API JSON Error**: I was curious about how the performance would change if there was an error in the JSON API format. So I removed a brace in the middle. +* **GeoJSON**: I’ve first seen [the GeoJSON format](https://en.wikipedia.org/wiki/GeoJSON) with [Overpass Turbo](https://overpass-turbo.eu/), an Open Streep Map exporter. You will get crazy big JSON files with mostly coordinates, but also pretty nested. +* **Machine Learning**: Just a massive list of floats. Those might be weights of a neural network layer. +* **JSON Line**: Structured logs are heavily used in the industry. If you analyze those logs, you might need to go through Gigabytes of data. They are all simple dictionaries with a datetime object, a message, the logger, log status, and maybe some more. + +#### Deserialization Speed + +The speed of my hard drive gives a lower boundary for the speed to read. I’ve included it as a baseline in the following 3 charts. + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*T6ZZEdyTdAfk2H7ZUROXQw.png) + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*l9edlCf_jRRmfk2c3E6sTQ.png) + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*mdU1HzX6SvyPmRQxvT267w.png) + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*dF6H5_XkF0B0zYFohYh8Fg.png) + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*UvxjYlDcM507RIVBytu78w.png) + +The conclusion from this: + +* Rapidjson is slow, but for small JSONs like the twitter.json, you will not notice a difference. One can see this with the structured logs. +* simdjson, orjson, and ujson are all crazy fast. +* Reading a JSON file that contains a structural error is equally fast for most libraries. A notable exception is rapidjson. I guess that it aborts reading the file once it finds the error. + +#### Serialization Speed + +In this case, I created the JSON-String beforehand and measured the time it takes to write it to disk as a baseline. + +![Image by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*li98MCygc3bb3CNeM6UmiQ.png) + +![Image by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*H-6Jn-siAFZol3zaMK3tZQ.png) + +![Image by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*euOrrhI4Ds2-rXc3I0MlBg.png) + +![Image created by Martin Thoma](https://cdn-images-1.medium.com/max/4800/1*vE2gNIkOy7087tGdeX0ZTA.png) + +What I conclude from this: + +* orjson is just insanely fast. It is super close to maxing out my hard drive. And ujson is pretty close to that. +* rapidjson is pretty quick, but not on the same level as orjson or ujson. +* simdjson is slow. + +## A professional workflow with JSON + +As a closing note, I want to point out some issues I see sometimes and have written myself: + +* Calling variables `foo_json` : JSON is a string format. If it’s not a string, it’s not JSON. If you deserialized a JSON with `bar = json.loads(foo)` , then `bar` is not a JSON. You can serialize `bar` to a JSON which is equivalent to the JSON`foo` , but `bar` is not a JSON. It’s a Python object. Very likely a dictionary. You can then all it `foo_dict` . +* Attribute checks all over the place: If you receive a JSON, it’s super easy to convert it to a Python object (e.g. a dict) and use it. This is fine for proof-of-concept code or very small JSON strings. It will bite you in the ass if you don’t convert it to something like a [dataclass](https://docs.python.org/3/library/dataclasses.html). + +[pydantic](https://github.com/samuelcolvin/pydantic) is a super helpful validation library. You can take the JSON-string, parse it to a Python base representation with dictionaries / lists / strings / numbers / booleans with your favorite JSON library and then parse it again with Pydantic. The advantage you get from this is that you know what you’re dealing with later. No longer just `Dict[str, Any]` as a [type annotation](https://medium.com/analytics-vidhya/type-annotations-in-python-3-8-3b401384403d). No longer unhelpful editor autocompletion. No longer checking if attributes exist all over your code. + +To include other json packages than the default `json` , I recommend the pattern + +```py +import ujson as json +``` + +For Flask, you can use another [encoder](https://flask.palletsprojects.com/en/1.1.x/api/#flask.json.JSONEncoder)/[decoder](https://flask.palletsprojects.com/en/1.1.x/api/#flask.json.JSONDecoder) like this: + +```py +from simplejson import JSONEncoder, JSONDecoder + +app.json_encoder = JSONEncoder +app.json_decoder = JSONDecoder +``` + +## See also + +* [Daniel Lemire](undefined): [Parsing JSON Really Quickly: Lessons Learned](https://www.youtube.com/watch?v=wlvKAT7SZIQ) at InfoQ +* [Ng Wai Foong](undefined): [Introduction to orjson](https://levelup.gitconnected.com/introduction-to-orjson-3d06dde79208) +* [Nicolas Seriot](undefined): [Parsing JSON is a Minefield](http://seriot.ch/parsing_json.php) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/machine-learning-with-android-11-whats-new.md b/article/2021/machine-learning-with-android-11-whats-new.md new file mode 100644 index 00000000000..e3f2a5edd67 --- /dev/null +++ b/article/2021/machine-learning-with-android-11-whats-new.md @@ -0,0 +1,197 @@ +> * 原文地址:[Machine Learning with Android 11: What’s new](https://proandroiddev.com/machine-learning-with-android-11-whats-new-1a8d084c7398) +> * 原文作者:[Rishit Dagli](https://medium.com/@rishit.dagli) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/machine-learning-with-android-11-whats-new.md](https://github.com/xitu/gold-miner/blob/master/article/2021/machine-learning-with-android-11-whats-new.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[HumanBeing](https://github.com/HumanBeingXenon)、[keepmovingljzy](https://github.com/keepmovingljzy)、[lsvih](https://github.com/lsvih) + +# 使用 Android 11 进行机器学习:新功能 + +![使用 Android 11 进行机器学习:新功能](https://cdn-images-1.medium.com/max/3840/1*_6zTCa-SeOV2q549ey3b5Q.jpeg) + +本文将会向大家展示如何使用专为 [Android 11](https://developer.android.com/11) 设计的工具或插件来开始使用设备上的 ML(Machine Learning,机器学习)功能。如果你以前在 Android 中使用过 ML,则可以跟随本文一起探索将你的 ML 应用程序与 Android 应用程序集成的更简便方法。而如果你没有在 Android 中使用过 ML,那么这可能是你使用 Android 进行 ML 的起点,开始你使用 ML 为你的 Android 应用程序提供超强功能之旅。在此博客中,我将主要演示 Android 11 的两个最强大的更新:[ML 模型绑定插件](https://developer.android.com/studio/preview/features#tensor-flow-lite-models)和[新的 ML Kit 套件](https://g.co/mlkit)。我们下面讨论的所有示例应用程序代码都可以在[此 GitHub 存储库](https://github.com/Rishit-dagli/ML-with-Android-11)中找到。 + +你也可以在 [GitHub 存储库](https://github.com/Rishit-dagli/ML-with-Android-11/blob/master/talks.md)中查看有关该主题的讨论。 + +## 为什么我们要关心 Android 设备上 ML 功能? + +如你所见,我们在本文中主要关注设备上的 ML。Android 11 对设备上的 ML 做出了许多很酷的更新,但先简述一下我们为什么要对此加以关注。你也将这里知道为什么会有这么多关于 ML 或 终端 ML 的宣传。 + +**设备上的 ML 背后的理念:** + +这里使用 ML 的方法与我们的旧有方法恰好相反,我们不再将设备上的数据发送到服务器或某个基于云的系统,在上面使用 ML 判断数据,然后再将得出的结论返回给设备。取而代之的是,直接利用设备上的 ML 模型获取输出或推断,即不再让设备发送数据给服务器判断数据,利用移动设备本身,完成所有的处理和推断。 + +![设备上 ML 背后的理念](https://cdn-images-1.medium.com/max/3836/1*O1a_Su6P-XggXk9IXTSzMQ.jpeg) + +你不会直接将模型用于你的设备,而需要在导入前先对你的模型进行压缩或优化,以便能够在设备上正常的运行它 —— 因为终端设备的计算能力、网络可用性和磁盘空间有限。但在本文中,我们将跳过优化过程,直接部署 `.tflite` 模型文件。而你可以进一步了解 [TensorFlow Lite](https://www.tensorflow.org/lite/)和[模型优化过程](https://www.tensorflow.org/lite/performance/model_optimization)。 + +**设备上进行 ML 的优势** + +使用设备上 ML 的一些优点: + +* 能量消耗 + +你所能够想到的第一件事应该就是能耗:曾经你需要耗费大量的能量,将你的视频数据连续发送或流式传输到服务器。但有时这样做是不可行的 —— 没有数据网络的时候。值得一提的是,如果你对你的数据先做大量的预处理,倒也能节省些能耗。 + +* 推理时间 + +另一项要考虑的重要事项是获取输出或实际运行模型所花的时间。对于实时应用而言,这是一个相当重要的层面。程序无需发送或接受数据,加快了推理的速度。 + +* 网络可用性 + +使用传统方法在考虑网络可用性层面也是相当昂贵的,因为你的设备必须在适宜的带宽或网络环境中,才能连续发送数据并从服务器接收数据才能正常获取 ML 结果。 + +* 安全 + +最后,你的数据的安全性也将提升:设备不再需要将数据发送到服务器或基于云的系统,即不再将数据发送出设备,从而增强了安全性。 + +## ML 模型绑定插件 + +> 注意:您需要 Android Studio 4.1 或更高版本才能使用 ML 模型绑定插件 + +**ML 模型绑定插件主要关注什么?** + +你可以从“模型构建”这个名称中做出足够合理的猜测,从而了解 [ML 模型绑定插件](https://developer.android.com/studio/preview/features#tensor-flow-lite-models)。它确实可以使我们非常轻松地使用自定义 TF Lite 模型,让我们这群开发人员可以方便地导入任何 TFLite 模型,读取导入的模型的输入或输出的签名,并且只需要再调用几行代码,就可以使用 TensorFlow Lite Android 支持库。 + +ML 模型绑定插件使您可以在应用程序中轻松使用 TF 模型。从本质上讲,你需要编写的调用 TensorFlow Lite Android 支持库的代码要少得多。如果你曾经使用过 TensorFlow Lite 模型,则你可能知道你首先需要将所有内容都转换为 `ByteArray`。使用 ML 模型绑定插件,你将不再需要再将所有内容都转换为 `ByteArray`。 + +我喜欢这个新插件的另一个原因是我可以轻松地使用 GPU 和 NN API。使用 ML 模型绑定插件,使用它们从未如此简单。现在,要使用它们,我们仅仅只需要调用一个依赖项和一行代码。难道使用 模型绑定 插件不酷嘛?借助 Android 11 神经网络 API,我们甚至还拥有了无符号整数权重支持和新的服务质量(QOS)API,也同时还支持了更多的终端场景。使用上文谈及的这些功能,你绝对可以更快地进行开发! + +**使用模型绑定插件** + +现在让我们看看如何实现所讨论的内容。 + +因此,第一步是导入带有元数据的 TensorFlow Lite 模型。Android Studio 现在有一个用于导入 TensorFlow 模型的新选项:只需右键单击要导入它的模块,随后你将会在 `Others` 下看到一个叫 `TF Lite Model` 的选项。 + +![Android Studio 中的导入模型选项](https://cdn-images-1.medium.com/max/2500/1*fnNNyLYKqafERAjUfwPsxQ.jpeg) + +我们只需传递 `tflite` 模型的路径即可,而它就会自动地在你之前选择的 `ml` 模块中的目录中为我们导入模型。我们现在就可以在其中使用该模型,并且我们只需几个单击即可添加依赖项目和使用 GPU 加速。 + +![导入 `tflite` 模型](https://cdn-images-1.medium.com/max/2502/1*wJmnVf7wtCOV50HnXXmmPQ.jpeg) + +现在从我的模型元数据中,我还可以知道输入、输出的类型以及其他需要被使用的信息 —— 我们可以通过在 Android Studio 中打开 `tflite` 模型文件来查看此信息。在这个屏幕截图中,我使用的是我制作的开源模型来对剪刀、石头、布进行区分。我们只需将手放在摄像头前即可识别出是剪刀还是石头还是布,这也是我在本文中演示的内容。 + +![查看模型元数据](https://cdn-images-1.medium.com/max/2502/1*ZHuSORcTLhxtSWr60TzxWA.jpeg) + +最后,让我们开始使用该模型,以便进行流推断,这很可能也是你想要执行的操作:实时图像分类。要实现这个,最简单的方法是使用 Camera X,并将每个帧传递给可以执行推理的函数。在这里,其实我感兴趣的是进行推断的函数。我们可以发现执行此操作真的是非常容易:在导入可以使用的 TF Lite 模型时,似乎也同时生成了一份示例代码。 + +```kotlin +private val rpsModel = RPSModel.newInstance(ctx) +``` + +这里我们将首先实例化一个 `rps` 模型,该模型是剪刀石头布模型的缩写,并将其传递给上下文。在使用这个插件,同时我的模型名称为 `RPS Model.tflite` 的情况下,程序为我创建了一个完全相同名称的类,一个名为 `RPS Model` 的类。 + +```kotlin +val tfImage = TensorImage.fromBitmap(toBitmap(imageProxy)) +``` + +现在我们需要将数据转换为可使用的格式,以便将其从 `Bitmap` 转换为 `Tensor Image`。如果我们使用 TF 解释器,则我们需要将图像转换为一个`ByteArray`。但现在我们无需再这样做了 —— 直接交给一个图片代理去处理即可。 + +```kotlin +val outputs = rpsModel.process(tfImage) + .probabilityAsCategoryList.apply { + sortByDescending { it.score } // 排序,高匹配率优先 + }.take(MAX_RESULT_DISPLAY) // 抱走第一 +``` + +现在我们已经将数据传递给模型,我们将处理模型中的图像并获得输出,我们将基本上得到一个匹配率的数组并对其进行降序排序,以获取具有最大值的概率,然后选择降序列表的第一名显示出来。 + +```kotlin +for (output in outputs) { + items.add( + Recognition( + output.label, + output.score + ) + ) +} +``` + +最后,我需要向用户显示标签,因此我将在输出中添加与每个条目相对应的标签。这就是我们所需要的全部代码! 🚀~ + +**使用 GPU 加速** + +如果我们想要使用 GPU 加速,其实做法非常简单。我们只需要在要使用 GPU 并进行构建模型的地方创建一个 `options` 对象。我只是将其作为参数传递给实例化过程。我们现在就可以使用 GPU,这个简易操作让使用 NN API 加速并在 Android 11 上执行更多操作变得非常容易。 + +```kotlin +private val options = Model.Options.Builder().setDevice(Model.Device.GPU).build() +private val rpsModel = rpsModel.newInstance(ctx, options) +``` + +## 一个新的 ML Kit 套件 + +> 我们现在不再需要 Firebase 项目来与 ML Kit 一起使用,虽然说我们依旧可以在 Firebase 中使用它。 + +另一个值得注意的更新是可以通过 [ML Kit](https://g.co/mlkit) 使用 TensorFlow Lite 模型。而且即使我们不使用 Firebase 项目,我们现在也可以直接使用 ML Kit 了。 + +正如我之前提到的,由于我之前提到的好处,Android 11 中有许多更新集中在设备上的 ML 上。现在,新的 ML Kit 在设备上具有更好的可用性。ML Kit 的[图像分类](https://developers.google.com/ml-kit/vision/image-labeling/custom-models/android)和[对象检测和跟踪(ODT)](https://developers.google.com/ml-kit/vision/object-detection/custom-models/android)现在也支持自定义模型,这意味着我们可以使用 `tflite` 模型文件走遍 Android 的 ML 了。这也意味着如果我们正在处理某些常见场景,例如对特定类型的对象检测,那么 ML Kit 是最好的选择。 + +**使用 ML Kit** + +让我们在代码中看看如何做到这一点~我们现在将要建立一个可以对不同食品分类的模型, + +```kotlin +private localModel = LocalModel.Builder() + .setAssetFilePath("lite-model_aiy_vision_classifier_food_V1_1.tflite"). + .build() +``` + +在这里我将首先通过设置模型并为其指定 `tflite` 模型文件路径开始。 + +```kotlin +private val customObjectDetectorOptions = CustomObjectDetectorOptions + .Builder(localModel) + .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE) + .setClassificationConfidenceThreshold(0.8f) + .build() +``` + +然后,此 `tflite` 模型将在带有 ML Kit 的对象检测模型的顶部运行。我们现在可以稍微自定义这些选项。在这里,由于要使用流输入并指定置信度阈值,因此我专门设置了 `STREAM_MODE`。 + +```kotlin +private val objectDetector = ObjectDetection.getClient(customObjectDetectorOptions) objectDetector.process(image) + .addOnFailureListener(Log.d(...)) + + .addOnSuccessListener{ + graphicsOverlay.clear() + for (detectedObject in it){ + graphicsOverlay.add(ObjectGraphic(graphicsOverlay, detectedObject)) + } + graphicsOverlay.postInvalidate()} + + .addOnCompleteListenerl imageProxy.close() } +``` + +让我们进入运行模型的那一部分,这样我们可能会看到一些类似于此处前面示例的语法。我将处理我的图像,这里需要注意的是,所有处于失败或成功状态的侦听器都是必不可缺的代码,在我们的每次运行上都需要附加上这些侦听器。这就是我们所有需要编写的代码!我们已经搞定了!🚀~ + +## 查找模型 + +我们讨论了很多有关模型制作后的内容,让我们看看如何为您的用例找到模型。 + +* TF Lite Model Maker + +TensorFlow 团队也于 2020 年初开启了 TF Lite Model Maker。这使得制作好的模型超级容易使用,具有很高的性能,还可以进行大量的自定义。我们现在可以简单地传递数据并使用很少的代码来构建 `tflite` 模型。我们可以查看官网中的 [TensorFlow Lite Model Maker 示例](https://github.com/Rishit-dagli/ML-with-Android-11/blob/dev/TensorFlow_Lite_Model_Maker_example.ipynb)。 + +* TensorFlow Hub + +TensorFlow Hub 是一个开放源代码存储库,其中包含最新技术和有据可查的模型。我们使用 ML Kit 构建的食品分类应用程序也出现在 TF Hub 上。我们还可以使用[社区 tfhub.dev](https://tfhub.dev/) 中的模型。 + +![tfhub.dev 上的一些发布者](https://cdn-images-1.medium.com/max/2022/0*cv-fzgw2WPuf4PQI.png) + +![TF Hub 中的过滤器](https://cdn-images-1.medium.com/max/2000/1*Cu-XiVrzOi2MdKatQ1dpzw.png) + +如果你只想查找基于图像或文本的模型,则可以在 TF Hub 中通过添加过滤条件来搜索。例如如果我们要在网络、终端设备或 Corals 上运行 ML,请通过架构、使用的数据集等筛选等等。 + +我们可以进一步直接从 TF Hub 下载这些模型,也可以非常轻松地使用您自己的数据对这些模型进行迁移学习。但是,在本文中我们将不进一步介绍使用 TF Hub 的迁移学习了。有关 TF Hub 的更多信息,请前往[我的博客](https://towardsdatascience.com/building-better-ai-apps-with-tf-hub-88716b302265)查看。 + +除此之外,还有不少的服务提供商,例如 [Teachable Machine](https://teachablemachine.withgoogle.com/),[AutoML](https://cloud.google.com/automl),但上述的都算是比较常见的提供商。 + +--- + +[GitHub 仓库](https://github.com/Rishit-dagli/ML-with-Android-11) 中提供了此处展示的所有有关 TF Lite Model Maker 的示例的代码。我还为您你供了一些已训练的模型,供初学者入门和实验。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/messengers-like-imageview.md b/article/2021/messengers-like-imageview.md new file mode 100644 index 00000000000..ad94ed0b885 --- /dev/null +++ b/article/2021/messengers-like-imageview.md @@ -0,0 +1,525 @@ +> * 原文地址:[Messengers-like ImageView](https://proandroiddev.com/messengers-like-imageview-90e9f1da19f4) +> * 原文作者:[Michael Spitsin](https://medium.com/@programmerr47) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/messengers-like-imageview.md](https://github.com/xitu/gold-miner/blob/master/article/2021/messengers-like-imageview.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[HumanBeing](https://github.com/HumanBeingXenon)、[keepmovingljzy](https://github.com/keepmovingljzy) + +# 构建像 `Messenger` 短信软件那样的 ImageView + +![](https://cdn-images-1.medium.com/max/2372/1*eUsCLT2MWPgMMc_7ltldOw.png) + +在上一篇论述中,我们讨论了[发送图片消息时候的上传动画以及构建这个动画的方法](https://proandroiddev.com/telegram-like-uploading-animation-e284f1404f63)。今天我决定写一篇与图片的显示有关的文章。先来提个问题,在消息历史记录中,我们应该如何显示图片? + +当然是使用 `ImageView` 啦!好的这篇文章到此结束啦! + +嘿,别走!虽说我们可以使用 ImageView 简简单单就能呈现图片信息,但要做到像 Messenger 应用那样显示图片并非像我们想象中那么简单。虽说本质上难度并不大,但是,我们所需要的不仅是一个 `ImageView`,还要一些小计算,以查看尺寸是否适合我们要向用户展示的内容。 + +## 测量 + +首先我们需要了解我们应该要做什么。我们解决方案的核心是,我们要基于某些图片或动图,或任何其他可显示媒体的预定义大小(宽度和高度),在考虑显示图片的容器的尺寸限制(例如我们可能需要把尺寸为 1000x1000 的图片缩小以适合尺寸只有 100x100 的容器),而且应该在大多数情况下保持长宽比的情况下绘制图片。 + +也就是说基本步骤可以分为两部分: + +1. 依据容器尺寸界定最佳的尺寸并将其提供给程序程序。如果图像太小,我们需要将其调整直到其最短的边的长度等于容器最短的边长。 +2. 给予其与容器一些约束条件(例如使用 `maxSize` 控制大小)。并且如果可能的话,我们应该就长宽比来计算得出最终的大小(稍后我们将讨论其他可能的情况) + +### 定义尺寸 + +让我们从一个简单的 `Size` 类的定义开始。它将包含图像的 `width` 和 `height`,并且向它添加对我们计算有帮助的方法: + +```Kotlin +internal class Size( + var width: Int, + var height: Int +) { + val area: Int get() = width * height + val ratio: Float get() = height.toFloat() / width + + operator fun contains(other: Size) = width >= other.width && height >= other.height + + fun update(new: Size) { + width = new.width + height = new.height + } + + // 这里不希望让 mutable class 变成 data class + fun copy(width: Int = this.width, height: Int = this.height) = Size(width, height) +} +``` + +这里有几点说明: + +1. 我们之所以把这个类定义为可变类,是因为它将在视图内使用,并且我们希望优化实例的创建 —— 因为我们的程序是在一个线程中工作的,我们不希望也不需要因为创造它而浪费大量资源。 +2. 我们其实可以将 `Size` 类本身视作数据类而不是自定义一个 `copy` 函数,但是我不想将可变性与数据类搭上边,因为数据类本应是不可变的。 + +我们现在定义好了 `Size` 类,可以接着创建一个 `ImageSizeMeasurer` 类,负责尺寸的定义、调整和测量。 + +### 设置所需的尺寸 + +首先我们将设置图片所需的尺寸以及最小尺寸。在这个方法中,我们将检查所需大小是否小于最小值,如果是则对其进行依次调整: + +```Kotlin +internal class ImageSizeMeasurer { + private var minSize: Size = Size(0, 0) + + private var desiredSize = Size(0, 0) + val desired get() = desiredSize.copy() + + // = (height/width) + var fixRatio: Float = 1f + private set + + // ... + + fun setDesiredSize(desired: Size, min: Size) { + minSize = min.copy() + + desiredSize = desired.copy() + fixRatio = desired.ratio + + adjustDesiredHeight() + adjustDesiredWidth() + } + + private fun adjustDesiredHeight() { + if (desiredSize.height < minSize.height) { + desiredSize.height = minSize.height + desiredSize.width = (minSize.height / fixRatio).toInt() + } + } + + private fun adjustDesiredWidth() { + if (desiredSize.width < minSize.width) { + desiredSize.width = minSize.width + desiredSize.height = (minSize.width * fixRatio).toInt() + } + } +} +``` + +此处我们使用了 `copy` 方法以避免数据被客户端操作修改的时候影响到。`copy` 方法让这些数据可以暗地里在不同地方之间共享(因此我们就不会因为字段不知道什么时候被更改而震惊)。 + +这里的关键点在于设置大小和比例后,我们需要对其进行调整。不必担忧调用 `adjustDesiredHeight` 和 `adjustDesiredWidth` 方法时没有进行任何智能检查会造成任何严重后果。因为第一个方法在 `height` 小于 `width` 的情况下会把 `desiredSize` 中处于最小值的高度增加到 `minSize`,第二个函数在 `width` 小于 `height` 的情况下会把 `desiredSize` 处在最小值的宽度增加到 `minSize`。 + +#### 分别测量约束条件 + +我们调整好了期望尺寸的最小尺寸,现在该测量实际尺寸的最大尺寸的了。该方法本身并不难,我们只需要记住,应该保证所有的更新不改变高宽比,除非降低图像的高度和宽度会导致两者之一小于 `minSize`。 + +比如说,应用于非常窄的图片。 + +![](https://github.com/PassionPenguin/gold-miner-images/blob/master/messengers-like-imageview-example.png?raw=true) + +* 要么宽度符合最大限值,但高度太小 +* 要么高度达到最小限值,但宽度过大 +* 要么将宽度设置为最大限值,高度设置为最小限值,但这个做法破坏了宽高比。 + +在那种情况下,最后一个选项是最合适的选择,因为我们不能让图像大小超过约束尺寸,并且我们也不希望图像太窄,因为过于小的图片可能会让我们很难看清图片的内容,或与之交互。在这里我们可以使用 `scaleType = imageCrop`:它能帮助你在打破图片显示的宽高比的情况下正确地显示图片。 + +```Kotlin +internal class ImageSizeMeasurer { + private var minSize: Size = Size(0, 0) + + var desiredSize = Size(0, 0) + get() = field.copy() + private set + + // 放缩因子: `height` : `width` + var fixRatio: Float = 1f + private set + + // ... + + fun measure(max: Size, out: Size) { + when { + desiredSize in max -> out.update(desiredSize) + fixRatio < max.ratio -> { + out.width = max.width + out.height = max((max.width * desiredSize.height) / desiredSize.width, minSize.height) + } + fixRatio > max.ratio -> { + out.width = max((max.height * desiredSize.width) / desiredSize.height, minSize.width) + out.height = max.height + } + else -> out.update(max) + } + } + + // ... 或者在这里设置需要的尺寸 +} +``` + +让我们快速分析该 `measure` 方法。 + +* 当所需大小适合最大大小时,一切正常。`setDesiredSize` 确定尺寸之后,我们将确保尺寸不小于最小尺寸。现在,我们只需要确保它不大于最大大小。因此,我们将返回它本身(`when` 代码块中的第一个条件句) +* 如果以上预测错误,则说明要么宽度大于 `max.width` ,要么高度大于 `max.height` ,要么两者都超了。在这种情况下,图片的长宽比将与最大尺寸的长宽比相同,则我们可以输出最大尺寸,因为它将缩小为所需尺寸的结果。(`when` 代码块中的 `else` 语句) +* 在另一种情况下,我们只需要比较宽高比。例如 `width` 的期望尺寸大于最大尺寸。但是期望尺寸的宽高比也大于最大尺寸的长宽比。意味着,当我们缩小期望尺寸时(因此当前尺寸的 `width` 将会和最大尺寸的相等),期望尺寸的 `height` 仍然大于最大尺寸的 `height`。 +因此,当期望尺寸的宽高比小于最大尺寸的长宽比时,我们只需将 `width` 更新为 `max.width`,然后高度也会相应地更新。但是如果小于 `minSize.height` ,我们将打破结果的宽高比,并把 `out.height` 设置为 `minSize.height`。 +* 类似地,如果期望尺寸的宽高比大于最大尺寸的宽高比,我们只需要将 `height` 更新为 `max.height`,宽度也相应地更新。但是,如果小于 `minSize.width` 我们将打破结果的宽高比,并且将 `out.width` 设置为 `minSize.width`。 + +## 所有计算中都带有一点魔术,使一切变得更自然,更漂亮 + +现在,我们准备好要衡量的所有内容: + +```Kotlin +private val measurer: ImageSizeMeasurer +private val measureResult = Size(0, 0) +private val maxSize = Size(0, 0) + +// ... + +override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { + setMeasuredDimension(measurer.desired.width, measurer.desired.height) + } else { + measure(widthMeasureSpec, heightMeasureSpec) + } +} + +private fun measure(widthSpec: Int, heightSpec: Int) { + maxSize.width = // 你可以在这里定义最大的尺寸:可以使用两个输入的尺寸,也可以使用硬编码的 + maxSize.height = // 宽高比并且只使用其中一个输入的尺寸,随你选择 :) + measurer.measure(maxSize, measureResult) + setMeasuredDimension(measureResult.width, measureResult.height) +} +``` + +这里的一切都足够简单。如果我们有未指明的尺寸,我们会告诉视图的父控件在理想状况下的期望尺寸。在另一种情况下(大多数情况下),我们需要提供 `width` 与 `height` 来设置 `maxSize`,并将它们传递进入我们的 `measurer`。 + +现在让我们看一下结果: + +![](https://cdn-images-1.medium.com/max/2000/1*lTedeH88K2J4Z8snpeSOfw.png) + +一切看起来都很棒,但是那些比较小图片似乎显示得太小了。我们希望让它们比现在的更大一些。你可能会说,“那就增大最小尺寸呗。”我们当然可以这样做,但是在那种情况下,小图和更小尺寸的图片之间的显示上的大小不会有任何区别,因为它们将使用一个相同的最小尺寸定义。 + +除此之外,我们可以施加点魔法! + +而魔法的主要目的是通过增加一些幻数或公式使小图变大,并保持小图和更微小的图之间的大小差异:) + +```Kotlin +fun measure(max: Size, out: Size) { + val desired = desiredSize.copy() + magicallyStretchTooSmallSize(max, desired) + + // ... +} + +private fun magicallyStretchTooSmallSize(max: ChatImageView.Size, desired: ChatImageView.Size) { + if (desired in max) { + // 如果图像小于最大尺寸,我们可以将图片尽可能往容器的边缘靠拢 + // 这是有意而为,目的是告诉用户他正在发送小图, + // 调整后的图片不会变得太小,我们仅仅只需要用魔法调整一下就可以让图片变得更加漂亮了。 + val adjustedArea = desired.area + (max.area - desired.area) / 3f + val outW = sqrt(adjustedArea / fixRatio) + desired.height = (outW * fixRatio).toInt() + desired.width = outW.toInt() + } +} +``` + +这个算法思路很简短:将期望面积增加到最大和期望面积之差的 1/3,然后通过新的面积和宽高比计算得出新的宽度和高度。 + + +这是一个比较结果。 + +![**Left:** without magic, **Right:** with magic](https://cdn-images-1.medium.com/max/2996/1*-pTHSTbjjPZlveMdtuTaeQ.gif) + +我更喜欢新的结果:我们能够拥有更大的图片,能更方便地看清图片内容。但在同时,我们又能够理解图片的尺寸有所差异,有的图片比较大有的比较小。 + +## 如果我只知道比例就想要获取尺寸,该怎么办 + +让我们再进一步讨论一下能否有更多的改进吧。有时,我们并没有所要展示的图片的真实尺寸,而只获得了缩略图的尺寸。在这种情况下,我们不能缩略图的尺寸当作是所需的尺寸,因为这些规格要小得多,但是我们可以计算出比例是大了,小了还是完全相等,然后使用 `ImageSizeMeasurer` 对象,在只有固定宽高比得情况下,尝试计算得出所需尺寸并让这个尺寸尽可能满足最大约束。 + +因此,首先,我们向 `Size` 类添加一个新属性: + +``` +val isSpecified: Boolean get() = width > 0 && height > 0 +``` + +接下来,我们需要添加方法以设置所需的比率而不是所需的大小: + +``` +fun setDesiredRatio(ratio: Float, min: Size) { + minSize = min.copy() + desiredSize = Size(0, 0) + fixRatio = ratio +} +``` + +然后,我们需要通过添加其他调整到所需的大小来更新 `measure` 方法: + +```Kotlin +fun measure(max: ChatImageView.Size, out: ChatImageView.Size) { + val desired = desiredSize.copy() + fixUnspecifiedDesiredSize(max, desired) + magicallyStretchTooSmallSize(max, desired) + + // ... +} + +// 没有指定所需的大小,但指定了宽高比,那么先将图片最大化伸展。 +private fun fixUnspecifiedDesiredSize(max: ChatImageView.Size, desired: ChatImageView.Size) { + if (!desired.isSpecified) { + if (fixRatio > max.ratio) { + desired.width = max.width + desired.height = (max.width * fixRatio).toInt() + } else { + desired.width = (max.height / fixRatio).toInt() + desired.height = max.height + } + } +} +``` + +最后,让我们更新 `onMeasure` 方法: + +```Kotlin +override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (measurer.desired.isSpecified) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { + setMeasuredDimension(measurer.desired.width, measurer.desired.height) + } else { + measure(widthMeasureSpec) + } + } else if (measurer.fixRatio > 0) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } else { + measure(widthMeasureSpec) + } + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } +} + +private fun measure(widthSpec: Int) { + maxSize.width = // 我们可以同时使用两个规格或具有一些预定义的 + maxSize.height = // 同时使用宽高或仅使用其中之一来定义最大尺寸,任君挑选;) + measurer.measure(maxSize, measureResult) + setMeasuredDimension(measureResult.width, measureResult.height) +} +``` + +## 让我们一起讨论一下视图 + +到现在为止一切表现得还挺好。我们拥有了一个绝妙的图片尺寸计算工具!我们甚至对如何将其与视图整合都有一个粗略的了解,但是我们仍然没有思路如何表现。 + +让我们首先描述一下我们想要什么。实际上,指定 `minWidth` 和 `minHeight` 并不难。这些属性是 xml 的一部分,`maxWidth` 和 `maxHeight` 也如此。但是我不想在这里硬编码任何特定的大小。相反,我想更多地依靠设备屏幕。意思是,最好用百分比来指定这些最大约束。我们现在已经拥有了 `ConstraintLayout` 控件,按理说像这样指定最大宽度(例如屏幕宽度的 70%)并不难...但是高度应该怎么办? + +其实你可以任意指定约束比例,毕竟这只是我的一点想法罢了。出于某些原因,我决定根据宽度决定高度,乘以缩放因子。因此,假设我们的 `factor` 值为 `1`,那便就是一个正方形。也就是说,只需指定 `width`(以及比例),程序就能计算对应的高度。 + +如你所见,做法极其简单,但也极度依赖屏幕尺寸,而不是取决于设备的不同因素的 dimens.xml 中的各种定义,尽管后者的解决方案是安卓化的: + +```Kotlin +open class FixRatioImageView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : AppCompatImageView(context, attrs, defStyleAttr) { + var factor = DEFAULT_FACTOR + set(value) { + if (field != value) { + field = value + requestLayout() + } + } + + init { + attrs?.parseAttrs(context, R.styleable.FixRatioImageView) { + factor = getFloat(R.styleable.FixRatioImageView_factor, DEFAULT_FACTOR) + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val width = View.getDefaultSize(suggestedMinimumWidth, widthMeasureSpec) + setMeasuredDimension(width, ceil(width * factor).toInt()) + } + + companion object { + private const val DEFAULT_FACTOR = .6f + } +} +``` + +## 合并所有代码! + +让我们看看最终的代码: + +```Kotlin +class ChatImageView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FixRatioImageView(context, attrs, defStyleAttr) { + + private val measurer = ImageSizeMeasurer() + private val measureResult = Size(0, 0) + private val maxSize = Size(0, 0) + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (measurer.desired.isSpecified) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { + setMeasuredDimension(measurer.desired.width, measurer.desired.height) + } else { + measure(widthMeasureSpec) + } + } else if (measurer.fixRatio > 0) { + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } else { + measure(widthMeasureSpec) + } + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + } + + private fun measure(widthSpec: Int) { + maxSize.width = MeasureSpec.getSize(widthSpec) + maxSize.height = (maxSize.width * factor).toInt() + measurer.measure(maxSize, measureResult) + setMeasuredDimension(measureResult.width, measureResult.height) + } + + fun setDesiredSize(width: Int, height: Int) { + measurer.setDesiredSize(Size(width, height), Size(minimumWidth, minimumHeight)) + invalidate() + requestLayout() + } + + fun setDesiredRatio(ratio: Float) { + measurer.setDesiredRatio(ratio, Size(minimumWidth, minimumHeight)) + invalidate() + requestLayout() + } + + internal class ImageSizeMeasurer { + private var minSize: Size = Size(0, 0) + + private var desiredSize = Size(0, 0) + val desired get() = desiredSize.copy() + + // 缩放因子 height : width + var fixRatio: Float = 1f + private set + + init { reset() } + + // 我们依赖客户端的 MATCH_PARENT 的设置以获取宽度 + // 并且不创建新的 Size + fun measure(max: Size, out: Size) { + val desired = desiredSize.copy() + fixUnspecifiedDesiredSize(max, desired) + magicallyStretchTooSmallSize(max, desired) + + when { + desired in max -> out.update(desired) + fixRatio < max.ratio -> { + out.width = max.width + out.height = max((max.width * desired.height) / desired.width, minSize.height) + } + fixRatio > max.ratio -> { + out.width = max((max.height * desired.width) / desired.height, minSize.width) + out.height = max.height + } + else -> out.update(max) + } + } + + // 如果没有指定期望尺寸,但指定了缩放因数,那么先将图像最大程度地伸展 + private fun fixUnspecifiedDesiredSize(max: Size, desired: Size) { + if (!desired.isSpecified) { + if (fixRatio > max.ratio) { + desired.width = max.width + desired.height = (max.width * fixRatio).toInt() + } else { + desired.width = (max.height / fixRatio).toInt() + desired.height = max.height + } + } + } + + @Suppress("MagicNumber") + private fun magicallyStretchTooSmallSize(max: Size, desired: Size) { + if (desired in max) { + // 如果图像比最大界限小,我们就把这张图额外拉伸一点儿至边界值 + // 这是有意这么做的,因为如果我们要发送小图像,图像不应该太小。 + // 因此,它只是某种调整魔法,让图片看起来更靓 ;) + val adjustedArea = desired.area + (max.area - desired.area) / 3f + val outW = sqrt(adjustedArea / fixRatio) + desired.height = (outW * fixRatio).toInt() + desired.width = outW.toInt() + } + } + + fun setDesiredRatio(ratio: Float, min: Size) { + reset() + minSize = min.copy() + fixRatio = ratio + } + + fun setDesiredSize(desired: Size, min: Size) { + minSize = min.copy() + + if (!desired.isSpecified) { + reset() + } else { + desiredSize = desired.copy() + fixRatio = desired.ratio + + adjustDesiredHeight() + adjustDesiredWidth() + } + } + + private fun adjustDesiredHeight() { + if (desiredSize.height < minSize.height) { + desiredSize.height = minSize.height + desiredSize.width = (minSize.height / fixRatio).toInt() + } + } + + private fun adjustDesiredWidth() { + if (desiredSize.width < minSize.width) { + desiredSize.width = minSize.width + desiredSize.height = (minSize.width * fixRatio).toInt() + } + } + + private fun reset() { + desiredSize = Size(0, 0) + fixRatio = 1f + } + } + + internal class Size( + var width: Int, + var height: Int + ) { + val area: Int get() = width * height + val ratio: Float get() = height.toFloat() / width + val isSpecified: Boolean get() = width > 0 && height > 0 + + operator fun contains(other: Size) = width >= other.width && height >= other.height + + fun update(new: Size) { + width = new.width + height = new.height + } + + // 不想使可变类成为数据类 + fun copy(width: Int = this.width, height: Int = this.height) = Size(width, height) + } +} +``` + +我们的努力所换来的完美的运行结果: + +![](https://cdn-images-1.medium.com/max/2000/1*gSYcSTxF0jS3NbpbAR0MXQ.gif) + +## 后记 + +如果你喜欢这篇文章,别忘记点赞或一键三连来支持我们。如果你有任何的疑问,请在评论区留言,让我们可以一起讨论!祝你编程快乐! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/monads-for-javascript-developers.md b/article/2021/monads-for-javascript-developers.md new file mode 100644 index 00000000000..50f89507047 --- /dev/null +++ b/article/2021/monads-for-javascript-developers.md @@ -0,0 +1,167 @@ +> * 原文地址:[Monads For JavaScript Developers](https://js.plainenglish.io/monads-for-javascript-developers-af29819823c) +> * 原文作者:[MelkorNemesis](https://medium.com/@melkornemesis) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/monads-for-javascript-developers.md](https://github.com/xitu/gold-miner/blob/master/article/2021/monads-for-javascript-developers.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[ZavierTang](https://github.com/ZavierTang) + +# 面向 JavaScript 开发人员的 Monads + +![](https://cdn-images-1.medium.com/max/5760/1*gA2dHvfpZEylFTBuiLiKxw.jpeg) + +和别的程序员一样,我也很想知道 **Monads** 到底是什么。但每当我在网上搜索 Monads 的时候,都只会找到大量的 Monads 理论范畴文章,而其它的资源似乎也并没有什么参考意义。 + +为了搞清楚什么是 Monads,我花费了大量的时间精力。我开始去学习 Haskell,但在学了几个月后,我才突然意识到,大家都在 Monads 上面太小题大做了。如果你是一名 JavaScript 开发人员,那么你肯定每天都在使用它,只是你并没有意识到而已。 + +--- + +本文并不会提及太多有关 Monads 的理论范畴或 Haskell 的细节,但有一件事我们始终需要知道 —— 当我们在互联网上搜索 Monads 时,不能错过这个定义: + +``` +(>>=) :: m a -> (a -> m b) -> m b +``` + +这是 Haskell 中 `bind` 运算符的定义。不同的语言对这个操作有不同的叫法,但意思都是一样的。比如一些替代名称是 `chain`、`bind`、`flatMap`、`then`、`andThen`。 + +## Monadic 上下文 + +``` +(>>=) :: m a -> (a -> m b) -> m b + +m :: monadic 上下文 +a, b :: 上下文的值 (string, number, ..) +``` + +**Monadic 上下文(Monadic Context)** 只是一个盒子,它实现了使该盒子成为一个 Monad 所需的全部功能。一个很简单的(非 Monadic)盒子可能是这样的: + +```js +const Box = val => ({ val }); +const foo = Box("John"); +``` + +这是一个只包装了值的盒子,该盒子没有任何功能,因为它没有任何方法实现。 + +> **要使某个东西成为一个 Monad,你必须使其表现得像一个 Monad。** + +接着让我们回到 `(>>=) :: m a -> (a -> m b) -> m b`。`(>>=)` 用作 `m a >>= (a -> m b)` 的中缀运算符,而 `(>>=)` 运算的结果是 `m b`。 + +## 存在的问题 + +你有没有注意到我们有 `m a`,但是函数以 `a` 为参数?这就是 Monads 的意义所在。 + +`(>>=)` 操作是在 Monadic 上下文 `m a` 中取一个值展开它,所以我们只得到 `a`,再将其传递给函数 `(a -> m b)`。这并不奇怪,你还要自己制定这种行为准则,我们稍后会介绍。 + +## JavaScript 的 Promises + +JavaScript 中的 Promises 类似于 Monads,更确切地说,他们都有 Monad 式(**Monad-ish**)行为。要成为 Monad,它还必须实现一个仿函数(**Functor**)和应用程序接口(**Applicative**)。我提这一点只是为了表述完整,但我们不会更深入地讨论这些。 + +JavaScript 的 **Promises** 使用 `.then()` 方法实现 Monadic 接口。我们来看以下示例: + +```js +// p :: m a :: Promise { 42 } +const p = Promise.resolve(42); +``` + +这通常会创建一个箱子,在 **Promise** 中有一个值为 `42`。 +☝️ 这是我们的 `m a`。 + +接着我们有一个将数字除以二的函数,输入的内容没有包装在 **Promise** 中,但是返回的函数包装在 **Promise** 中。 + +```js +// divideByTwo :: (a -> m b) +const divideByTwo = val => Promise.resolve(val / 2); +``` + +☝️ 这就是我们的 `(a -> m b)`。 + +再次注意,我们在 **Promise** 中有一个值 `42`,但是函数 `divideByTwo` 接受一个未包装的值,并且我们仍然可以链接这些。 + +```js +// p :: m a :: Promise { 42 } +const p = Promise.resolve(42); +// p2 :: m a :: Promise { 21 } +const p2 = p.then(divideByTwo); +// p3 :: m a :: Promise { 10.5 } +const p3 = p2.then(divideByTwo); +``` + +或者更明显的是: + +```js +// p :: m a :: Promise { 10.5 } +const p4 = p.then(divideByTwo).then(divideByTwo); +``` + +**这是 Monads 最重要的特性。** + +箱子中有一个值 —— `Promise { 42 }`,你有一个采用展开值 `42` 的函数。`m a` 与 `a` 的类型不匹配,你仍然可以将该函数应用于封装的值。 + +**那怎么可能呢?** + +这是因为 **Promise** 实现 `then` 方法并以这种方式工作。大多数时候,在 **Promise** 中运行的代码是异步的。但是 **Promise** 的单步行为使得它可以链接一系列函数。 + +Monads 抽象出辅助数据管理、控制流或函数副作用(**side-effects**),将可能复杂的函数序列转换成简明的管道。 + +## 自定义 Monad 式类 + +我使用 TypeScript 整理了一个非常简单的 Monad 式类例子,它不产生任何函数副作用,并且允许链接函数。 + +```ts +class Dummy { + constructor(private val: T) {} + + chain(fn: (value: T) => Dummy): Dummy { + return fn(this.val); + } + + static unit(val: T): Dummy { + return new Dummy(val); + } +} + +const d = new Dummy(41); +d.chain(val => new Dummy(val + 1)) + .chain(val => new Dummy("The answer is: " + val)); +``` + +## Monad 规则 + +具有 Monad 特性的类必须遵循一些规则。 + +* 左单位元 +* 右单位元 +* 可结合性 + +你可以在网上查找更多有关信息。在这里放一段代码,以证明 Dummy 类遵循这些规则。 + +```js +const m = Dummy.unit(1); +const f = (val: number) => new Dummy(val + 1); +const g = (val: number) => new Dummy(val + 2); + +// 1. 左单位元 +Dummy.unit(1).chain(f) ==== f(1) + +// 2. 右单位元 +m.chain(Dummy.unit) ==== m + +// 3. 可结合性 +const m1 = Dummy.unit(1); +m.chain(f).chain(g) ==== m.chain(val => f(val).chain(g) +``` + +`==` 或 `===` 在这里不起作用,因为对象引用是不同的。为此,我使用不存在的 `====`,但可以理解为 Monad 式类的对象的内部值。 + +## 本文总结 + +我希望本文能使你了解 Monads,如果你是 JavaScript 开发人员,则每天都会使用它们。例如将 **Promise** 中装箱的值提供给需要未包装值的函数,并再次返回包装在 **Promise** 中的新值。 + +## 参考资料 + +* [https://en.wikipedia.org/wiki/Monad_(functional_programming)](https://en.wikipedia.org/wiki/Monad_(functional_programming)) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/native-splash-screen-in-flutter-using-lottie.md b/article/2021/native-splash-screen-in-flutter-using-lottie.md new file mode 100644 index 00000000000..eea5e3c12d6 --- /dev/null +++ b/article/2021/native-splash-screen-in-flutter-using-lottie.md @@ -0,0 +1,287 @@ +> * 原文地址:[Native Splash Screen in Flutter Using Lottie](https://medium.com/swlh/native-splash-screen-in-flutter-using-lottie-121ce2b9b0a4) +> * 原文作者:[AbedElaziz Shehadeh](https://medium.com/@elaziz-shehadeh) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/native-splash-screen-in-flutter-using-lottie.md](https://github.com/xitu/gold-miner/blob/master/article/2021/native-splash-screen-in-flutter-using-lottie.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[keepmovingljzy](https://github.com/keepmovingljzy) + +# 在 Flutter 项目中使用 Lottie 构建原生 Splash 启动页 + +![](https://cdn-images-1.medium.com/max/2400/1*4vlkTJCWbP2Kh2vyK9BdEw.png) + +我们当然可以直接使用 Dart 代码为 Flutter 应用程序添加动画启动效果,但是,Flutter 应用程序在 Android 和 iOS 中以 FlutterActivity 或 FlutterViewController 的形式启动,会让 Flutter 应用程序在实际绘制第一帧之前已经耗费了一段时间。因此,在应用启动时设置启动画面将会带来更好的用户体验。 + +值得一提的是,在 Flutter 的官方[文档](https://flutter.dev/docs/development/ui/advanced/splash-screen)中我们可以轻松地将静态图像添加为启动页,并且这个页面上面有充足的文档信息提供给我们使用。我们事实上只需将图像添加到 Android 的 drawable 文件夹中和 iOS 的资源文件夹中,然后在 Android 的 `styles.xml` 和 iOS 的 `LaunchScreen.storyboard` 中使用它们即可。但是,在针对如何使用 Lottie 等其他库实现应用程序启动页面动画的功能,我并不能找到相关的参考资料,而这些就是我将在本文中讲述的内容。 + +## 为什么我们要使用 Lottie? + +[Lottie](https://airbnb.io/lottie/#/) 是一个支持多平台(包括 Android 与 iOS)的库,用于通过 [Bodymovin](https://github.com/airbnb/lottie-web) 解析 [Adobe After Effects](http://www.adobe.com/products/aftereffects.html) 导出的 JSON 格式的动画,并以本地方式呈现。这意味着动画是由专业的设计人员设计的,并使用的是 **JSON** 文件导出,让我们开发人员无需再额外付出什么努力,轻轻松松完成动画的渲染。在本教程中,我们将使用由 LottieFiles 创建的免费示例文件,可以在[这里](https://lottiefiles.com/38237-thanksgiving-cornucopia)中找到该原文件。让我们开始我们的 Flutter + Lottie 之旅吧。 + +首先让我们先创建一个新的 Flutter 项目,然后执行以下步骤: + +## Android + +1. 先添加 Lottie 依赖到你的项目的 `app/build.gradle` 文件中(相对于 Flutter 应用程序则是 `android/app/build.gradle` 文件)(在这里我也同样添加了 Constraint Layout) + +```groovy +dependencies { + ... + implementation "com.airbnb.android:lottie:3.5.0" # 当前版本 3.6.0 + implementation "androidx.constraintlayout:constraintlayout:2.0.4" + # 译者注:原文为 implementation "com.android.support.constraint:constraint-layout:2.0.4" 但 Lottie 2.8+ 只支持 AndroidX 项目 + ... +} +``` + +2. 在 `AndroidManifest.xml` 中删去 `name` 为 io.flutter.embedding.android.SplashScreenDrawable 的 `` 标记并替换 `activity` 标签下面的 `LaunchTheme` 为 `NormalTheme`,现在你的文件是这样的: + +```xml + + + + + + + + + + + + + + + +``` + +你可以在 `/android/app/res/values/styles.xml` 文件夹中删除 `LaunchTheme` 的定义,因为你将不再需要它。 + +3. 在 `/android/app/res/values` 文件夹下创建一个 `raw` 目录,并复制生成的 `.json` 文件(无论你是创建自己的文件还是从上面的链接下载了免费示例)。 在本案例中,JSON 文件夹的名字应该是 `splash_screen.json`。 + +4. 为了使用 `.json` 文件并显示动画视图,我们需要创建具有其布局的启动视图类。 在 `/android/app/res` 下,创建一个名为 `layout` 的新目录(如果不存在的话),然后创建一个名为 `splash_view.xml` 的新的布局资源文件。 打开这个 XML 文件,修改文件的代码为: + +```xml + + + + + + +``` + +在这个示例中,我将动画设置为自动播放,设置的播放速度为 `1.0`,并且禁止循环播放功能。你可以根据需要使用不同的值。 最重要的部分是 `app:lottie_rawRes` 属性,它定义了我们要使用在 `raw` 目录中添加的 JSON 文件。现在,我们需要创建启动视图的类。让我们在 `/android/app/src/main/kotlin/YOUR-PACKAGE-NAME` 中来创建一个新的 Kotlin 类。将这个类命名为 `SplashView`,然后修改它的内容为: + +```kotlin +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import io.flutter.embedding.android.SplashScreen + +class SplashView : SplashScreen { + override fun createSplashView(context: Context, savedInstanceState: Bundle?): View? = + LayoutInflater.from(context).inflate(R.layout.splash_view, null, false) + + override fun transitionToFlutter(onTransitionComplete: Runnable) { + onTransitionComplete.run() + } +} +``` + +如你所见,此视图 Inflate 了 `splash_view` 布局文件。最后一步是告诉 `MainActivity` 我们的自定义启动视图。 + +5.转到 `/android/app/src/main/kotlin/YOUR-PACKAGE-NAME` 文件夹,然后单击 `MainActivity.kt`。 `FlutterActivity` 提供了一种称为 `provideSplashScreen` 的方法,修改代码为: + +```kotlin +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.android.SplashScreen + +class MainActivity: FlutterActivity() { + + override fun provideSplashScreen(): SplashScreen? = SplashView() +} +``` + +现在项目的目录应该像这样: + +![Android 项目目录](https://cdn-images-1.medium.com/max/2000/1*kj2sZaD-YWBgNaEXYAwqbg.png) + +这就是 Android 下 Lottie 构建 Splash 启动页的方法,只需要跑一下这个应用程序然后你就能够看到应用程序启动时候的动画了。 + +![Android 中使用了动画的 Splash 页面](https://cdn-images-1.medium.com/max/2000/1*EDVg6zpUrwJ39ppvlN7nTA.gif) + +## iOS + +让我们在 iOS 中添加启动页: + +1. 打开项目所在的目录,单击 ios 文件夹,然后双击 `Runner.xcworkspace` 打开你的项目。 + +2.单击 `Main.storyboard`,你将看到带有一个屏幕的布局编辑器。 我们需要添加一个新的 `ViewController`,这将是我们的启动页(你可以通过单击右上角的 `+` 号来做到这一点。点击之后,屏幕中将弹出一个窗口。我们在输入框处输入 View Controller 搜索并将这个控件拖动到编辑器中即可),如以下屏幕快照所示: + +![添加一个新的 View Controller](https://cdn-images-1.medium.com/max/7108/1*L9EKQQFnxtozE_xgcpVkfw.png) + +3. 完成了第二步之后,你会看到两个屏幕。选择新的 View Controller 然后点击 `attributes inspector`,然后再点击 `is initial view controller` . + +![设置 Splash View Controller 为起始的 View Controller](https://cdn-images-1.medium.com/max/3826/1*TzWohD3MyARxjm7Vetmzow.png) + +4. 我们需要在 `ios/Podfile` 文件中添加 Lottie 依赖; + +```text +pod 'lottie-ios' +``` + +这个文件中现在应该是这样的:(编者注:可能你已经修改了一部分设置了,这里只是一个案例) + +```shell +#platform :ios, '9.0' + +target 'Runner' do + use_frameworks! + + pod 'lottie-ios' + +end +``` + +然后运行这个应用程序(确保命令行当前在 ios 目录中。如果不是,那么就使用 `cd` 命令将你的目录移动到 ios 目录中) + +```shell +pod install +``` + +5. 使用 Xcode 将你的生成的 `.json` 文件拖到中的根目录中(请选择 `Copy items if needed` 选项),这个文件可能是你自己创建的文件,也有可能是你从上面的链接下载了免费样本。在本案例中它的名字是 `splash_screen.json`。 + +6.在已经添加了依赖项和 `splash_screen.json` 文件的情况下,我们可以创建我们的初始视图控制器,该控制器将处理显示的动画。打开你的 ios 项目,在项目根目录处(相对于 Flutter 根目录:/ios/Runner)创建一个新的名为 `SplashViewController` 的 Swift 文件。在类中编写任何内容之前,我们先来修改一下 `AppDelegate.swift` 以创建 `FlutterEngine`。 如果你跳过了这个步骤,则动画启动画面的动画播放完了以后不能跳转至 `FlutterViewController`。 + +```swift +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + + lazy var flutterEngine = FlutterEngine(name: "MyApp") + + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + // Runs the default Dart entrypoint with a default Flutter route. + flutterEngine.run() + // Used to connect plugins (only if you have plugins with iOS platform code). + GeneratedPluginRegistrant.register(with: self.flutterEngine) + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} +``` + +在这里我们创建了一个名为 `MyApp` 的 `FlutterEngine`(你可以自己决定它的名称),然后在 `application` 的 `didFinishLaunchingWithOptions` 中运行了这个引擎并在引擎中注册了插件。需要注意的是默认代码是 `GeneratePluginRegistrant.register(with:self)`,请确保它已向 `self.flutterEngine` 注册。 + +7. 做完了这些,现在我们可以准备 `SplashViewController` 以显示动画。导航到 `Flutter` 的 View Controller 处,修改代码为: + +```swift +import UIKit +import Lottie + +public class SplashViewController: UIViewController { + + private var animationView: AnimationView? + + public override func viewDidAppear(_ animated: Bool) { + animationView = .init(name: "splash_screen") + animationView!.frame = view.bounds + animationView!.contentMode = .scaleAspectFit + animationView!.loopMode = .playOnce + animationView!.animationSpeed = 1.00 + view.addSubview(animationView!) + animationView!.play{ (finished) in + self.startFlutterApp() + } + } + + func startFlutterApp() { + let appDelegate = UIApplication.shared.delegate as! AppDelegate + let flutterEngine = appDelegate.flutterEngine + let flutterViewController = + FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil) + + flutterViewController.modalPresentationStyle = .custom + flutterViewController.modalTransitionStyle = .crossDissolve + + present(flutterViewController, animated: true, completion: nil) + + } +} +``` + +在 `viewDidAppear` 中,我们使用添加的 `splash_screen.json` 文件初始化动画视图。你可以修改诸如 `loopMode`、`animationSpeed` 等播放设置。在动画播放结束后,我们将启动我们的 Flutter 应用程序。 + +为了获取 `FlutterViewController`,我们必须获取我们创建并在 `AppDelegate.swift` 运行的 `FlutterEngine` 的实例。 + +``` +let appDelegate = UIApplication.shared.delegate as! AppDelegate +let flutterEngine = appDelegate.flutterEngine + +let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil) +``` + +然后使用 `present(completion :)` 启动视图控制器。 + +8. 现在是时候将第 2 步创建的 `ViewController` 与 `SplashViewController` 类相链接了。单击 `Main.storyboard` 并选择新的 `ViewController`,然后从 `identity inspector` 中选择 `SplashViewController`,如屏幕快照所示: + +![链接到 `SplashViewController`](https://cdn-images-1.medium.com/max/7152/1*ghXXOoQqELmNTc4wrbxoJQ.png) + +9. 最后一步是设置 `Main.storyboard` 的主界面,替换掉 `LauncherScreen.storyboard`。单击 Runner,选择 `General` 选项卡,在 `deployment info` 下,从下拉菜单中将 `Main interface` 设置为 **Main**,如屏幕快照所示: + +![设置 Main interface 为 Main](https://cdn-images-1.medium.com/max/3274/1*KQV8lIB3aRfA_AHtTNXi4g.png) + +生成并运行该应用程序,你应该能够看到动画的启动页了: + +![](https://cdn-images-1.medium.com/max/2000/1*bdfeeBtOIHW_1A0MfdjnZQ.gif) + +就是这样,你现在已经生成了针对 Android 和 iOS 应用程序的动画启动页。有关完整的源代码和演示应用程序可以在这里获取到: + +[**AbedElazizShe/flutter_lottie_splash_app**](https://github.com/AbedElazizShe/flutter_lottie_splash_app) + +如果你有任何疑问,或者有更好的方法可以解决此问题,请记得发表评论嗷。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/new-features-chrome-88.md b/article/2021/new-features-chrome-88.md new file mode 100644 index 00000000000..8b9a3ba15e1 --- /dev/null +++ b/article/2021/new-features-chrome-88.md @@ -0,0 +1,51 @@ +> * 原文地址:[New Features in Chrome 88 Devtools](https://www.infoq.com/news/2021/03/new-features-chrome-88/?topicPageSponsorship=eb89fa44-b190-43ef-87d0-4bc8727e7413) +> * 原文作者:[Guy Nesher](https://www.infoq.com/profile/Guy-Nesher/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/new-features-chrome-88.md](https://github.com/xitu/gold-miner/blob/master/article/2021/new-features-chrome-88.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Chorer](https://github.com/Chorer) + +# Chrome 88 DevTools 中的新功能 + +最近发布的 Chrome 88 对 Chrome DevTools 进行了重大更新,包括改进的网络调试、实验性的 CSS Flexbox 调试工具、改进的框架详细信息视图、新的 WASM 调试功能以及总体性能上的提高。 + +网络选项卡提供了三种旨在简化调试过程的新功能: + +1. 现在,我们可以通过右键单击特定请求并选择`复制值`(`Copy value`),直接从`网络`(`Network`)选项卡中复制请求属性。 +2. 现在可以通过选择`复制堆栈跟踪`(`Copy stack trace`)选项,从单个网络请求中复制网络启动器的堆栈跟踪。 +3. 现在可以在网络视图上正确地标记 [**C**ross-**O**rigin-**R**esource-**S**haring 的错误](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS/Errors)。 + +[CSS Flexbox](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox) 是一种功能强大的设计工具,但由于它在两个轴上进行操作,因此通常很难调试。为了简化调试过程,Chrome 提供了两个新标志。第一个标志出现在元素层次结构视图上,并标记了带有 *`display:flex`* 的元素。 + +第二个标志是上下文敏感的对齐指示符,该指示符基于以下 `flexbox` 属性: + +* `flex-direction` +* `align-items` +* `align-content` +* `align-self` +* `justify-items` +* `justify-content` + +同时也会顾及到基于以下属性的方向: + +* `flex-direction` +* `direction` +* `writing-mode` + +要使用 Flexbox 的调试,开发人员需要在“设置”>“实验”标签下启用它。 + +![](https://res.infoq.com/news/2021/03/new-features-chrome-88/en/resources/113-flex-debugging-1614281700033.png) + +Chrome 88 Devtools 还提供了改进的框架详细信息视图,其中包括有关跨域隔离信息状态的额外信息、有关框架 Web Worker 的专用信息,以及发现哪个框架触发了另一个窗口打开的功能。 + +Chrome 88 还使 [Wasm](https://developer.mozilla.org/zh-CN/docs/WebAssembly) 调试与现有的 JavaScript 调试功能保持一致。在打断点暂停代码执行时,开发人员可以将鼠标悬停在变量上以查看其当前值,或在控制台中对其进行计算。 + +最后,从 JavaScript 编译速度的角度来说,由于减少了启动过程中的序列化、解析和反序列化所带来的性能开销,DevTools 现在的启动速度提高了近 40%。 + +Chrome DevTools 提供了丰富的实用程序集以调试 Web 应用,并且用于大多数基于 Chromium 的浏览器中。Chrome 开发团队将继续改进 DevTools,并在每次发布新版本的 Chrome 时都提供新功能。开发者可以在 [Google 开发者网站](https://developers.google.com/web/updates/tags/devtools)上跟进最新功能,并在[邮件列表](https://groups.google.com/forum/#!forum/google-chrome-developer-tools)中讨论可能出现的功能、更新和漏洞。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/nginx-concepts-i-wish-i-knew-years-ago.md b/article/2021/nginx-concepts-i-wish-i-knew-years-ago.md new file mode 100644 index 00000000000..11396daf1fb --- /dev/null +++ b/article/2021/nginx-concepts-i-wish-i-knew-years-ago.md @@ -0,0 +1,312 @@ +> * 原文地址:[Nginx concepts I wish I knew years ago](https://dev.to/aemiej/nginx-concepts-i-wish-i-knew-years-ago-23o0) +> * 原文作者:[Aemie Jariwala](https://dev.to/aemiej) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/nginx-concepts-i-wish-i-knew-years-ago.md](https://github.com/xitu/gold-miner/blob/master/article/2021/nginx-concepts-i-wish-i-knew-years-ago.md) +> * 译者:[joyking7](https://github.com/joyking7) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[ningzhy3](https://github.com/ningzhy3) + +![路由器](https://res.cloudinary.com/practicaldev/image/fetch/s--B8sTzGjW--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/jldvigb958mnww2rvcvx.jpeg) + +# 我希望多年前就知道的 Nginx 概念 +*Nginx 是一个遵循主从架构的 Web 服务器,可以用作反向代理、负载均衡器、邮件代理和 HTTP 缓存。* + +哇!复杂的术语和混乱的定义,里面充斥着大量令人困惑的词语,对吧?不用担心,我可以帮大家先了解 Nginx 的基本架构和术语,然后我们将安装并创建 **Nginx** 配置。 + +![迷惑表情.gif](https://res.cloudinary.com/practicaldev/image/fetch/s--mxz4Qgrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fbj8exwkli91ord2xscz.gif) + +为了让事情变简单,只需要记住:*Nginx 是一个神奇的 Web 服务器*。 + +简单来说,Web 服务器就像个中间人。比如你想访问 dev.to,输入地址 `https://dev.to`,你的浏览器就会找出 `https://dev.to` 的 Web 服务器地址,然后将其定向到后台服务器,后台服务器会把响应返回给客户端。 + +## 代理 vs 反向代理 + +Nginx 的基本功能是代理,所以现在就需要了解什么是代理和反向代理。 + +### 代理 + +好的,我们有一个或多个客户端、一个中间 Web 服务器(在这种情况下,我们称它为代理)和一个服务器。这其中最主要的事情是服务器不知道哪个客户端正在请求。是不是有点困惑?让我用一张示意图来解释一下。 + +![代理示意图](https://res.cloudinary.com/practicaldev/image/fetch/s--tPAqn11I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1moanfdnfnh5d0dqs4wd.png) + +在这种情况下,客户端 client1 和 client2 通过代理服务器向服务器发送请求 request1 和 request2,后台服务器不会知道 request1 是由 client1 还是 client2 发送的,只会执行操作。 + +### 反向代理 + +用最简单的话来说,反向代理就是把代理的工作反过来。比方说有一个客户端、一个中间 Web 服务器和一个或多个后台服务器。让我们继续通过一张示意图解释吧! + +![反向代理示意图](https://res.cloudinary.com/practicaldev/image/fetch/s--iUfM34yx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/64jk21oeqlki2t3bx1kz.png) + +在这种情况下,客户端将通过 Web 服务器发送一个请求,Web 服务器会通过一种算法将请求定向到众多服务器的任意一个,其中一种算法是轮询调度(Round-Robin)(最可爱的一个!),然后再将响应通过 Web 服务器返回给客户端。因此在这里,客户端并不知道与之交互的是哪一个后台服务器。 + +## 负载均衡 + +可恶,又是一个新词,但是这个词比较容易理解,因为它是**反向代理**本身的一个实际应用。 + +我们先说说基本的区别。在负载均衡中,必须要有两个或者更多的后台服务器,但在反向代理设置中,这不是必须的,它甚至可以只跟单台后台服务器一起使用。 + +让我们从幕后看一下,如果我们有大量来自客户端的请求,这个负载均衡器会检查每个后台服务器的状态并分配请求的负载,然后将响应更快地发送给客户端。 + +## 有状态应用 vs 无状态应用 + +好的各位,我保证我很快就要讲到 Nginx 代码了,先让我们把所有的基本概念搞清楚! + +### 有状态应用 + +这个应用程序存储了一个额外的变量,用于保存只适用于单个服务器实例的信息。 + +![有状态应用图例](https://res.cloudinary.com/practicaldev/image/fetch/s--Ng8XRfi_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bb9kkupl1z9dpacex8vt.png) + +我的意思是,如果后端服务器 *server1* 存储了一些信息,那么它不会被存储在 *server2* 上,因此进行交互的客户端(这里指 Bob)可能得不到想要的结果,因为它可能会与 server1 或者 server2 交互。在这种情况下,server1 将允许 Bob 查看配置文件,但 server2 不会允许。因此,即使有状态应用阻止了许多 API 调用数据库,并且速度更快,但却可能会在不同服务器上导致上述问题。 + +### 无状态应用 + +现在,无状态是对数据库的 API 调用更多,但客户端与不同后台服务器交互时,存在的问题就更少了。。 + +![无状态应用图例](https://res.cloudinary.com/practicaldev/image/fetch/s--42mTsbTP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c44w9vi7jmgfeo9rea1l.png) + +我知道你没有明白我的意思。简单来说,如果我从客户端通过 Web 服务器向比如说后台服务器 *server1* 发送一个请求,它将向客户端提供一个令牌以用于访问其他任何请求。客户端可以使用令牌并将请求发送给 Web 服务器,该 Web 服务器将请求和令牌一起发送给任意后台服务器,每个服务器都将返回相同的期望输出。 + +## 什么是 Nginx? + +Nginx 就是 Web 服务器,到目前为止,我一直在整篇博客中使用 Web 服务器这个词,老实说,它就像一个*中间人*。 + +![Nginx示意图](https://res.cloudinary.com/practicaldev/image/fetch/s--Z6CIUUND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2u3l8t4klwflv8k36rtg.png) + +这张图并不难懂,它只是结合了我到现在为止解释的所有概念。在这张图中,我们有 3 台分别运行在 3001、3002、3003 端口的后台服务器,这些后台服务器共同使用运行在 5432 端口的数据库。 + +现在,当客户端向 `https://localhost`(默认 443 端口)发送请求 `GET /employees` 时,Nginx 将根据算法把这个请求发送给任意一个后台服务器,后台服务器从数据库中获取信息,然后把 JSON 结果发送回 Nginx Web 服务器,Nginx 再发送回客户端。 + +如果我们要使用诸如**轮询调度**这样的算法,Nginx 会这样做:比如 client2 发送了一个请求到 `https://localhost`,那么 Nginx 服务器会先把请求传到 3001 端口,然后把响应返回给客户端。对于另一个请求,Nginx 会把请求传到 3002 端口,以此类推。 + +这也太多概念了吧!但是到此为止,你应该已经清楚地了解了什么是 Nginx 及其相关术语。现在,我们将继续了解 Nginx 的安装和配置。 + +## 安装过程 + +终于到这一步了!如果你能理解 Nginx 概念并看到了代码这部分,那真是棒棒哒! + +![十分感动.gif](https://res.cloudinary.com/practicaldev/image/fetch/s--7rgP-NQB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4mju73ad1f22gy1ni3gu.gif) + +好的,老实说,在任何操作系统上安装 Nginx 都只需要一行命令。我是 Mac OSX 用户,所以会基于它来写命令。但对于 [Ubuntu](https://ubuntu.com/tutorials/install-and-configure-nginx#2-installing-nginx) 和 [Windows](https://www.maketecheasier.com/install-nginx-server-windows/) 以及其他 Linux 发行版,也有类似的命令。 + +``` +$ brew install Nginx +``` + +只需要一行命令,你的系统就已经安装上 Nginx 了!非常 Amazing! + +### 运行 So easy!😛 + +运行下面的命令来检查 Nginx 是否在你的系统上运行起来了,又是非常简单的一步。 + +``` +$ nginx +# OR +$ sudo nginx +``` + +运行完命令之后,使用你最喜欢的浏览器访问 `http://localhost:8080/`,你将在屏幕上看到下面的画面! + +![Nginx网页](https://res.cloudinary.com/practicaldev/image/fetch/s--q4OAcvwJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9mlhwlzgqhs6l8aw8sxi.png) + +### 基本配置和示例 + +好的,我们将通过一个示例来展示 Nginx 的神奇之处。首先,在本地机器上创建如下的目录结构: + +``` +. +├── nginx-demo +│ ├── content +│ │ ├── first.txt +│ │ ├── index.html +│ │ └── index.md +│ └── main +│ └── index.html +└── temp-nginx + └── outsider + └── index.html +``` + +同时,在 **html** 和 **md** 文件中写上基本的上下文内容。 + +### 我们要达到什么效果? + +在这里,我们有两个单独的文件夹 `nginx-demo` 和 `temp-nginx`,每个文件夹都包含静态 HTML 文件。我们将专注于在一个共同端口上运行这两个文件夹,并设置我们喜欢的规则。 + +现在回到正轨。我们可以通过修改位于 `/usr/local/etc/nginx` (译者注:默认安装路径)路径下的 `nginx.conf` 文件,实现对 Nginx 默认配置的任何改动。另外,我的系统中有 Vim,所以我将用 Vim 进行修改,你也可以自由使用所选的编辑器。 + +``` +$ cd /usr/local/etc/nginx +$ vim nginx.conf +``` + +这将打开一个默认的 Nginx 配置文件,但我真的不想使用它的默认配置。因此,我通常会复制这个配置文件,然后对原文件进行修改。在这里我们也这样做。 + +``` +$ cp nginx.conf copy-nginx.conf +$ rm nginx.conf && vim nginx.conf +``` + +现在打开一个空文件,我们将给它添加我们的配置。 + +1. 添加一个基本配置。添加 `events {}` 是必须的,因为对于 Nginx 架构来讲,它通常被用来表示 Worker 的数量。我们在这里使用 `http` 来告诉 Nginx,我们将使用 [OSI 模型](https://bit.ly/2LGdbYB) 的第 7 层。 + + 在这里,我们让 Nginx 监听 5000 端口,并指向 `/nginx-demo/main` 文件夹下的静态文件。 + + ``` + http { + + server { + listen 5000; + root /path/to/nginx-demo/main/; + } + + } + + events {} + ``` + +2. 接下来我们将对 `/content` 和 `/outsider` URL 添加额外的规则,其中 **outsider** 将指向第一步中提到的根目录(`/nginx-demo`)以外的目录。 + + 这里 `location /content` 表示无论我在子目录中定义了哪一个根目录,**content** 子 URL 都会被添加到定义的根目录末尾。因此,这里当我指定根目录为 `root /path/to/nginx-demo/` 时,仅仅表示我告诉 Nginx 在 `http://localhost:5000/path/to/nginx-demo/content/` 向我展示文件夹内静态文件的内容。 + + ``` + http { + + server { + listen 5000; + root /path/to/nginx-demo/main/; + + location /content { + root /path/to/nginx-demo/; + } + + location /outsider { + root /path/temp-nginx/; + } + } + + } + + events {} + ``` + + > 好酷!现在 Nginx 不仅限于定义根 URL,还可以设置规则,以便于我可以阻止客户端访问某些文件。 + +3. 我们将在定义的主服务器中写入一条附加规则,用来阻止访问任何 **.md** 文件。我们可以在 Nginx 中使用正则表达式,规则定义如下: + + ``` + location ~ .md { + return 403; + } + ``` + +4. 最后我们来学习一下流行的命令 `proxy_pass`。现在我们已经了解了什么是代理和反向代理,这里我们先定义另一个运行在 8888 端口的后台服务器,所以现在我们已经有了 2 个分别运行在 5000 和 8888 端口的后台服务器。 + + 我们要做的是,当客户端通过 Nginx 访问 8888 端口时,将这个请求传到 5000 端口,并向客户端返回响应! + + ``` + server { + listen 8888; + + location / { + proxy_pass http://localhost:5000/; + } + + location /new { + proxy_pass http://localhost:5000/outsider/; + } + } + ``` + +### 最后一起来看看完整的代码!😁 + +``` + http { + + server { + listen 5000; + root /path/to/nginx-demo/main/; + + location /content { + root /path/to/nginx-demo/; + } + + location /outsider { + root /path/temp-nginx/; + } + + location ~ .md { + return 403; + } + } + + server { + listen 8888; + + location / { + proxy_pass http://localhost:5000/; + } + + location /new { + proxy_pass http://localhost:5000/outsider/; + } + } + + } + + events {} +``` + +通过 `sudo nginx` 来运行代码。 + +## 额外的 Nginx 命令! + +1. 首次启动 Nginx Web 服务器。 + + ``` + $ nginx + #OR + $ sudo nginx + ``` + +2. 重新加载正在运行的 Nginx Web 服务器。 + + ``` + $ nginx -s reload + #OR + $ sudo nginx -s reload + ``` + +3. 关闭正在运行的 Nginx Web 服务器。 + + ``` + $ nginx -s stop + #OR + $ sudo nginx -s stop + ``` + +4. 查找有哪些 Nginx 进程正在系统中运行 + + ``` + $ ps -ef | grep Nginx + ``` + +第 4 条命令很重要,当前 3 条命令出现错误时,可以使用第 4 条命令找到所有正在运行的 Nginx 进程,然后 kill 掉这些进程,重新启动 Nginx 服务。 + +要 kill 一个进程,你需要先知道它的 PID,然后用下面的命令 kill 它: + +``` +$ kill -9 +#OR +$ sudo kill -9 +``` + +在结束这篇文章之前,声明一下我所使用图片和视觉效果来自 Goole 图片和由 [Hussein Nasser](https://www.youtube.com/user/GISIGeometry) 提供的 Youtube 教程。 + +关于 Nginx 的基本认识和配置,我们就讲到这里。如果你对 Nginx 的进阶配置感兴趣,请通过评论告诉我。在此之前,请享受编程的乐趣,探索 Nginx 的魔力!👋 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/programmatically-generate-images-with-css-painting-api.md b/article/2021/programmatically-generate-images-with-css-painting-api.md new file mode 100644 index 00000000000..168d0a9aab3 --- /dev/null +++ b/article/2021/programmatically-generate-images-with-css-painting-api.md @@ -0,0 +1,242 @@ +> * 原文地址:[Programmatically generate images with CSS Painting API](https://blog.bitsrc.io/programmatically-generate-images-with-css-painting-api-3b1a860dae3b) +> * 原文作者:[Viduni Wickramarachchi](https://medium.com/@viduniwickramarachchi) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/programmatically-generate-images-with-css-painting-api.md](https://github.com/xitu/gold-miner/blob/master/article/2021/programmatically-generate-images-with-css-painting-api.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[lsvih](https://github.com/lsvih) + +# 使用 CSS Painting API 自动生成图像 + +![Banner](https://cdn-images-1.medium.com/max/5760/1*wKYGWd-7eWgpmMeBNiLCDA.jpeg) + +图像为应用程序增添色彩,丰富内容。然而,如果网页中嵌入了大量高分辨率图像,会大量增加页面资源加载时间,严重影响用户体验。对于展示产品、方案等必须内容的图像,我们别无选择,只能按照正常方式嵌入这些图像并通过缓存它们来优化应用程序。但是,如果我们在应用程序中需要几何图像,则不必再将其作为资源来加载。 + +> 我们可以使用 CSS Painting API 即时生成几何图像。 + +让我们一起来走进这个 API,并且学习如何使用它生成图像吧~ + +## CSS Painting API 的简介 + +开发者们能够使用 [CSS Painting API](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API) 使用编写的 JavaScript 函数将图像绘制到 CSS 属性中,例如 `background-image`和 `border`。它提供了一组 API,使开发人员可以访问 CSSOM,CSS Houdini([Houdini](https://github.com/w3c/css-houdini-drafts))的一部分 —— 新浏览器 API 的集合,为开发人员提供了对 CSS 本身的更底层的访问方法。) + +嵌入图像的传统方法如下。 + +```css +div { + background-image: url('assets/background.jpg'); +} +``` + +而如果使用 CSS Painting API,我们只需要调用 `paint()` 函数,并且传入一个 JavaScript 声明好的 Worklet: + +```css +div { + background-image: paint(background); +} +``` + +这串代码的工作逻辑是这样的: + +![](https://cdn-images-1.medium.com/max/2000/1*c2EShrISdnmcxc87qJdKPg.png) + +在上文中似乎存在着一些晦涩难懂的术语。例如,我们提及了 `worklet`? + +简而言之,让程序自动生成图像的 JavaScript 代码称为 Paint Worklet。[Worklet](https://www.w3.org/TR/worklets-1/#intro) 是浏览器渲染管道的一个扩展。除了 Paint Worklet 之外,还有其他类型的 Worklet,例如 Animation Worklet 和 Layout Worklet。 + +现在,让我们看一下程序生成图像的分步方法。 + +## 在实践中使用 CSS Painting API + +在本文中,我们将会探讨如何创建一个气泡背景 + +#### 第一步:添加 CSS paint() 函数 + +在开始这一切之前,我们需要往所需要添加图片的 CSS 属性中添加 `paint()` 函数。 + +```css +.bubble-background { + width: 400px; + height: 400px; + background-image: paint(bubble); +} +``` + +`bubble` 就是我们等下生成图片的 Worklet,而要生成 Worklet,仅仅只需要短短几步。 + +#### 第二步:定义 Worklet + +Worklet 需要在外部 JavaScript 文件中被保存,而 Painting Worklet 应该是一个 `class`,例如 `class Bubble { …… }`,然后这个 Worklet 需要使用 `registerPaint()` 函数注册。 + +```js +class Bubble { + paint(context, canvas, properties) { + /* TODO: ... */ + } +} + +registerPaint('bubble', Bubble); +``` + +`registerPaint()` 函数的第一个参数是我们向在 CSS 中使用的参考名。 + +现在就让我们来绘制背景吧! + +```js +class Bubble { + paint(context, canvas, properties) { + const circleSize = 10; + const bodyWidth = canvas.width; + const bodyHeight = canvas.height; + + const maxX = Math.floor(bodyWidth / circleSize); + const maxY = Math.floor(bodyHeight / circleSize); + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + context.fillStyle = '#eee'; + context.beginPath(); + context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true); + context.closePath(); + context.fill(); + } + } + } +} + +registerPaint('bubble', Bubble); +``` + +创建图像的运算是在 `paint()` 函数的内部进行的。我们将需要一些有关 Canvas 的知识来绘制上述图像。如果不熟悉,我们其实可以看一下 [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial) 文档。 + +#### 第三步:调用 Worklet + +最后一步是在 HTML 文件中调用 Worklet。 + +```html + +
+ + +``` + +这就好啦! + +你现在已经在三步之内用程序自动生成一张图片啦! + +## 生成的图片 + +我们所编写的的代码的运行效果应该是这样的: + +![[在编辑器中查看](https://codepen.io/viduni94/pen/jOMgpNX)](https://cdn-images-1.medium.com/max/2448/1*vvLIdPpqWdRWswddJ9CgUw.png) + +## 我们还可以用 CSS Painting API 干些什么呢? + +The power of the CSS Painting API is not over yet. There are more things you can do with it. + +#### 1. 我们可以创建动图 + +例如,我们可以动态更改气泡的颜色,而 CSS 变量就是服务此目的的。为了使用 CSS 变量,浏览器应该先明白我们在使用它。我们可以使用 `inputProperties()` 函数来做到这一点。 + +```js +registerPaint('bubble', class { + static get inputProperties() { + return ['--bubble-size', '--bubble-color']; + } + + paint() { + /* ... */ + } +}); +``` + +变量们可以通过第三个参数传给 `paint()` 方法 + +```js +paint(context, canvas, properties) +{ + const circleSize = parseInt(properties.get('--bubble-size').toString()); + const circleColor = properties.get('--bubble-color').toString(); + const bodyWidth = canvas.width; + const bodyHeight = canvas.height; + + const maxX = Math.floor(bodyWidth / circleSize); + const maxY = Math.floor(bodyHeight / circleSize); + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + context.fillStyle = circleColor; + context.beginPath(); + context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true); + context.closePath(); + context.fill(); + } + } +} +``` + +#### 2. 我们可以使用 `Math.random()` 在 `paint()` 函数中生成随机的图片 + +```css +body { + width: 200px; + height: 200px; + background-image: paint(random); +} +``` + +```javascript +function getRandomHexColor() { + return '#' + Math.floor(Math.random() * 16777215).toString(16) +} + +class Random { + paint(context, canvas) { + const color1 = getRandomHexColor(); + const color2 = getRandomHexColor(); + + const gradient = context.createLinearGradient(0, 0, canvas.width, 0); + gradient.addColorStop(0, color1); + gradient.addColorStop(1, color2); + + context.fillStyle = gradient; + context.fillRect(0, 0, canvas.width, canvas.height); + } +} + +registerPaint('random', Random); +``` + +如果你在如何做到这些上存在疑惑,请在评论区中提出你的问题。 + +这个真是太棒啦! + +但是,好事总有糟糕的一面,这个 API 现在仅仅只被部分浏览器所有限制的支持。 + +## 浏览器支持 + +![数据源:[Can I Use](https://caniuse.com/css-paint-api)](https://github.com/PassionPenguin/gold-miner-images/blob/master/programmatically-generate-images-with-css-painting-api-caniuse.com_css-paint-api.png?raw=true) + +包括 Firefox 在内的大多数浏览器都不支持 CSS Painting API。到目前为止,只有基于 Chromium 的浏览器完全支持此功能,真希望不久的将来浏览器支持会有所改善。 + +## 摘要 + +CSS Painting API 对于减少网络请求的响应时间非常有用,因为图片是程序化生成而非获取网络数据得到的。 + +最重要的是,我认为主要的好处如下。 + +* 能够创建完全可定制的图像,而不是静态图像。 +* 它创建与分辨率无关的图像(让我们的站点上不再有质量差的图像)。 + +需要注意的重要一点是,我们可以使用 `polyfill` 等库作为解决方案来支持尚未实现 CSS Painting API 的 Firefox 等浏览器。 + +--- + +如果你对本文有任何疑问或想法,请在评论区告诉我们!感谢你的阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/python-lists-and-tuples.md b/article/2021/python-lists-and-tuples.md new file mode 100644 index 00000000000..14b497a382a --- /dev/null +++ b/article/2021/python-lists-and-tuples.md @@ -0,0 +1,104 @@ +> * 原文地址:[Lists and Tuples in Python](https://medium.com/python-in-plain-english/python-lists-and-tuples-760d45ebeaa8) +> * 原文作者:[Mayur Jain](https://medium.com/@mayur-ds) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/python-lists-and-tuples.md](https://github.com/xitu/gold-miner/blob/master/article/2021/python-lists-and-tuples.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[lsvih](https://github.com/lsvih) + +# Python 中的列表和元组 + +要编写一个高效的程序,我们需要了解两件事事:**首先是程序的输入内容是什么,其次是我们应该如何选择最合适的数据结构来处理该输入。** + +在这篇博文中,我们将会在与 **dict**、**set** 等其他数据结构的比较中了解数据结构 **List** 和 **Tuple** 以及它可以有效处理的输入内容。 + +列表和元组属于一类称为**数组**的数据结构。数组是元素的集合,而这些元素的顺序或位置与元素本身一样重要。因为定义数组时我们给定了位置或索引,所以找到元素需要的时间复杂度为 O(1)。 + +> 列表是一个动态数组,我们可以在其中修改和调整存储在其中的数据的大小。 +> 元组是一个静态数组,其元素是固定且不可变的。元组由 Python 运行时缓存,这意味着我们不需要在每次我们需要使用一个元组的时候 Python 不需要与内核对话来获得保留这个元组的内存。 + +在计算机系统中,存储器是一系列编号的分配存储块,每个分配存储块都可以容纳一个数字。Python 通过引用将数据存储在这些分配存储块中。这意味着数字本身只是指向或引用了我们实际关心的数据。 + +![**一个存储了长度为 6 的数组系统内存布局**](https://cdn-images-1.medium.com/max/2664/1*r3B7WgUsBJeYQmExYERwig.png) + +当创建列表或元组时,我们需要分配一个系统存储块,该块的每个部分都使用整数指针进行引用。为了查找列表中的任何特定元素,我们应该知道分配存储块的编号和所需的元素。 + +例如,假设我们有一个从**分配存储块编号** **S** 开始的数组,要找到该数组中的第 5 个元素,我们可以直接搜索分配存储块编号 **S + 5** ,同样类推到数组中的 i 元素。但是,如果分配存储块编号不适用于给定的数组,那么我们需要在整个数组中执行元素搜索,时间复杂度会随着数组大小的增加而增加。此搜索也称为**线性搜索**。最坏的情况是 O(n),其中 n 是列表中元素的总数。如果列表已排序,则可以使用其他有效的搜索算法来搜索数组中的元素如二分法。 + +为了进行搜索和排序,Python 内置了 **__eq__**、**__lt__** 等比较方法,并且 Python 中的列表内置有 TimSort 的内置排序算法,而它的最佳情况是 O(n),最坏的情况是 O(nlog n)。 + +排序完成后,我们可以进行二分法,一个平均复杂度为 O(log n) 的排序方法。它是通过查看列表的中间并将此值与所需值进行比较来实现查找的。如果中点的值小于我们的期望值,程序就会去比较列表的右半部分,然后继续像这样将列表不断缩小,直到找到该值或知道该值不会出现在已排序列表中为止。我们不需要像线性搜索那样需要读取列表中的所有值。相反,我们仅读取其中的一小部分。 + +注意:我们可以使用 Python 标准库中的 **bisect** 模块,该模块可以将元素添加到列表中、并保持排序顺序。 + +**LISTS 列表** + +List 是一个动态数组,所以它可以使用调整大小操作,且它也支持动态更改。 + +如果有一个大小为 N 的列表 A,如果将新项目附加到列表 A,则 Python 会创建一个足够容纳 N 个元素以及更多元素的新列表。即,Python 中的列表的创建,不是分配能够容纳 N + 1 个元素的数组,而是分配能够容纳 M 个元素( M > N )的数组。当 Python 复制旧列表到新列表的时候,它会随即删除或销毁旧列表。我们建议在首次分配时请求额外的空间,以减少后续分配的次数 —— 出于内存复制的消耗系统资源之大,列表元素的增加会严重影响程序运行速度。 + +**List 的分配方程** + +```python +M = (N >> 3) + (3 if N < 9 else 6) +``` + +![列表的 "过度" 分配](https://cdn-images-1.medium.com/max/2134/1*mYYlsNHqfxdvdSUUmlSARQ.png) + +该图显示列表尺寸与额外元素的关系。例如,如果使用创建了一个包含 8000 个元素的列表,Python 将返回一个能够容纳大约 8,600 个元素的列表,也就是会多分配 600 个元素的空间! + +![**追加元素对列表理解的记忆和时间的影响**](https://cdn-images-1.medium.com/max/2000/1*Tb-UGxpj6tL93pKUo8EXUg.png) + +当我们构建了一个列表并且添加元素时候,我们使用了 2.7 倍的内存。与创建列表相比,添加元素时候分配给列表的额外空间要大得多。 + +**TUPLES 元组** + +元组是静态的,也就是说,一旦创建了元组,与列表不同,我们再也无法对其进行修改或调整其大小。 + +**特性 1:静态性** + +```python +>>> t = (1, 2, 3, 4) +>>> t[0] = 5 +Traceback (most recent call last): + File "", line 1, in +TypeError: 'tuple' object does not support item assignment +``` + +**特性 2:可连接性** + +```python +>>> t1 = (1, 2, 3, 4) +>>> t2 = (5, 6, 7, 8) +>>> t1 + t2 +(1, 2, 3, 4, 5, 6, 7, 8) +``` + +现在,如果我们考虑将连接操作与列表的 `append` 操作放在一起,一起使用,那么有趣的是,元组连接所花费的时间将会是 O(n),而列表所花费的时间为 O(1)。因为列表是追加元素的,所以列表中只要有多余的空间即可。对于元组,每当将一个新元素连接到现有元组时,它就会在不同的内存位置上创建一个新的元组,从而使连接花费 O(n) 时间(因为对于元组来说没有直接添加元素的方法可用)。 + +元组被认为是轻量的 —— 与列表不同,元组仅占用数据所需的内存。所以说,**如果数据是静态的,我们建议大家去使用元组。** + +使用元组的另一个好处是**资源回收** —— Python 是支持垃圾回收的,这意味着,当我们不再使用某个变量的时候,它将释放其内存,并将其返回给系统,以便将该内存分配给其他应用程序或变量。对于元组,如果不再使用元组空间,Python 会保留它的内存,并且如果将来需要该大小的内存,则 Python 不会去向系统寻求新的内存,而是直接分配自己保留下来的内存 —— 极大程度上避免了向系统再度调用内存块,节省了时间,优化了资源的配置。 + +**List 和 Tuple 的实例** + +```python +>>> %timeit l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +95 ns ± 1.87 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) + +>>> %timeit t = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) +12.5 ns ± 0.199 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each) +``` + +列表和元组都有优点和缺点,但是重要的是要牢记它们的特性 —— 例如列表中的过度分配以及元组中的静态和缓存资源,同时将其用作可能的数据结构。 + +希望你会喜欢阅读本文! + +**参考资料** + +[High Performance Python book](https://www.oreilly.com/library/view/high-performance-python/9781449361747/) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/quick-overview-of-http-requests-cross-origin-resource-sharing-cors.md b/article/2021/quick-overview-of-http-requests-cross-origin-resource-sharing-cors.md new file mode 100644 index 00000000000..e347346d446 --- /dev/null +++ b/article/2021/quick-overview-of-http-requests-cross-origin-resource-sharing-cors.md @@ -0,0 +1,152 @@ +> * 原文地址:[An Overview of HTTP Requests & Cross-Origin Resource Sharing (CORS)](https://medium.com/javascript-in-plain-english/quick-overview-of-http-requests-cross-origin-resource-sharing-cors-db139b41d71) +> * 原文作者:[Bilge Demirkaya](https://medium.com/@bilgedemirkaya) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/quick-overview-of-http-requests-cross-origin-resource-sharing-cors.md](https://github.com/xitu/gold-miner/blob/master/article/2021/quick-overview-of-http-requests-cross-origin-resource-sharing-cors.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[regon-cao](https://github.com/regon-cao) + +# 简述 HTTP 请求与跨域资源共享 CORS + +![图片源自 [Alina Grubnyak](https://unsplash.com/@alinnnaaaa?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/network?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/6912/1*YECeOxlko9KoOJNw8RNm3A.jpeg) + +## URL 简介 + +以下示例 URL 由 4 部分组成: + +![](https://cdn-images-1.medium.com/max/2000/1*HfJAWr4Jw7rIXHSRaG4wcw.png) + +**服务类型(Scheme)** 指明将被使用的协议(Protocol)。**协议**指定数据如何传输以及如何处理请求。当你查看协议时,你就能很好地理解这个 URL 的用途。(例如是带有 SMTP、POP3、IMAP 的电子邮件协议,还是获取和管理 git 仓库的 SSH 请求,或者是针对 Web 的 HTTP 请求。) + +**HTTP** — 默认是在 80 端口运行,它指定请求中的表头。 + +**HTTPS** — 与 **HTTP** 协议类似,但 HTTPS 被认为是浏览器与服务器之间的安全通信。它与 HTTP 不同之处: + +* 默认是在 443 端口运行 +* 加密除 IP 请求之外的所有请求或响应头 + +**主机名(Host name):** + +只是一个更好命名的 IP 地址。 + +**路径(Path):** + +URL 路径就像你的目录路径。它为用户和搜索引擎提供了解当前所在的部分,例如 `/about` 部分。这有助于实现更好的搜索引擎优化(SEO)。 + +**查询参数(Query parameters):** + +它用于将数据发送到服务器。通常出于营销原因使用它来查看广告的效果。以 `?` 开始,用 `&` 分隔数据。 + +> **注意**:由于安全原因,不建议发送带有查询参数的数据(这样每个人都可以看到),并且它有一个字符限制(限制在 2048 个字符以内)。 + +**使用 HTTP 和 HTTPS 协议,我们还有其他方法可以将数据发送到服务器。** + +## 请求与响应 + +![Taken from C0D3.com](https://cdn-images-1.medium.com/max/2000/1*8S-OTIgudIC9wOIbN3VETg.png) + +当用户在浏览器中输入域名时,浏览器会找到该服务器(这只是其他人的计算机)并向该服务器发送请求。如果它从服务器成功获取响应,就会在浏览器上呈现相应的页面。 + +> **注意**:当你使用终端发送请求(例如运行 `node index.js`)时,进程是相同的。向服务器发送请求不一定需要浏览器,也可以使用终端。然而,如果响应是 HTML,那么终端不会做任何事情,因为 HTML 只是浏览器的指令。 + +## 表头部分 + +浏览器和服务器都需要获取对方的大量信息,才能识别对方,并最终发送请求或响应。比如 IP 地址、内容类型(Content-Type)、Cookie、[缓存控制(Cache-Control)](https://en.wikipedia.org/wiki/Cache-Control)等。你可以在这里找到[完整列表](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields),它们带着**表头**数据也就是**键值对**。 + +![Request Headers Example | Taken from C0D3.com](https://cdn-images-1.medium.com/max/2000/1*kJ2ViLP32reDBOfeYHB46Q.png) + +在发送请求时,只需要手动设置两个表头:**内容类型(Content-Type)**和**授权(Authorization)**。虽然你可以设置其它表头,但它们通常由浏览器自动处理。 + +**内容类型(Content-Type)** — 当你通过正文向服务器发送(POST、PATCH、PUT 请求)数据时,你需要指定其内容类型,可以是 `application/json`、`text/html`、`image/gif` 或 `video/mpeg.`。 + +**授权(Authorization)** — 这是服务器用来识别用户的。与 cookie 表头不同,该表头必须由开发人员在发送请求时手动设置。通常用于 API 请求和 JWT 身份验证。 + +## 请求处理 + +通过互联网发送的每个请求包括 2 个必填部分和 1 个可选部分。 + +1. **请求行**:由请求方法(GET、POST、DELETE 等)和路径(从 URL 中提取)组成。 +2. **表头**:上文已经简要说明过。 +3. **请求体**(可选): 向服务器发出 POST、PUT、PATCH 请求时,需要发送一个请求体报文,该报文告诉服务器你想要发送什么数据。示例: + +```js +axios.post(‘/users’, +{id: “5fddfefc4fbd19494493cd71”, name: "username"} // 这部分是请求体 +).then(console.log) +``` + +* **axios** 是一个发送请求的库。浏览器还提供了一个叫做 **fetch** 的函数,可以用来发送请求。另外还有一个用于发送请求的过时请求库。 +* **post** 是请求方法,表明我们正在向服务器发送信息。可以在[这里](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)详细查看 HTTP 请求方法。 +* **`/users`** 是指定你在服务器中发送该请求的确切位置的路径。这个 URL 部分其实叫 API。当一个 API 遵循 **REST** 模式时,它就变成了 **REST API**,让开发人员可以快速理解和使用 API。例如像 REST 模式所说的,**路径**应该总是复数形式。 + +> **REST** 是指表述性状态传递,它是一组设计原则,允许你使用 API 和修改服务器上的资源。 + +* **请求体**是数据对象本身,因此服务器可以获取该数据。 + +如上所述,除了在浏览器中输入域名外,还有多种方法可以将请求发送到服务器。 + +> **AJAX**:从浏览器发送请求。如果有人说了解 ajax,这意味着他知道如何从浏览器发送请求。 + +## 跨域资源共享 + +**OPTIONS** 请求也叫做**预处理请求(pre-flight requests)** + +当前,你看到的响应来自 **medium.com** 服务器。假设我写了一个 JS 代码,当你在网页浏览这个的时候,它正在向我自己的网站服务器发送一个 POST 请求。这称为跨域请求(**Cross-Domain request**)。 + +> **跨域请求(Cross-Domain request)**:发送到与你当前所在 url 主机名不同的 url 请求。 + +例如我想使用 JS 代码从浏览器发送另一个请求到另一个域(另一个服务器),但你会发现这并不容易。出于安全原因,浏览器限制从脚本发起的跨源 HTTP 请求。 + +[同源安全策略](https://en.wikipedia.org/wiki/Same-origin_policy)默认禁止某些`跨域(Cross-Domain)`请求,尤其是 Ajax 请求,而始终允许`相同来源(Same-Origin)`请求。 + +**CORS** 定义了浏览器和服务器可以交互的方式,并确定允许跨域请求是否安全。 + +> **跨域资源共享**([CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS))是基于 HTTP 表头的机制,它允许服务器指出浏览器应该允许加载资源的任何其他[来源](https://developer.mozilla.org/en-US/docs/Glossary/origin)(域、协议或端口)。 + +![Taken from [https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)](https://cdn-images-1.medium.com/max/2000/1*J35DcnM_wbU9b4C5IZvkpQ.png) + +## 跨域请求分析 + +当浏览器发现域是不同的,它会向该服务器发送一个 **OPTIONS** 请求,检查请求是否被允许。这个行为与我们开发人员其实并没有什么关系,因为这是浏览器自动进行的行为。然而开发人员可以在发送跨域请求之前,向请求添加一些表头,这可能有助于获得允许。 + +就像其它浏览器请求一样,表头中的一些数据会提供一些信息。例如,通过 OPTIONS 方法发送的 [Access-Control-Request-Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method) 表头会提供一些信息:真实请求何时到来,数据类型是什么,请求方法是什么等。 + +在这种情况下,服务器可以响应是否接受请求,至于其余部分则取决于服务器。作为响应,服务器可以发回 [Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) 表头,表明资源可以被任何域访问。 + +虽然它允许来自其他域的 GET 请求,但它可能限制 POST 请求。 + +## 跨域请求响应头 + +**Access-Control-Allow-Origin** — 包含允许发送跨域请求的主机名。如果这与用户所在站点的主机名不匹配,则将拒绝跨域请求。 + +**Access-Control-Allow-Credentials** — 如果在响应头中为 true,则跨域请求将包含 Cookie 表头。 + +**Access-Control-Allow-Methods** — 这是一个逗号分隔的字符串,它告诉浏览器跨域请求中允许使用哪种请求方法。如果请求方法未包含在此响应头中,则不会发送请求。 + +使用一段 Node.js 代码设置表头: + +```js +router.options('/api/*', (req, res) => { + res.header('Access-Control-Allow-Credentials', true) + res.header('Access-Control-Allow-Origin', req.headers.origin) + res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, PATCH, DELETE') + res.header( + 'Access-Control-Allow-Headers', + 'Origin, X-Requested-With, Content-Type, Accept, Credentials' + ) + res.send('ok') +}) +``` + +## 总结 + +CORS 标准意味着,服务器开发人员必须处理新的请求和响应头。他们需要用表头来划清界限,这样才能防止安全漏洞。 + +在这篇文章中我尝试着以最简明的方式来介绍这些重要的概念,如果你有任何疑问或想在上述一个特定主题中了解更多信息,请记得告诉我。 + +感谢阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git "a/article/2021/raspberry-pi\342\200\231s-ninth-birthday-9-things-you-might-not-know.md" "b/article/2021/raspberry-pi\342\200\231s-ninth-birthday-9-things-you-might-not-know.md" new file mode 100644 index 00000000000..731c67800e2 --- /dev/null +++ "b/article/2021/raspberry-pi\342\200\231s-ninth-birthday-9-things-you-might-not-know.md" @@ -0,0 +1,92 @@ +> * 原文地址:[Raspberry Pi’s Ninth Birthday: 9 Things You Might Not Know](https://www.tomshardware.com/news/raspberry-pi-9th-birthday) +> * 原文作者:[Avram Piltch]([https://www.tomshardware.com/author/avram-piltch](https://www.tomshardware.com/author/avram-piltch)) +> * 译文出自:[掘金翻译计划]([https://github.com/xitu/gold-miner](https://github.com/xitu/gold-miner)) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/raspberry-pi’s-ninth-birthday-9-things-you-might-not-know.md](https://github.com/xitu/gold-miner/blob/master/article/2021/raspberry-pi’s-ninth-birthday-9-things-you-might-not-know.md) +> * 译者: +> * 校对者: + +# Raspberry Pi’s Ninth Birthday: 9 Things You Might Not Know + +One of the world’s most popular and innovative computers officially launched on February 29, 2012. Nine years and 38 million units sold later, the Raspberry Pi powers a huge community of makers, students and businesses. What started as a small project, meant to increase applications for Cambridge University’s computer science program has become a global movement. + +Every serious tech enthusiast should own at least one Raspberry Pi or, if you’re like me, 30 Raspberry Pis. You can use one as a lightweight PC, a [retro arcade machine](https://www.tomshardware.com/how-to/install-retropie-raspberry-pi-4) or to power a variety of projects, from [home security cameras](https://www.tomshardware.com/how-to/raspberry-pi-security-camera) to [tic-tac-toe-playing robots](https://www.tomshardware.com/news/this-raspberry-pi-robot-plays-tic-tac-toe-so-you-never-play-alone), [self-driving trash cans](https://www.tomshardware.com/news/clean-your-room-with-this-raspberry-pi-trash-delivery-bot) or [streaming media servers](https://www.tomshardware.com/how-to/raspberry-pi-plex-ubuntu). + +In honor of the Raspberry Pi’s ninth birthday, here are 9 key facts about it. + +## 1. Raspberry Pi’s original target was just 1,000 units. + +The Raspberry Pi was originally developed to solve a very limited problem: the decreasing number of people applying to study computer science at Cambridge University. The number of applications had dropped from 600 to 250 per year and Eben Upton, who was the director of studies and responsible for admission, became concerned that not enough kids were taking an interest in computers. By providing a low-cost, hackable computer to just a few kids in the UK, Upton intended to get more and better students for his program. + +## 2. There have been at least 21 Different Models of Raspberry Pi. + +Since its launch in 2012, the Raspberry Pi Foundation has released 20 additional models, 52 if you count all four RAM capacities of the [Raspberry Pi 4 B](https://www.tomshardware.com/reviews/raspberry-pi-4) and all 32 variants of the Raspberry Pi Compute Module 4 (which comes in different RAM and storage capacities and with or without Wi-Fi). + +The original Raspberry Pi, the Model B had just 256MB of RAM and a single-core, 700 MHz processor. The current mainstream model, the Pi 4 B, has up to 8GB of RAM, a quad-core 1.5-GHz CPU and USB 3.0 ports. + +[Untitled](https://www.notion.so/8167832e68b6463b931c6876c83629dd) + +Launched in late 2020, the [Raspberry Pi 400](https://www.tomshardware.com/news/raspberry-pi-400-review-faster-cpu-new-layout-better-thermals) is Raspberry Pi's first standalone computer. Instead of a bare board, the Pi 400 is a keyboard with the equivalent of a Pi 4 inside, though the CPU runs at 1.8 rather than 1.5 GHz. It's sold either by itself or in a kit with a mouse, power supply, cables and an official guide. + +The Raspberry Pi Pico is a completely different type of Pi, a microcontroller board that's more like an Arduino than a traditional Pi (more on that below). + +## 3. Raspberry Pi Pico marks a new chapter in Pi history. + +Released in January 2021, the [Raspberry Pi Pico](https://www.tomshardware.com/news/raspberry-pi-pico-tutorials-pinout-everything-you-need-to-know) is the company’s first microcontroller and marks the debut of its first custom silicon, the RP2040 CPU. Where every prior Pi has been a full-fledged computer that boots into a, typically Linux, operating system, the `$4` Pico falls into the same category as Arduino. The Pico is great for controlling motors, lights and sensors and runs a program as soon as you turn it on, without the need to boot up or the worry that you’ll lose data if you pull the plug without doing a safe shutdown. + +The Pico has three built-in ADC (analog-to-digital converters), something that other Pis lack, which allow you to connect directly to analog devices such as joysticks, potentiometers and distance sensors. See our articles about [Raspberry Pico vs Arduino](https://www.tomshardware.com/features/raspberry-pi-pico-vs-arduino) and [which Raspberry Pi is right for you](https://www.tomshardware.com/how-to/raspberry-pi-buying-guide) for more detailed comparisons between the Pico, the Arduino and other Raspberry Pis. + +The RP2040 chip which powers the Pico marks an even bigger evolution than the board itself. This 133-MHz, dual-core Cortex M0+ CPU is designed by the Raspberry Pi Foundation and licensed out to other vendors such as Pimoroni and Adafruit who are building an entire ecosystem of RP2040-powered microcontrollers themselves. Even Arduino is getting in on the act, releasing the [Arduino Nano RP2040 Connect](https://www.tomshardware.com/news/first-pi-silicon-arduino-nano-rp2040-connect-spotted), which will have built-in Wi-Fi and Bluetooth. + +## 4. The most popular Pi is . . . + +The Raspberry Pi 3 B is the best-selling Pi model of all-time, with 13.2 million units sold. Of the various Raspberry Pi 4 B RAM capacities, the 4GB model accounts for approximately twice as many sales as the 8GB and 2GB SKUs. + +The Pico has only been on the market for a few weeks, but already has sold 250,000 units with 750,000 on back order. 2020 was the top-selling year for Pi, with 7.1 million units sold. + +## 5. The Pi has more than 20 operating systems. + +Raspberry Pi OS, a customized version of Debian, is the official operating system for Raspberry Pi boards, but it’s not the only choice, by far. From Pi-friendly versions of Ubuntu and FreeBSD Linux to unofficial ports of Android and Chrome OS, there are a ton of different operating systems available. Some of the most interesting include: + +- **[LibreELEC](https://libreelec.tv/downloads_new/):** A lightweight OS that runs the Kodi open-source media software. +- **[RISC OS](https://www.riscosopen.org/content/downloads/raspberry-pi):** Designed for ARM chips, this unique OS promises faster speeds than Linux. +- **[Chromium OS](https://github.com/FydeOS/chromium_os-raspberry_pi)**: Turn your Pi into a Chrome Box. +- **Windows 10:** Yes, you can [install Windows 10 on a Raspberry Pi 4](https://www.tomshardware.com/how-to/install-windows-10-raspberry-pi) (with some hacks), but it’s so slow you probably won’t want to keep using it. +- **[Lakka](https://www.lakka.tv/):** Specially designed for retro gaming, this OS comes with a series of emulators pre-loaded. + +## 6. There are two Raspberry Pis in space. + +The International Space Station is home to two [“Astro Pis,”](https://www.raspberrypi.org/education/programmes/astro-pi/) which are specially modified Raspberry Pi B+ models that have been “space hardened” and equipped with the official Raspberry Pi Sense HATs . The European Space agency runs periodic contests where children submit code to be run on the devices. + +Though the Pis are older models, they recently got a storage upgrade as the Astro Pi project [sent 256GB microSD cards to the ISS](https://twitter.com/astro_pi/status/1365315688034799622) to replace the 32GB cards they were using. + +## 7. The Raspberry Pi Foundation wants products to live forever. + +Even though the Raspberry Pi B+, Raspberry Pi 2, Raspberry Pi 3 B and other models are way out of date, the Raspberry Pi Foundation continues to actively manufacture and sell them. The organization hates to End-of-Life (EOL) products, because there are industrial clients who may still need them even if they are really old. + +"EOLing product is death. We’ve EOLed [just] five products in our life," Upton told us in 2019. He said that the only five products that Raspberry Pi discontinued include the Pi 1A and Pi 1B, because "the Pi 1A+ and B+ are a better implementation of that world." + +Even after the price of the Raspberry Pi 4 B (2GB) dropped to $35, the 1GB model remained available at the same price, because some customers may still want it as a drop-in replacement. + +## 8. The price of Raspberry Pi has dropped, relative to inflation. + +The original Raspberry Pi cost $35 in 2012 while the [Raspberry Pi 4](https://www.tomshardware.com/reviews/raspberry-pi-4) B (2GB) costs the same price today. However, if you consider inflation, $35 from 2012 is actually equivalent to $39.88 today. For that same price, you get: + +- A 40x faster processor (700 MHz, single-core vs 1.5-GHz quad core) +- 8x the RAM (256GB vs 2GB) +- Wi-Fi vs no-Wifi +- Dual monitor output vs single HDMI out +- USB 3.0 ports vs USB 2 only + +If $35 still seems like a lot of money, there are cheaper Pi models. The Raspberry Pi Zero goes for just $5 while the Raspberry Pi Pico, a microcontroller board, goes for a mere $4. + +## 9. There’s a Pi War every year. + +Yes, you can compete with your Raspberry Pi. [Pi Wars](https://piwars.org/) is an annual robotics competition where all of the gear must be built with your choice of Raspberry Pi. Teams at Pi Wars compete in challenges such as navigating obstacle courses, popping balloons and navigating a maze. + +There are both human-driven and automated challenges. The next Pi Wars will take place in July 2021. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划]([https://github.com/xitu/gold-miner](https://github.com/xitu/gold-miner)) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划]([https://github.com/xitu/gold-miner](https://github.com/xitu/gold-miner)) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金]([https://juejin.im](https://juejin.im/)) 上的英文分享文章。内容覆盖 [Android]([https://github.com/xitu/gold-miner#android](https://github.com/xitu/gold-miner#android))、[iOS]([https://github.com/xitu/gold-miner#ios](https://github.com/xitu/gold-miner#ios))、[前端]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)前端)、[后端]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)后端)、[区块链]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)区块链)、[产品]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)产品)、[设计]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)设计)、[人工智能]([https://github.com/xitu/gold-miner#](https://github.com/xitu/gold-miner#)人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划]([https://github.com/xitu/gold-miner](https://github.com/xitu/gold-miner))、[官方微博]([http://weibo.com/juejinfanyi](http://weibo.com/juejinfanyi))、[知乎专栏]([https://zhuanlan.zhihu.com/juejinfanyi](https://zhuanlan.zhihu.com/juejinfanyi))。 diff --git a/article/2021/responsive-images-different-techniques-and-tactics.md b/article/2021/responsive-images-different-techniques-and-tactics.md new file mode 100644 index 00000000000..aff4fe8c63f --- /dev/null +++ b/article/2021/responsive-images-different-techniques-and-tactics.md @@ -0,0 +1,161 @@ +> * 原文地址:[Responsive Images: Different Techniques and Tactics](https://blog.bitsrc.io/responsive-images-different-techniques-and-tactics-6045a1fa7ea2) +> * 原文作者:[Lahiruka Wijesinghe](https://medium.com/@lahiruka_) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/responsive-images-different-techniques-and-tactics.md](https://github.com/xitu/gold-miner/blob/master/article/2021/responsive-images-different-techniques-and-tactics.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[Chorer](https://github.com/Chorer) + +# 实现响应式图像的四种技术策略 + +![](https://cdn-images-1.medium.com/max/5760/1*AeGGYFx8qjpVRaSw4jPPzQ.jpeg) + +创建响应式图像并不像是火箭科学那么的深奥,我相信你已经使用 CSS 创建了很多类似工具。然而,当谈到响应式图像时,灵活的尺寸只是其中的一个因素。 + +> 有时根据不同的设备类型,我们需要调整图像质量甚至图像类型,以获得更好的用户体验。 + +今天,我们有了不同的技术帮助我们加载合适的质量和尺寸的图片。本文将探讨这些方法,帮助你找到最适合你项目的方法。 + +## 响应式图像方法简介 + +* **基于设备像素方法**:这种方法使用同一图片的多个版本。它会以不同的分辨率来选择最合适的一个图片来渲染。这种方法比较适合不渲染高分辨率图像的设备。 +* **流式图像方法**:默认情况下,图像不是流式的,因而当屏幕尺寸改变时,它们往往会被裁切或仍然保持一个固定的尺寸。使用流式图像方法,我们就可以将图像放入到响应式布局中,并根据需要拉伸或收缩。 +* **艺术指导方法**:艺术指导是我们在处理不同屏幕尺寸时普遍采用的方法。我们可以通过改变图片内容,裁剪图片,或者根据用户的屏幕尺寸使用不同的图片来解决这个问题。 +* **类型切换方法**:有些浏览器和设备不支持 WebP 等现代图像类型。类型切换方法可用于在图像类型之间进行切换,从而允许你基于设备和浏览器的兼容性向用户提供最佳内容。 + +既然你了解了这些方法和它们最适用的场景,那就让我们看一下如何实现这些方法。 + +## 实现响应式图像方法 + +如上文所述,有多种实现响应式图像的方法。了解这些方法的最佳实现方式,从而让你的项目获得最大收益是非常重要的。 + +默认情况下,HTML 提供了几个优秀的标签和属性,如 `img`、`picture`、`size` 和 `srcset`,用于 Web 开发中的图片渲染。现在,我将向大家展示如何使用这些标签和属性在短时间内实现上述方法。 + +### 1. 基于设备像素方法 + +在深入探讨之前,我需要解释一下有关高密度显示屏的信息。现代旗舰移动设备(例如三星 Galaxy S10)具有 4 倍的密度显示屏,而某些经济型机型可能只有低密度显示屏。 + +> 如果我们在低密度的显示屏中推送加载高密度的图片,那么会导致用户体验非常差,而且会浪费资源。因此,我们需要针对不同的设备像素比使用不同的图像。 + +在如下示例中,我们对比了两张图片。`320×240` 像素的 **small-kitten.jpg** 图像和 `640×480` 像素的 **large-kitten.jpg** 图像,显然后者适合高分辨率显示。(`x` 描述符表示预期的设备像素比) + +```html +A cute kitten +``` + +如果用户的设备分辨率高于 `640×480` 像素,则将渲染 **large-kitten.jpg** 图像,否则,将渲染 **small-kitten.jpg** 图像。最重要的是,具有低分辨率设备的用户不会感到图像加载时间有任何延迟,而具有高分辨率设备的用户不会感到图像质量有任何问题。 + +### 2. 流式图像方法 + +这种方法的核心在于使用同一图像的不同尺寸,而不是使用不同的图像。 + +例如,我们可以通过给出相对比例的图像大小而不是给出精确的像素值来实现简单的流式图像。最常用的方法是 `max-width:100%`。 + +```html +Black dog image +``` + +![最大宽度缩放图像的行为](https://cdn-images-1.medium.com/max/2000/1*qRrsflBr2ijjicwLijLZxw.gif) + +> 如你所见,上面的图像可以自由缩放并适应浏览器窗口大小。在文章头图较大时,该方法将是理想的选择。 + +此外,还有一种使用流式图像的高级方法,可以使用图像的宽度和页面的整体宽度来计算尺寸。 + +例如,考虑一个 `1200px` 宽的网页和一个 `500px` 宽的图像。然后,按照如下方法计算图像在页面上占用的空间: + +``` +图像宽度占用量 = 图像宽度 / 页面宽度 + +(500/1200) x 100% = 41.66% +``` + +然后,我们可以在下面的代码块中使用这个值。它将使图像始终与网页大小保持相同比例。 + +```html +Black dog image +``` + +![按百分比宽度缩放图像的行为](https://cdn-images-1.medium.com/max/2000/1*71Fwlv3IISxAwLGUZNyFXw.gif) + +> 但是,当视口太大或太小时,这种计算可能会引起一些问题。 + +我们可以通过给图像添加以像素为单位的最大宽度和最小宽度来设置上限和下限,从而解决这个问题。 + +```html +Black dog image +``` + +### 3. 艺术指导方法 + +艺术指导方法的核心是根据设备的屏幕大小显示不同的图像。我们可以通过切换到 `picture` 标签而不是使用 `img` 标签来做到这一点,因为它允许在不同的设备上查看时提供多比例或多焦点的图像。 + +![著名的[猫咪实验艺术指导方法](https://googlechrome.github.io/samples/picture-element/)— Google Chrome](https://cdn-images-1.medium.com/max/2000/1*owaoaROx5LN6QVYe6edlEg.gif) + +像下面这样简单的代码片段就可以得到上述结果。这里,我们在 `` 元素中提供了 2 个不同的属性值:`media` 和 `srcset` 分别定义了图像的大小和来源。 + +```html + + + + + A cute kitten + +``` + +在上面的示例中,如果屏幕尺寸大于 `560px`,浏览器将显示第一张图片的图像。如果屏幕尺寸大于 `465px` 且低于 `650px`,浏览器将使用第二张图片。 + +你会注意到常规的 `` 标签是 `` 元素的最后一个嵌套标签。使用 `` 元素对于代码是否能够正常工作至关重要 —— 当媒体查询中的条件不匹配时,它将作为备选方案,并且会兼容不支持 `` 元素的浏览器。 + +### 4. 类型切换方法 + +随着技术的飞速发展,`avif`、`webp` 等不同类型的现代图像类型日渐被引入。虽然它们提供了更高的用户体验,但是有些浏览器还不支持这些图像类型。 + +> 因此,我们可以通过改变图像格式来使用类型切换去解决这种情况。 + +例如,下面的代码包含 2 种现代图像类型和 `gif` 图像。首先,浏览器将尝试 `avif` 格式,如果失败,它将尝试 `webp` 格式。如果浏览器不支持这两种格式,它将使用 `png` 图像。 + +```html + + + + A cute kitten + +``` + +你也可以使用 Chrome DevTools 来模拟这一点,看看当浏览器不支持现代图像类型时,你的图像会是什么样子。 + +![使用 Chrome DevTools 来模拟图像切换](https://cdn-images-1.medium.com/max/2706/1*6Ey8MZsWnVkB74lQYfOBBw.gif) + +## 总结 + +我相信现在大家对可以用什么方法来实现响应式图像,以及它们大多适合什么情况有了一定的了解。 + +开发任何 Web 应用程序时,请确保充分利用这些知识,因为以正确的方式实现响应式图像有助于提供更好的用户体验。 + +因此,我希望大家尝试这些方法,并在评论区分享你的想法。 + +感谢你的阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/safari-has-become-the-second-internet-explorer.md b/article/2021/safari-has-become-the-second-internet-explorer.md new file mode 100644 index 00000000000..5ede598035a --- /dev/null +++ b/article/2021/safari-has-become-the-second-internet-explorer.md @@ -0,0 +1,118 @@ +> * 原文地址:[Safari Has Become The Second Internet Explorer](https://medium.com/javascript-in-plain-english/safari-has-become-the-second-internet-explorer-e2c2dd114837) +> * 原文作者:[Golosay Volodymyr](https://medium.com/@golosay) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/safari-has-become-the-second-internet-explorer.md](https://github.com/xitu/gold-miner/blob/master/article/2021/safari-has-become-the-second-internet-explorer.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[lsvih](https://github.com/lsvih) + +# 恭喜 Safari 荣获「第二个 Internet Explorer」的美誉 + +![Safari 有时候看起来长得跟 IE 没啥不一样的](https://cdn-images-1.medium.com/max/2300/1*obluMaNgoWxwefRpP__Elg.png) + +如果你去问问一个程序员他对听到 IE 这个词的感受,一般来说,绝对是这样的 —— OMG 痛苦的要死!我当然也不是例外!我作为一名 Web 开发者已经有了十多年,在这段时间里面,开发过不少必须要兼容 IE 的项目。我清晰地认识到,某些奇葩浏览器不支持别的浏览器支持的常见功能这个问题,是如何令我们这群本已秃头的程序员们更加头秃沮丧的。或者说,有的时候,这种坑货浏览器甚至还会错误地将部分元素渲染在错误的地方!更糟糕的是,你可能有些时候还得去调试某些意料之外的错误的行为。 + +幸(讽)运(刺)的是,我在日常生活中使用着一台 M1 芯片的新款 MacBook Pro。我超级喜欢使用 Apple 所开发的软件,因为它们总是快速、节能、美观的。Safari 就是 Apple 所提供的软件的其中之一。我好想再爱一遍 Safari 啊,可惜我越多地与它共事,就越多地回想起 IE。因此,点明这些关切到我们每个人切身头发安全的问题是非常之重要的。而对于其中一些问题,我将会为大家提供防脱发治疗手段。 + +## PWA 支持 + +Safari 对 PWA 的支持?更确切地说应该是缺乏支持!Apple 是现当时最离谱的拒绝 PWA 的厂商之一。你知道什么是 PWA 吗?PWA 是一类可以在浏览器中打开它,并在本地安装的网络应用。它看起来和从应用商店中安装的普通应用一样,并且具有离线启动的功能。从理论上讲,你可以立即在你的浏览器上尝试一下(例如在 iPhone 上安装 PWA 应用程序),但是好心的 Apple 会用如下的借口劝退你: + +* 你不能存储超过 50 MB 的数据 +* 不支持蓝牙 +* 不支持原生的分享框 +* 没有后台同步或是 Web 推送通知 +* 没有 Web App 横幅提醒用户安装应用 +* 不支持自定义启动画面 + +这些限制使 PWA 这项技术毫无用处。比起技术,Apple 可能更希望控制市场,让用户仅可以通过 App Store 安装所谓真正的应用程序。 + +在 Mac 上的 Safari 中,你根本无法用它。 + +## Web 推送通知 + +这个话题虽说位列 PWA 的限制列表中,但也值得单独一提。 + +在 Mac 上,某些应用程序的 Web 版本无法发送推送通知,导致不能提供全部功能。 + +![推送通知浏览器支持表格](https://github.com/PassionPenguin/gold-miner-images/blob/master/safari-has-become-the-second-internet-explorer-developer.mozilla.org_en-US_docs_Web_API_Push_API.png?raw=true) + +Messenger 应用们就是最好的例子。如今,Telegram 或 Facebook Messenger 只能在网站打开时通过变更标题和播放声音来通知用户有关新消息的信息。如果用户静音了,并将浏览器最小化了,显然就会错过新的消息。 + +此限制的唯一好处是,新闻站点没有烦人的通知告示希望你去订阅它们的提醒 —— 这可真棒,但丝毫不等同于我们不需要通知功能! + +## 滑动表现 + +Apple 为 Safari 的性能和能效感到骄傲(这点的确如此)! + +为了获得如此好的性能,他们实施了许多优化,其中之一是在用户进行动态滚动操作时阻止 DOM 更新。但是优化之后,用户们开始发现浏览器出现了一些滚动的滞后。最著名的问题 —— 在 YouTube 视频页面上滚动评论。大量的用户在[官方支持论坛](https://discussions.apple.com/thread/250853003)和 MacRumors 上对有关问题进行了讨论。 + +要解决此问题,你必须安装 UserScripts 扩展并添加一些 CSS 样式: + +```scss +// ==UserScript== +// @name FixYouTubeScrolling +// @description Stop improper styling, Google +// @match *://*youtube.* +// ==/UserScript== + +ytd-page-manager { + overflow-y: unset !important; +} + +#page-manager.ytd-app { + overflow-x: unset !important; +} +``` + +但这不是存在此问题的唯一地方。我在许多不同的在滚动事件上附加了很多功能的网站(例如 Youtube 音乐、Facebook、Reddit 等)上都发现了类似的滚动上的问题。 + +这就实现快速滚动的代价,所以我希望 Apple 能够在性能和表现上找到一个更好的平衡点。 + +## YouTube + +让我们讨论讨论 YouTube!你大概率遇到过缩略图或头像无法加载的问题,可以在 Apple 论坛中找到有关此问题的许多帖子(例如[这个](https://discussions.apple.com/thread/252092264)和[这个](https://forums.macrumors.com/threads/youtube-website-scrolling-issue.2272026/))。 + +我不知道问题的根源,但已经明确了是缓存中的错误。虽说清除缓存可以解决此问题。但是它有时仍然会复现。 + +有两种清除 Safari 中缓存的方法: + +1. 在 Safari 中单击"刷新"按钮的同时,按键盘上的 `Shift` 键。 +2. 按键盘上的 **`Command(⌘)`** + **`Option(⌥, alt)`** + **`R`**。 + +随你选择~ + +## 图标 + +你是否能在 Mac 的 Safari 中看到 Instagram 网页的图标?出于某种原因,它是黑白的。 + +![左上角的黑白图标](https://cdn-images-1.medium.com/max/5744/1*GgbMRIpIX_cuz6eCaLSoXA.png) + +这是个次要的但也是个非常奇怪的问题。你可以自己尝试访问一下,会发现真正的图标应该是有颜色的。这个问题也出现在了我的 [methodist.io](https://methodist.io) 网页上。我在许多站点上都发现了此问题,而如果你知道此问题的发生原因以及解决方法,麻烦在评论中分享~ + +## 拓展 + +在 2018 年之前,Safari 并没有用于构建浏览器扩展的框架。因此,App Store 中针对 Safari 的扩展程序真的很少。仅在 2018 年之后,他们才开始像 Chrome 一样使用 WebExtensions Api。对于扩展程序开发人员而言,这是一个巨大的进步,因为主要浏览器的核心 API 已经相同了。虽说已经过了很长一段时间了,但如今,Safari 与其他浏览器相比,扩展的数量依旧存在着巨大的差异。 + +## 媒体格式标准化 + +你们可能都知道 JPEG 和 PNG 图像格式。它们年代久远(诞生于 1992 年),文件又大。因此,在 2017 年,科技巨头们都决定设计更高效的媒体格式。苹果发布了 HEIC(High-Efficiency Image Coding 高效图片编码),谷歌推广了 WebP。但是由于某些原因,他们都彼此不认可对方。Chrome 仅支持 WebP,而 Safari 又仅支持 HEIC。直到 2020 年年中,Apple 才在 Safari 中添加了对 WebP 的支持。 + +这个问题是关于图像的,但同样也适用于视频。Google 为视频设计了 **WebM** 格式,但即使现在(2021 年 1 月),**Safari 也不支持这个格式**。 + +在 2019 年,IT 巨头开始合作,开发先进、免费的视频编解码器 **AV1**。苹果、谷歌、Netflix 等公司(这个名单令人印象深刻)成立了一家”开放媒体联盟“公司,这些企业共享了他们的技术和专利,以创建跨时代的解编码器。目前,解编码器已开发完了,Netflix 也业已在其应用中使用了它,但是 Safari 还是不支持它。 + +![开放媒体联盟](https://cdn-images-1.medium.com/max/2000/1*4Hu_Vd2eexqGCyRn16_AZg.jpeg) + +如你所见,Safari 是一款非常保守的浏览器,而 Apple 总是不愿意与用户的意愿保持一致。 + +## 小结 + +Safari 是快速的、节能的一款(甚至是)安全的浏览器。但是 Apple 它呢有它自己的想法。当然,Apple 还是喜欢赚钱,而让用户能够避开 App Store 安装应用程序可不是什么有利可图的想法。类似的辩解口径对于自己不兼容某些主流的媒体格式都是通用的,但是这些问题可真真实实地阻碍了技术的发展,给我们这群头秃的开发人员平添了更多的麻烦。 + +**感谢你的阅读!** + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/self-supervised-learning-the-dark-matter-of-intelligence.md b/article/2021/self-supervised-learning-the-dark-matter-of-intelligence.md new file mode 100644 index 00000000000..6d1b59a1ef4 --- /dev/null +++ b/article/2021/self-supervised-learning-the-dark-matter-of-intelligence.md @@ -0,0 +1,152 @@ +> * 原文地址:[Self-supervised learning: The dark matter of intelligence](https://ai.facebook.com/blog/self-supervised-learning-the-dark-matter-of-intelligence/) +> * 原文作者:Yann LeCun, Ishan Misra +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/self-supervised-learning-the-dark-matter-of-intelligence.md](https://github.com/xitu/gold-miner/blob/master/article/2021/self-supervised-learning-the-dark-matter-of-intelligence.md) +> * 译者: +> * 校对者: + +# Self-supervised learning: The dark matter of intelligence + +In recent years, the AI field has made tremendous progress in developing AI systems that can learn from massive amounts of carefully labeled data. This paradigm of supervised learning has a proven track record for training specialist models that perform extremely well on the task they were trained to do. Unfortunately, there’s a limit to how far the field of AI can go with supervised learning alone. + +Supervised learning is a bottleneck for building more intelligent generalist models that can do multiple tasks and acquire new skills without massive amounts of labeled data. Practically speaking, it’s impossible to label everything in the world. There are also some tasks for which there’s simply not enough labeled data, such as training translation systems for low-resource languages. If AI systems can glean a deeper, more nuanced understanding of reality beyond what’s specified in the training data set, they’ll be more useful and ultimately bring AI closer to human-level intelligence. + +As babies, we learn how the world works largely by observation. We form generalized predictive models about objects in the world by learning concepts such as object permanence and gravity. Later in life, we observe the world, act on it, observe again, and build hypotheses to explain how our actions change our environment by trial and error. + +A working hypothesis is that generalized knowledge about the world, or common sense, forms the bulk of biological intelligence in both humans and animals. This common sense ability is taken for granted in humans and animals, but has remained an open challenge in AI research since its inception. In a way, common sense is the dark matter of artificial intelligence. + +Common sense helps people learn new skills without requiring massive amounts of teaching for every single task. For example, if we show just a few drawings of cows to small children, they’ll eventually be able to recognize any cow they see. By contrast, AI systems trained with supervised learning require many examples of cow images and might still fail to classify cows in unusual situations, such as lying on a beach. How is it that humans can learn to drive a car in about 20 hours of practice with very little supervision, while fully autonomous driving still eludes our best AI systems trained with thousands of hours of data from human drivers? The short answer is that humans rely on their previously acquired background knowledge of how the world works. + +How do we get machines to do the same? + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/152694956_207655794383548_8489544025025665441_n.png?_nc_cat=102&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=vTr8Ey9RqxEAX_hYt0f&_nc_ht=scontent-nrt1-1.xx&oh=f1466ddb3a53501d68d6ca58e1574ef1&oe=6071B6F1](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/152694956_207655794383548_8489544025025665441_n.png?_nc_cat=102&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=vTr8Ey9RqxEAX_hYt0f&_nc_ht=scontent-nrt1-1.xx&oh=f1466ddb3a53501d68d6ca58e1574ef1&oe=6071B6F1) + +We believe that self-supervised learning (SSL) is one of the most promising ways to build such background knowledge and approximate a form of common sense in AI systems. + +Self-supervised learning enables AI systems to learn from orders of magnitude more data, which is important to recognize and understand patterns of more subtle, less common representations of the world. Self-supervised learning has long had great success in advancing the field of natural language processing (NLP), including the [Collobert-Weston 2008 model](https://l.facebook.com/l.php?u=https%3A%2F%2Fronan.collobert.com%2Fpub%2Fmatos%2F2008_nlp_icml.pdf&h=AT1yOAr331_AUdt65mqISQy-_ejoxQLKDRouxlGfpR0q1stomp2cdKkfrg3NRvm6otV7B__bvAjftxzZXPXnFtR6NzneYOqwourNxEXYoCOhHof2I-pykUiTPcRItQ8Ps5fWLN_IDgHLS9-ctSRLf9AOKoI), [Word2Vec](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fpdf%2F1301.3781.pdf&h=AT2jLU4yk75SQC_TRhoKW7VxXnrxpuMIJ0MbVQKoz7rFprDLqddCm2ZkVDVpHlbNxgTOQZLBQsGbpexUSy7_3SlFjYCrsCnmvosxw7F8QOSnIMDk-agewDgwzU_zIcjTN7sb88yjBY7ofrw4qf8gdBXzvPU), [GloVE](https://l.facebook.com/l.php?u=https%3A%2F%2Fnlp.stanford.edu%2Fpubs%2Fglove.pdf&h=AT3xNxZzYY6jjwV0QuqQIpORfF_cDnZa2_ybdVMuy79Bbxfinvhym3GBbwR_s9mVdWdd7hDy1PfaF6INbC-IW71Su1ep6_R5tlMouzyVgif_pWHxyAaeoVm-MyCxZ7tJm32ClcyIlU_Z1bbVPPEiIKkbnGw), [fastText](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fpdf%2F1607.01759.pdf&h=AT1fFLk32dWLmQgrfPgFVh-nnuu3Gs_uYn2BnFmyJ6EzQWVNU_R5jUOM096qjHjBjwbmO0oUhllkkguDJduIe44so0ViXJrTDPcI7uBhHlYsNb9ARXnGpuwrvZ8hIljPmTU5pFhueOkkLAo-9wMcA4xrARY), and, more recently, [BERT](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fpdf%2F1810.04805.pdf&h=AT3FYFWnWwZoAFAmqqdB0iCSoI1GDYIH9IfcL6YOAf9uPh5xNl5A0G4DboF3taMf7mpPfaQfI8bZduWQIUlh1cdRzboolktPLjNh3lUz76SPzfoWgGCfHmCntbyhmEgP1WJn7-tEKbSaH4g3lHiuv25VeyA), [RoBERTa](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fpdf%2F1907.11692.pdf&h=AT2CQnffCaZC6L5Y5CKZeea9Dp1EVhdCPb86jEDCTAxoCozK45ePOxDD-xI-Pd8cdX6_IXk4z19c6ljVw3AeA8KpK0SgRd95mXmyej8Bb4OUgddGs_TCjHMBVg-0RFXUgV4jm9FZivJHW4Dydiss5i-rjwg), [XLM-R](https://ai.facebook.com/blog/-xlm-r-state-of-the-art-cross-lingual-understanding-through-self-supervision/), and others. Systems pretrained this way yield considerably higher performance than when solely trained in a supervised manner. + +Our latest research project [SEER](https://ai.facebook.com/blog/seer-the-start-of-a-more-powerful-flexible-and-accessible-era-for-computer-vision) leverages SwAV and other methods to pretrain a large network on a billion random unlabeled images, yielding top accuracy on a diverse set of vision tasks. This progress demonstrates that [self-supervised learning can excel at CV tasks in complex, real-world settings as well](https://arxiv.org/pdf/2103.01988.pdf?fbclid=IwAR2pqhYda6MV9r2b3Afx_0eKUiZhX-Es6Pa_FbLOqH8fglQzO2kY3yKxZE8). + +Today, we’re sharing details on why self-supervised learning may be helpful in unlocking the dark matter of intelligence — and the next frontier of AI. We’re also highlighting what we believe are some of the most promising new directions of energy-based models for prediction in the presence of uncertainty, joint embedding methods and latent-variable architectures for self-supervised learning and reasoning in AI systems. + +## Self-supervised learning is predictive learning + +Self-supervised learning obtains supervisory signals from the data itself, often leveraging the underlying structure in the data. The general technique of self-supervised learning is to predict any unobserved or hidden part (or property) of the input from any observed or unhidden part of the input. For example, as is common in NLP, we can hide part of a sentence and predict the hidden words from the remaining words. We can also predict past or future frames in a video (hidden data) from current ones (observed data). Since self-supervised learning uses the structure of the data itself, it can make use of a variety of supervisory signals across co-occurring modalities (e.g., video and audio) and across large data sets — all without relying on labels. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/148954125_461761118405979_2035914075893596810_n.png?_nc_cat=107&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=a7mBQyPFw24AX_f0OWL&_nc_ht=scontent-nrt1-1.xx&oh=0124866062146d753e181cb9f12b0c98&oe=60720D19](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/148954125_461761118405979_2035914075893596810_n.png?_nc_cat=107&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=a7mBQyPFw24AX_f0OWL&_nc_ht=scontent-nrt1-1.xx&oh=0124866062146d753e181cb9f12b0c98&oe=60720D19) + +In self-supervised learning, the system is trained to predict hidden parts of the input (in gray) from visible parts of the input (in green). + +As a result of the supervisory signals that inform self-supervised learning, the term “self-supervised learning” is more accepted than the previously used term “unsupervised learning.” Unsupervised learning is an ill-defined and misleading term that suggests that the learning uses no supervision at all. In fact, self-supervised learning is not unsupervised, as it uses far more feedback signals than standard supervised and reinforcement learning methods do. + +## Self-supervised learning for language versus vision + +Self-supervised learning has had a particularly profound impact on NLP, allowing us to train models such as BERT, RoBERTa, XLM-R, and others on large unlabeled text data sets and then use these models for downstream tasks. These models are pretrained in a self-supervised phase and then fine-tuned for a particular task, such as classifying the topic of a text. In the self-supervised pretraining phase, the system is shown a short text (typically 1,000 words) in which some of the words have been masked or replaced. The system is trained to predict the words that were masked or replaced. In doing so, the system learns to represent the meaning of the text so that it can do a good job at filling in “correct” words, or those that make sense in the context. + +Predicting missing parts of the input is one of the more standard tasks for SSL pretraining. To complete a sentence such as “The (blank) chases the (blank) in the savanna,” the system must learn that lions or cheetahs can chase antelope or wildebeests, but that cats chase mice in the kitchen, not the savanna. As a consequence of the training, the system learns to represent the meaning of words, the syntactic role of words, and the meaning of entire texts. + +These techniques, however, can’t be easily extended to new domains, such as CV. Despite promising early results, SSL has not yet brought about the same improvements in computer vision that we have seen in NLP (though this will change). + +The main reason is that it is considerably more difficult to represent uncertainty in the prediction for images than it is for words. When the missing word cannot be predicted exactly (is it “lion” or “cheetah”?), the system can associate a score or a probability to all possible words in the vocabulary: high score for “lion,” “cheetah,” and a few other predators, and low scores for all other words in the vocabulary. + +Training models at this scale also required a model architecture that was efficient in terms of both runtime and memory, without compromising on accuracy. Fortunately, a recent innovation by FAIR in the realm of architecture design led to a new model family called [RegNets](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F2003.13678&h=AT0R7AOGM3W0HxnXE94rVR33vdmjyoOhjALclG00EUTQuel2P09LSzyaDzDrvM8pjvx9TLPtGRJT94F8pmX4NxFA6VsvSJBotumq0JlaPNi6zTnH0jAsgwv8kxn2r7F3_Hi-UapmqfPtbr8yVvS-ZZxoSb8) that perfectly fit these needs. RegNet models are ConvNets capable of scaling to billions or potentially even trillions of parameters, and can be optimized to fit different runtime and memory limitations. + +But we do not know how to efficiently represent uncertainty when we predict missing frames in a video or missing patches in an image. We cannot list all possible video frames and associate a score to each of them, because there is an infinite number of them. While this problem has limited the performance improvement from SSL in vision, new techniques SSL techniques such as SwAV are starting to beat accuracy records in vision tasks. This is best demonstrated by the SEER system that uses a large convolutional network trained with billions of examples. + +## Modeling the uncertainty in prediction + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/148662482_469317657771087_6509708649537324681_n.png?_nc_cat=110&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=oZ2iEBMofskAX-Br_0U&_nc_ht=scontent-nrt1-1.xx&oh=4e685702e8fdb5b3ea65e3e14b71c7b8&oe=60707C09](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/148662482_469317657771087_6509708649537324681_n.png?_nc_cat=110&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=oZ2iEBMofskAX-Br_0U&_nc_ht=scontent-nrt1-1.xx&oh=4e685702e8fdb5b3ea65e3e14b71c7b8&oe=60707C09) + +To better understand this challenge, we first need to understand the prediction uncertainty and the way it’s modeled in NLP compared with CV. In NLP, predicting the missing words involves computing a prediction score for every possible word in the vocabulary. While the vocabulary itself is large and predicting a missing word involves some uncertainty, it’s possible to produce a list of all the possible words in the vocabulary together with a probability estimate of the words’ appearance at that location. Typical machine learning systems do so by treating the prediction problem as a classification problem and computing scores for each outcome using a giant so-called softmax layer, which transforms raw scores into a probability distribution over words. With this technique, the uncertainty of the prediction is represented by a probability distribution over all possible outcomes, provided that there is a finite number of possible outcomes. + +In CV, on the other hand, the analogous task of predicting “missing” frames in a video, missing patches in an image, or missing segment in a speech signal involves a prediction of high-dimensional continuous objects rather than discrete outcomes. There are an infinite number of possible video frames that can plausibly follow a given video clip. It is not possible to explicitly represent all the possible video frames and associate a prediction score to them. In fact, we may never have techniques to represent suitable probability distributions over high-dimensional continuous spaces, such as the set of all possible video frames. + +This seems like an intractable problem. + +## A unified view of self-supervised methods + +There is a way to think about SSL within the unified framework of an energy-based model (EBM). An EBM is a trainable system that, given two inputs, x and y, tells us how incompatible they are with each other. For example, x could be a short video clip, and y another proposed video clip. The machine would tell us to what extent y is a good continuation for x. To indicate the incompatibility between x and y, the machine produces a single number, called an energy. If the energy is low, x and y are deemed compatible; if it is high, they are deemed incompatible. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/157272588_1389905731371138_8776386318723848066_n.png?_nc_cat=103&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=K0iuVzQHrTQAX8qFvra&_nc_ht=scontent-nrt1-1.xx&oh=d3d4572253e8c0099f0e462fdd901e31&oe=606FA02E](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/157272588_1389905731371138_8776386318723848066_n.png?_nc_cat=103&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=K0iuVzQHrTQAX8qFvra&_nc_ht=scontent-nrt1-1.xx&oh=d3d4572253e8c0099f0e462fdd901e31&oe=606FA02E) + +An energy-based model (EBM) measures the compatibility between an observation x and a proposed prediction y. If x and y are compatible, the energy is a small number; if they are incompatible, the energy is a larger number. + +Training an EBM consists of two parts: (1) showing it examples of x and y that are compatible and training it to produce a low energy, and (2) finding a way to ensure that for a particular x, the y values that are incompatible with x produce a higher energy than the y values that are compatible with x. Part one is simple, but part two is where the difficulty lies. + +For image recognition, our model takes two images, x and y, as inputs. If x and y are slightly distorted versions of the same image, the model is trained to produce a low energy on its output. For example, x could be a photo of a car, and y a photo of the same car that was taken from a slightly different location at a different time of day, so that the car in y is shifted, rotated, larger, smaller, and displaying slightly different colors and shadows than the car in x. + +## Joint embedding, Siamese networks + +A particular well-suited deep learning architecture to do so is the so-called Siamese networks or joint embedding architecture. The idea goes back to papers from Geoff Hinton’s lab and Yann LeCun’s group in the early 1990s ([here](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.nature.com%2Farticles%2F355161a0&h=AT05vV0wl8-ymnIP9tLB7exqY1dYgCoJmyhkNKYZ_5uffyRaqZef2-5zDqlpmg214RjiiLfEdKtagMbXieCfTpqTdCyTPwO_Ai1bNAg4bIG8iVBCQ7SPKT-AMhkfBD1DV0UE13rBfUHFlVxJzLMKEXXZCsc) and [here](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.worldscientific.com%2Fdoi%2Fabs%2F10.1142%2FS0218001493000339&h=AT3cUfJu8IEmA9GoTqNdguxuQfr87tRTCHAOU7r1FLo1C_URCXx0op_TL85oOVCMM3d_JQZKeHImkiS58JImAXA2PhOpZYACuYOj6MBqJE5VIiMAnBRIKbplhH-ccSLmyniSIzlcNIEpqgU50-sF2FxccaM)) and mid-2000s ([here](https://l.facebook.com/l.php?u=https%3A%2F%2Fproceedings.neurips.cc%2Fpaper%2F2004%2Fhash%2F42fe880812925e520249e808937738d2-Abstract.html&h=AT0Jzqnsltx0bAHsyUqrGaAKY21eoFBj7vXrxY7XFXn38ykexxvifvX_M8axzA_mq_syOn4LVFJCqFdGySG7C-XAQRGAHPmxWkfI1ArTzvP0sP-TYJpgQWy6VVrcXFQf1F9mIq3flg06L6TdDw3e8Z4aDcs), [here](https://l.facebook.com/l.php?u=https%3A%2F%2Fieeexplore.ieee.org%2Fabstract%2Fdocument%2F1467314&h=AT3iw6_7KTUwwBPaC5Y2F84lpYOqU-zKG5axbft_xI981ZFgt1l8RRc1Ef-KcFUFC92ZXy6sWqbE6rlOqGwzw0eU49S3QbeZTPd-Jood14Or6JwvPKCmZvOxP4yvfXcIX3AlBrQtXNCY31X_mmP6h-AO7QM), and [here](https://l.facebook.com/l.php?u=https%3A%2F%2Fieeexplore.ieee.org%2Fabstract%2Fdocument%2F1640964&h=AT0VVtlgl6tkyUvpX-NAgRhibMi8lMnL6bsYI7n_5NxZSMnABpV2lEfk0RTMvcIipebgDswSNtd2yeIWSPePDOoQp0m5WiTddMx5FxfkRfIDqG6MNJzVNPhse3Se_cLgY6ZheO2LmK5sDQx2v6DPthWZqlc)). It was relatively ignored for a long time but has enjoyed a revival since late 2019. A joint embedding architecture is composed of two identical (or almost identical) copies of the same network. One network is fed with x and the other with y. The networks produce output vectors called embeddings, which represent x and y. A third module, joining the networks at the head, computes the energy as the distance between the two embedding vectors. When the model is shown distorted versions of the same image, the parameters of the networks can easily be adjusted so that their outputs move closer together. This will ensure that the network will produce nearly identical representations (or embedding) of an object, regardless of the particular view of that object. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/149794655_780907256142255_4794526832594825319_n.jpg?_nc_cat=105&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=EiHfJJU682kAX_OTfbJ&_nc_ht=scontent-nrt1-1.xx&oh=e62f54136abfae75858098037ecbbc4f&oe=60719435](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/149794655_780907256142255_4794526832594825319_n.jpg?_nc_cat=105&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=EiHfJJU682kAX_OTfbJ&_nc_ht=scontent-nrt1-1.xx&oh=e62f54136abfae75858098037ecbbc4f&oe=60719435) + +Joint embedding architecture. The function C at the top produces a scalar energy that measures the distance between the representation vectors (embeddings) produced by two identical twin networks sharing the same parameters (w). When x and y are slightly different versions of the same image, the system is trained to produce a low energy, which forces the model to produce similar embedding vectors for the two images. The difficult part is to train the model so that it produces high energy (i.e., different embeddings) for images that are different. + +The difficulty is to make sure that the networks produce high energy, i.e. different embedding vectors, when x and y are different images. Without a specific way to do so, the two networks could happily ignore their inputs and always produce identical output embeddings. This phenomenon is called a collapse. When a collapse occurs, the energy is not higher for nonmatching x and y than it is for matching x and y. + +There are two categories of techniques to avoid collapse: contrastive methods and regularization methods. + +## Contrastive energy-based SSL + +Contrastive methods are based on the simple idea of constructing pairs of x and y that are not compatible, and adjusting the parameters of the model so that the corresponding output energy is large. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/127784209_262471582050413_7179678990272222350_n.gif?_nc_cat=104&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=Qw2ydPy1j7MAX-uPZLK&_nc_ht=scontent-nrt1-1.xx&oh=a720c6baeadc92181bacdb2fe8c3b850&oe=606F9307](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/127784209_262471582050413_7179678990272222350_n.gif?_nc_cat=104&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=Qw2ydPy1j7MAX-uPZLK&_nc_ht=scontent-nrt1-1.xx&oh=a720c6baeadc92181bacdb2fe8c3b850&oe=606F9307) + +Training an EBM with a contrastive method consists in simultaneously pushing down on the energy of compatible (x,y) pairs from the training set, indicated by the blue dots, and pushing up on the energy of well chosen (x,y) pairs that are incompatible, symbolized by the green dots. In this simple example, x and y are both scalars, but in real situations, x and y could be an image or a video with millions of dimensions. Coming up with incompatible pairs that will shape the energy in suitable ways is challenging and expensive computationally. + +The method used to train NLP systems by masking or substituting some input words belongs to the category of contrastive methods. But they don’t use the joint embedding architecture. Instead, they use a predictive architecture in which the model directly produces a prediction for y. One starts for a complete segment of text y, then corrupts it, e.g., by masking some words to produce the observation x. The corrupted input is fed to a large neural network that is trained to reproduce the original text y. An uncorrupted text will be reconstructed as itself (low reconstruction error), while a corrupted text will be reconstructed as an uncorrupted version of itself (large reconstruction error). If one interprets the reconstruction error as an energy, it will have the desired property: low energy for “clean” text and higher energy for “corrupted” text. + +The general technique of training a model to restore a corrupted version of an input is called denoising auto-encoder. While early forms of this idea go back to the 1980s, it was [revived in 2008](https://l.facebook.com/l.php?u=https%3A%2F%2Fdl.acm.org%2Fdoi%2Fabs%2F10.1145%2F1390156.1390294&h=AT0iy2KZaDRdop2QuB0FNn-TuQDr_PY8D194VrfRJZ659gzmCtZHXTi2ie5CtfRGlMd_HrBfRZgvjlv8LcrhKrSI9dljoDsZFdoCigXlXGnqYltf9nCSe5T1GOdD071b6mWffNirylURp3-MyYZBlcOmqIM) by Pascal Vincent and colleagues at the University of Montréal, introduced in the context of NLP by [Collobert and Weston](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.jmlr.org%2Fpapers%2Fv12%2Fcollobert11a.html&h=AT2ijGuIKPJkvG6A4SE_ZE5IsRcFqoxMbzGTw4_YZYHTpnjMgvsKM5IELfhc8EjBZhqqSVqkXtQj7SUKHMPHgQ_wQft6_mnv-wJm1P82ovLPz1Y0_VI8ezEAtxo2LRkPvdHnM8bk99u7luL1Hu12udy3uc8), and popularized by the [BERT paper](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F1810.04805&h=AT31I_xZIh8igomUwEa56DrfuzVLvtwTeTEiaRm2i1LQXDYXzC41rQS3bp_ywXbRdrndEMcIvDFrI5boPnOnXtNqU77B8GVZlLQDd-zvqnhPFrzcGwy_vVtNKVU9j3wWPKuCCC8LAIXpHIqcgOuIoGfdhVE) from our friends at Google. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/155526762_897797787644739_8022451761586606565_n.png?_nc_cat=108&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=v1xIgMFEa-sAX_NR5C9&_nc_ht=scontent-nrt1-1.xx&oh=a8dfd2ba7a9f2ddbe296f0df7eba3d4f&oe=60705F16](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/155526762_897797787644739_8022451761586606565_n.png?_nc_cat=108&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=v1xIgMFEa-sAX_NR5C9&_nc_ht=scontent-nrt1-1.xx&oh=a8dfd2ba7a9f2ddbe296f0df7eba3d4f&oe=60705F16) + +A masked language model, which is an instance of denoising auto-encoder, itself an instance of contrastive self-supervised learning. Variable y is a text segment; x is a version of the text in which some words have been masked. The network is trained to reconstruct the uncorrupted text. + +As we pointed out earlier, a predictive architecture of this type can produce only a single prediction for a given input. Since the model must be able to predict multiple possible outcomes, the prediction is not a single set of words but a series of scores for every word in the vocabulary for each missing word location. + +But we cannot use this trick for images because we cannot enumerate all possible images. Is there a solution to this problem? The short answer is no. There are interesting ideas in this direction, but they have not yet led to results that are as good as joint embedding architectures. One interesting avenue is latent-variable predictive architectures. + +![https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/151779454_861787841053485_9032472471565149785_n.jpg?_nc_cat=106&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=cc4pkqqvFtsAX_GIs3Z&_nc_ht=scontent-nrt1-1.xx&oh=b5891bcaaf377ef489d8f486030ae8a7&oe=606F3303](https://scontent-nrt1-1.xx.fbcdn.net/v/t39.2365-6/151779454_861787841053485_9032472471565149785_n.jpg?_nc_cat=106&ccb=1-3&_nc_sid=ad8a9d&_nc_ohc=cc4pkqqvFtsAX_GIs3Z&_nc_ht=scontent-nrt1-1.xx&oh=b5891bcaaf377ef489d8f486030ae8a7&oe=606F3303) + +A latent-variable predictive architecture. Given an observation x, the model must be able to produce a set of multiple compatible predictions symbolized by an S-shaped ribbon in the diagram. As the latent variable z varies within a set, symbolized by a gray square, the output varies over the set of plausible predictions. + +Latent-variable predictive models contain an extra input variable (z). It is called latent because its value is never observed. With a properly trained model, as the latent variable varies over a given set, the output prediction varies over the set of plausible predictions compatible with the input x. + +Latent-variable models can be trained with contrastive methods. A good example of this is a generative adversarial network (GAN). The critic (or discriminator) can be seen as computing an energy indicating whether the input y looks good. The generator network is trained to produce contrastive samples to which the critic is trained to associate high energy. + +But contrastive methods have a major issue: They are very inefficient to train. In high-dimensional spaces such as images, there are many ways one image can be different from another. Finding a set of contrastive images that cover all the ways they can differ from a given image is a nearly impossible task. To paraphrase Leo Tolstoy’s Anna Karenina: “Happy families are all alike; every unhappy family is unhappy in its own way.” This applies to any family of high-dimensional objects, it seems. + +What if it were possible to make sure the energy of incompatible pairs is higher than that of compatible pairs without explicitly pushing up on the energy of many incompatible pairs? + +## Non-contrastive energy-based SSL + +Non-contrastive methods applied to joint embedding architectures is possibly the hottest topic in SSL for vision at the moment. The domain is still largely unexplored, but it seems very promising. + +Non-contrastive methods for joint-embedding include [DeeperCluster](https://l.facebook.com/l.php?u=https%3A%2F%2Fopenaccess.thecvf.com%2Fcontent_ICCV_2019%2Fhtml%2FCaron_Unsupervised_Pre-Training_of_Image_Features_on_Non-Curated_Data_ICCV_2019_paper.html&h=AT0lGsUnkJuqLTGwf4IilXCQSdkXDxkc-1tIlVMywb1TiAOI7QgaGHpt-LgYZaLGn6Z0JdGe6cklqw-gugrOTjTI0U8mX5DFVGUiITHDjojotorDRkA2BX5GxTtN0qzXdpOnpidbEFy9d7-6EqTgDRosBe8), [ClusterFit](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F1912.03330&h=AT2gErfIVKIz0AQJmisT_3vzLwebVKnwEf7Jmb4BSdXt8oQCNlL6JseM3BAWk8G-oawbQQcddUvVcpGpAFJ2xBLSlpgeb8QsbuQFlQ1JRJBvXNTUjbiB7F1kJGLbvfZpE62uGKXvKR9MmWbhGTGJIMmg_zk), [MoCo-v2](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F2003.04297&h=AT13BN44Ili715bIZ-9ERSdFXfElNdexuWjDCQCtNHFjX83ViV0ktfsmVBLJ4_XkKDgGxa7RxVg5crNtQwYOzcT5ImrkCTGxcb6cp532z0cZ1K2-0gO4kybzXNrVzlA7ntRT2ue0oJx4LXWw24nJgEm9o6k), [SwAV](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F2006.09882&h=AT34EtJlZPzlYoVFNt3HGYT0L7i4P2er5UNiuS7vW1J9s4nRsU-Ly5EEtd6scF5DMI2rgqzdxsFzcXR71mifQHgL3VuKGNZjQ_oLoy9h8cjcm3WKVzUynb6Rf1rVsOYhuC1K7w9OVILn1IIqbo3AaduhJNGgbrY714pzCFCF), [SimSiam](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F2011.10566&h=AT1EbBeittVqlUaApLvyl-pgmbHZO46cMCbSlKw2bPwqI1My4L5cj401n8A9NrIo5-0o8rRLosPZV2b4qexouK7xrjGeKkVrYYnLoihnaVURkx0i_kyixZWaVYNrhp1ItNjXjUizgfC73NbIR4bXFNeIuqM), Barlow Twins, [BYOL](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F2006.07733&h=AT3bB9uJ-JmvSJl0lumFLkSdhJFmnbM7IlIFd5Aufs1U8H0MIQqPjgGJtPqUPfYYVh2WB6p5xkRASQpWcrLQicLAvFykWvcu_25bkTNYw6pJ4nj2Qx-6yXTQ1WujDha060x0moKHhb34cqarvQusxKGSxE4) from DeepMind, and a few others. They use various tricks, such as computing virtual target embeddings for groups of similar images (DeeperCluster, SwAV, SimSiam) or making the two joint embedding architectures slightly different through the architecture or the parameter vector (BYOL, MoCo). Barlow Twins tries to minimize the redundancy between the individual components of the embedding vectors. + +Perhaps a better alternative in the long run will be to devise non-contrastive methods with latent-variable predictive models. The main obstacle is that they require a way to minimize the capacity of the latent variable. The volume of the set over which the latent variable can vary limits the volume of outputs that take low energy. By minimizing this volume, one automatically shapes the energy in the right way. + +A successful example of such a method is the [Variational Auto-Encoder](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fabs%2F1312.6114&h=AT0LSo74Ry4dVnWT2ib7xuKHKfBG3vK4p02VWz4HwBBVlrE054Cd-pQNiVseCTqrtZH-6-35ystyZ83lX60u5x_l0WwluR6SN2SqtwULMnog76bHo0vbVUGUbldzTD1d0dNqRKLt5mLw2bbmkYsDqgOrWRw) (VAE), in which the latent variable is made “fuzzy”, which limits its capacity. But VAE have not yet been shown to produce good representations for downstream visual tasks. Another successful example is [sparse modeling](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.nature.com%2Farticles%2F381607a0&h=AT3bvD2Vlvu0QQIkeY1fbGP4hURuEYRC4g59AjajqLOOiMeBz9GPfbx1z-rTvqSUJSDANOozRNa3JG2wFNrYPGf2dbdq3c9ixxqJiJxxehwUqnCh3MlKSVWzM9Gjj2XZshO0au6qN7ZGgASzNwJ_9b9osuw), but its use has been limited to simple architectures. No perfect recipe seems to exist to limit the capacity of latent variables. + +The challenge of the next few years may be to devise non-contrastive methods for latent-variable energy-based model that successfully produce good representations of image, video, speech, and other signals and yield top performance in downstream supervised tasks without requiring large amounts of labeled data. + +## Advancing self-supervised learning for vision + +Most recently, we’ve [created and open sourced](https://ai.facebook.com/blog/seer-the-start-of-a-more-powerful-flexible-and-accessible-era-for-computer-vision) a new billion-parameter self-supervised CV model called SEER that’s proven to work efficiently with complex, high-dimensional image data. It is based on the SwAV method applied to a convolutional network architecture (ConvNet) and can be trained from a vast number of random images without any metadata or annotations. The ConvNet is large enough to capture and learn every visual concept from this large and complex data. After pretraining on a billion random, unlabeled and uncurated public Instagram images, and supervised fine-tuning on ImageNet, [SEER outperformed the most advanced, state-of-the-art self-supervised systems, reaching 84.2 percent top-1 accuracy on ImageNet](https://l.facebook.com/l.php?u=https%3A%2F%2Farxiv.org%2Fpdf%2F2103.01988.pdf%3Ffbclid%3DIwAR2pqhYda6MV9r2b3Afx_0eKUiZhX-Es6Pa_FbLOqH8fglQzO2kY3yKxZE8&h=AT3oeBOnOiEqqnEhqdnng6gu8m4PZCAqD8mJmSaAt5NAzKWqb25TUfoKCWxSHENUx8xHNVOBsQ2UO1Rz-L_Bc5tVudMuhjoWVWbRUL4ccNvlY9t5Bx_hRmw_M55y79apxax_j8yoTXA2GFqQDx1zFnp1pFg). + +These results show that we can bring the self-supervised learning paradigm shift to computer vision. + +## Using self-supervised learning at Facebook + +At Facebook, we’re not just advancing self-supervised learning techniques [across many domains](https://ai.facebook.com/blog/advances-in-content-understanding-self-supervision-to-protect-people/) through fundamental, [open scientific research](https://ai.facebook.com/blog/advances-in-content-understanding-self-supervision-to-protect-people/), but we’re also applying this leading-edge work in production to quickly improve the accuracy of content understanding systems in our products that keep people safe on our platforms. + +Self-supervision research, like our pretrained language model [XLM](https://l.facebook.com/l.php?u=https%3A%2F%2Fgithub.com%2Ffacebookresearch%2FXLM%3Ffbclid%3DIwAR2Gqz_1SBcEXAVowtEOqRvN9Iveaci6Jwdvdy8yHDnlyjnfm91ZDREK6Rs&h=AT0eYnZVx3prg4YHeL22pV7-dw9V2CFxQ08Es75A1aWt8aCDBuMjYbWLUs0j04C6Teizxz5z44yBS9O-JhKCtLkvwIlm4rOWE9NKNV75w5y46BYgpFn3VYNO0NbMlOh6tFUIgbDkjbufFeXjbmlV51ZZUEI), is accelerating important applications at Facebook today — including [proactive detection of hate speech](https://ai.facebook.com/blog/how-ai-is-getting-better-at-detecting-hate-speech/). And we’ve deployed [XLM-R](https://ai.facebook.com/blog/-xlm-r-state-of-the-art-cross-lingual-understanding-through-self-supervision/), a model that leverages our [RoBERTa](https://ai.facebook.com/blog/roberta-an-optimized-method-for-pretraining-self-supervised-nlp-systems/) architecture, to improve our hate speech classifiers in multiple languages across Facebook and Instagram.This will enable hate speech detection even in languages for which there is very little training data. + +We’re encouraged by the progress of self-supervision in recent years, though there’s still a long way to go until this method can help us uncover the dark matter of AI intelligence. Self-supervision is one step on the path to human-level intelligence, but there are surely many steps that lie behind this one. Long-term progress will be cumulative. That’s why we’re committed to working collaboratively with the broader AI community to achieve our goal of, one day, building machines with human-level intelligence. Our research has been made publicly available and published at top conferences. And we’ve organized workshops and released libraries to help accelerate the research in this area. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/serverless-where-is-the-industry-going-in-2021.md b/article/2021/serverless-where-is-the-industry-going-in-2021.md new file mode 100644 index 00000000000..e8ca4795b4c --- /dev/null +++ b/article/2021/serverless-where-is-the-industry-going-in-2021.md @@ -0,0 +1,69 @@ +> * 原文地址:[Serverless: Where Is the Industry Going in 2021?](https://dzone.com/articles/serverless-where-is-the-industry-going-in-2021) +> * 原文作者:Suresh Kumar +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/serverless-where-is-the-industry-going-in-2021.md](https://github.com/xitu/gold-miner/blob/master/article/2021/serverless-where-is-the-industry-going-in-2021.md) +> * 译者: +> * 校对者: + +# Serverless: Where Is the Industry Going in 2021? + +> In this article, we discuss what it means to be considered Serverless, how companies are adopting this trend, and where the industry is advancing in 2021. + +## Introduction + +Serverless computing is a style of developing software on cloud platforms that frees developers of the complexities of code deployment, infrastructure provisioning, and availability management of the code in the cloud.  Amazon popularized this with Lambda in 2014.  Since then, all the cloud vendors have followed suit with similar capabilities, Azure Functions, and Google Cloud Functions. + +In the same way that developers had to worry about bare metal servers before virtualization came around, developers didn’t need to worry specifically about virtual machines with the advent of containers.  Similarly, developers don’t need to worry about containers with the increasing interest in serverless computing—the new paradigm for getting code developed, deployed, and executed. + +## Serverless Definition + +There are many definitions of serverless—some definitions talk about Functions as a Service (FaaS) and the other definitions relate to Backend Services (BaaS) whether they are database (DBaaS) or Security services.  They both share similar characteristics to abstract to a platform or a functional layer using an execution or consumption-based cost model. + +Most of the serverless interest is in Function as a Service; this should not be misunderstood to mean functional programming, in fact, most of the Cloud providers do not provide major support for functional programming.  What then characterizes Function as a Service? + +1. **Writing the code** — A developer can write whatever code they want and have it executed within a FaaS environment with minimal change. The code will have a message handler which is the main method that acts as the listener interface. + +2. **Deploying the code** — It's literally a copy-and-paste into the FaaS console for that specific function. Although most IDE also supports FaaS integration. + +3. **Scaling the code** — It is the responsibility of the FaaS runtime to scale as many instances as necessary. Cluster management technologies like Kubernetes, if used, are abstracted.* + +4. **Executing the code** — FaaS are suitable for event-driven architectures as the code runs when it receives an event or a trigger. This can be an HTTP request, a file being sent, or a message arriving on a message queue, etc.  + +5. **Short running** — FaaS are ephemeral and not long-running, therefore they do not hold any state. It is the responsibility of the developer to persist in any state outside the function. + +6. **Cost execution** — FaaS is charged for the duration of execution. This is where FaaS differs from BaaS; for example, Google BigQuery would charge the amount of data scanned or SQS would charge per API call. Code that runs for too long or doesn’t receive a request will eventually time out. + +## Latency Challenges + +![https://dzone.com/storage/temp/14502652-picture-1.png](https://dzone.com/storage/temp/14502652-picture-1.png) + +When an event is triggered there is an amount of time for the FaaS function to be initialized before it can be executed. This can be the cold-start-time or the warm-start time of the VM running the code. + +## Language and Memory Challenges + +The latency of your FaaS code can vary from milliseconds to seconds and the choice of language and the amount of memory allocated can have a big difference; for example from a recent AWS re:Invent, talk they showed how cold start time was significantly higher using Springboot to Java and how increasing memory allocation from 1Mb to 3Mb could reduce that further.  But using node frameworks had a 100x lower cold start-up time regardless of memory allocation.  Thus, showing node as a popular language for serverless. In summary Python or Node is faster. + +### Why Is This Not a Problem Today? + +In recent years a lot has been said about the performance concerns regarding serverless computing lending them for certain use cases over others; for example, Serverless could greatly benefit from traditional Web and API serving compared to something like low latency IoT applications.  Concerns about latency and cold and warm start-up times and performance characteristics of different language frameworks have also been stated. + +- **Cloud Vendors are optimizing:**  All of the major cloud providers are putting significant effort into Serverless plumbing to optimize the cold-start times which means that through a number of measures (including predictive scheduling, optimization of language runtimes, native forked processes) that these concerns will be resolved. + +- **Developers can optimize too:**  For developers there are a number of strategies that they are in control of like, increasing memory allocation, choosing a faster language runtime, keeping shared data in memory, shrinking the package size, keeping a pool of pre-warmed functions (also known as provisioned concurrency), all of which addresses most concerns. + +### Where Is the Industry Going? + +> Forrester predicts “25% of developers will use serverless and nearly 30% will use containers regularly by the end of 2021." + +Serverless is moving beyond just Compute to really make it easy to provision Database on Serverless too. Amazon announced at AWS re:Invent 2020 that Aurora Serverless v2 will scale MySQL and PostgresSQL to Petabyte scale with full support for Multi-AZ, Global database with Read Replicas, backtrack, and Parallel Query. AWS is not standing still they announced that you can package and deploy Lambda serverless functions using containers, thus making it much easier for developers who have existing automated pipelines—this all helps to reduces the friction for developer adoption. + +Many enterprises have adopted Kubernetes as a common platform for the deployment of their containers and this has not been an easy journey for many putting additional pressure on developers and operations teams.  Very few enterprises need the scale and complexity of Kubernetes (EKS) and the market has realized that with alternative options in the marketplace like Elastic Container Service (ECS), which is cheaper and easier to deploy, couple that with something like Fargate for Serverless then developers don’t even need to worry about provisioning their EC2 instances.  The equivalent of ECS Fargate is Google Cloud Run and Azure for Anthos. + +Despite cloud vendors trying to simplify container management in the cloud the trend and direction are clear to higher levels of abstraction where the developers can focus on the code rather than the complexities of deploying nodes, pods, or virtual machines. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 + diff --git a/article/2021/should-you-compile-your-javascript-code.md b/article/2021/should-you-compile-your-javascript-code.md new file mode 100644 index 00000000000..65ee8508952 --- /dev/null +++ b/article/2021/should-you-compile-your-javascript-code.md @@ -0,0 +1,119 @@ +> * 原文地址:[Should You Compile Your JavaScript Code?](https://blog.bitsrc.io/should-you-compile-your-javascript-code-a857ad2e3032) +> * 原文作者:[Fernando Doglio](https://medium.com/@deleteman123) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/should-you-compile-your-javascript-code.md](https://github.com/xitu/gold-miner/blob/master/article/2021/should-you-compile-your-javascript-code.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[Ashira97](https://github.com/Ashira97) + +# 你应该编译你的 JavaScript 代码吗? + +![Image by [seznandy](https://pixabay.com/users/seznandy-15803435/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=5093898) from [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=5093898)](https://cdn-images-1.medium.com/max/3840/1*_7N-LnDFVgKcgEgzczZVmg.jpeg) + +我们都会也都喜爱 JavaScript,并且我们都通过编写代码和在我们最爱的运行环境(通常是浏览器,Node.js 和 Deno)中来执行 JavaScript 代码。但你是否曾经尝试过去编译你的 JavaScript 代码呢? + +不对,等一下,我们都知道 JavaScript 是一门动态语言啊!其实它同样也会被解析,但是与常见的运行时大不相同,它是会在运行时被一个 [JIT 编译器](https://blog.bitsrc.io/the-jit-in-javascript-just-in-time-compiler-798b66e44143)优化的。 + +这可是事实! + +但它能够被编译吗?这两个问题可不搭边呢!在运行之前编译一款动态语言(或称为 AOT,运行前编译)是可能的,这是当然的。但我们真的值得去这样做吗? + +## AOT vs JIT + +**首先让我们再走进 AOT 和 JIT(要不然这文章也太短太水了。当然其实还有别的相关的能够帮助你的内容可能会被你所找到)** + +AOT 和 JIT 最主要的区别是它们所作用的时间。AOT 是在你的代码的执行之前运行的,而 JIT 是与你的代码的执行同时进行的。还有什么不同吗? + +几乎全都不同啊! + +AOT 通常是为那些静态语言所使用的,因为对于他们而言,没有什么需要在运行时判断和决定的动态行为。所有的规则都已经摆在代码中了,编译器可以很简单地阅读这些内容,明白其中的数据流并且有针对性的对其进行优化,并同时将这些代码转译为原生的解析语言(也叫做机器指令). + +JIT 呢,则是与之相对,一般用于动态语言,因为它会侦测代码的执行并且基于它所控制的数据的类型,会对其优化并创造一个更好的机器指令。 + +如果让我们来就这些实时优化来考虑编译代码的进行优化的时间吧,AOT 会在一开始就为你提供一份最优化的代码,而你会直接执行这一份最优化的代码。但对于 JIT 而言,他会在代码运行过程中先耗费一段时间去计算分析这段代码,但会在潜在地在代码的后续执行中能够因为[这个原因](https://blog.bitsrc.io/the-jit-in-javascript-just-in-time-compiler-798b66e44143)更多地节省和优化。它有更多去优化的角度,而不仅仅只是针对于类型定义上(例如函数的调用就只能在运行时优化)。 + +对于每一种方案当然都有它们的优劣,但如果你想要概述并决定其中之一,我大概会说: + +* 如果你的代码只需要运行短时间,那就用 AOT 吧。 +* 如果你的代码会运行地比较长时间,那么就用 JIT 吧,这样可以让你的代码在一些运行时分析后获得更好的优化。 + +## 那么对于编译你的 JavaScript ? + +同样的,为什么 JavaScript 是被解析并且 JIT 并不能直接去编译 JavaScript 为机器代码的原因:JavaScript 的动态功能让它在实时编译中更占优势。 + +但需要注意的是,我并没有提及 [WebAssembly](https://blog.bitsrc.io/whats-wrong-with-web-assembly-3b9abb671ec2) 。事实上在哪些情况下,WASM 将所有代码(C、C++ 或别的什么语言的代码)编译为一个 JavaScript 运行时兼容的原生代码。这与编译 JavaScript 可不是一个东西。 + +事实上,并没有那么多项目正在尝试去编译 JavaScript 代码为机器指令,因为我可以确定这是个很大的挑战 —— 我指的是,例如让我们编译下面的代码: + +```js +let result = null; +if (my_complex_function()) { + result = 10; +} else { + result = "something else"; +} +console.log("The result is " + result); +``` + +你真的在运行之前能够判定 `result` 变量的类型吗?你可能需要先在心中思考一下所有可能的类型,并且同时将不同的情况判断一遍。即便你解决了这个问题,你依旧添加了不少的逻辑到你的思考与判断之中。这听起来可并不那么好啊! + +事实上,有一个专门解决这个问题的项目,尽管不一定是最佳的(至少在纸面上):[NectarJS](https://github.com/NectarJS/nectarjs) + +## 通过使用 NectarJS 进行编译 + +该项目旨在将 JavaScript 代码编译为机器指令,以便让我们可以在任何兼容的平台上运行它。现在,兼容的名单包括了 Windows、Linux、Arduino、[STM32 Nucleo](https://www.st.comenevaluation-toolsstm32-nucleo-boards.html)、Android、Web([WASM](https://www.st.com/en/evaluation-tools/stm32-nucleo-boards.html), Android, Web ([WASM](https://blog.bitsrc.io/whats-wrong-with-web-assembly-3b9abb671ec2))、macOS 和 SunOS。 + +虽说实际上上述所有的平台基本上都有对应的,用于运行你的 JavaScript 代码的解析器,这个项目能够让最终的编译输出一个比当前可用编译器输出的更优化的一个输出。 + +针对它们输出的结果而言,它们早已对 Windows 上 Node.js 的 v12 有了一些优化。在某些情况下并不是提升速度,而是内存的使用甚至是输出文件的大小。 + +![NectarJS’ 网站上的一份表格](https://cdn-images-1.medium.com/max/3036/1*HyX7ShDvXey6u9mo9_3ezg.png) + +当然,该项目仍然有其局限性,特别是到目前为止,该项目仅支持大约 80% 的 ES3 标准,这意味着您可以编写的 JavaScript 代码是非常有限且不符合当今的标准的。 + +但是,对于你的某些项目而言你并不一定要编写兼容 ES6 的代码。而且能够去编译这些代码,并原生地在你的 Arduino 开发板上面运行这些代码,可能真的会是非常好用的 + +但是话又说回来,对于特定项目而言,你可能并不需要在其中编写兼容 ES6 的代码,并且在对其进行编译并在 Arduino 板上本地运行这段代码的情况下它可能会派上用场。 + +#### 安装并测试 NectarJS + +这个项目可以直接以一个 NPM 模块的形式被安装到你的计算机,所以你所需要做的仅仅是运行下面这行代码(这里默认了你已经安装了 Node 环境): + +``` + +$ npm install nectarjs -g + +``` + +在安装并同时设置或导入了[必要的依赖](https://github.com/NectarJS/nectarjs/blob/master/docs/ADVANCED_USAGE.md#requirements-and-compilation)以后,你就可以简单的编写一段 HelloWorld 代码并编译这段代码: + +```JavaScript +console.log("Hello 编译过的 world!") +``` + +要去编译这段代码,简简单单的使用这段指令即可: + +``` +$ nectar your-file.js +``` + +这就是我在我的 macOS 系统上能够获得的输出: + +![](https://cdn-images-1.medium.com/max/2028/1*7i_ihlwJ8Kx49n7v3wrePw.png) + +需要注意的是,被创建的文件并没有一个拓展名 —— 它是一个二进制文件。如果你给予它执行的权限,你就能够执行这段代码。这很简单,并且它能够正常工作。 + +--- + +## 这就是 JavaScript 的未来吗? + +就我个人而言我不会为之打赌。这个项目本身也还在初期,拥有着不完善的文档,并且只有对旧语言的部分支持。但是,它目前正处于活跃的开发状态并且这些可以在快速地变化。 + +对于编译 JavaScript 做法的推广,我并不认为会是一个很大的趋势,毕竟事实证明了,现有的运行时已经足以满足最常见的使用情况。对于希望拥有原生性能并且不愿意切换到其他技术的朋友来说,编译 JavaScript 真的有用吗?这当然有用,但这只是 JavaScript 广泛用途的其中一种情况。 + +你会考虑编译你的 JavaScript 代码吗?发表一下你的看法吧! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/staggered-animation-in-flutter.md b/article/2021/staggered-animation-in-flutter.md new file mode 100644 index 00000000000..fc53f181751 --- /dev/null +++ b/article/2021/staggered-animation-in-flutter.md @@ -0,0 +1,217 @@ +> * 原文地址:[Staggered Animation In Flutter](https://medium.com/flutterdevs/staggered-animation-in-flutter-e7282a936b99) +> * 原文作者:[Shaiq khan](https://medium.com/@shaiq_khan) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/staggered-animation-in-flutter.md](https://github.com/xitu/gold-miner/blob/master/article/2021/staggered-animation-in-flutter.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[lsvih](https://github.com/lsvih) + +# Flutter 中的交织动画 + +![Flutter 中的交织动画](https://cdn-images-1.medium.com/max/2000/1*icYuiagsCKqcRapvjiLbmw.png) + +交织动画由一个动画序列或重叠的动画组成,而要制作交织的动画,我们需要使用多个或多组动画对象。我们应该使用同一个 `AnimationController` 控制所有动画,每个动画对象都应该指定某个点或锚点在一段时间内的运动,并且对于要执行的动画的每个属性,我们都应该创建一个补间(`Tween`)。 + +所谓交织动画,直接来说就是:并非在同一时刻发生全部的视觉变化,而是让其随着任务的进行逐步发生。这个动画可能纯粹只是一个顺序动画,视觉上的变化一个接一个的出现;也可能有部分的动画重叠出现,乃至完全重叠。当然,交织动画的动画中同样可能会有一些时刻空着,即在一些间隙中没有发生任何动画。 + +[**这里是一段有关交织动画的样例视频**](https://youtu.be/0fFvnZemmh8) + +在这个视频中,你可以看到发生在一控件上,从一个带边框而略微有圆角的蓝色矩形的出现开始的动画。这个矩形会按照以下顺序变化: + +* 淡入 +* 水平上变宽 +* 向上移动同时竖直上变得更高 +* 变为一个有边框的圆圈 +* 颜色变为橙色 + +在顺序播放完动画后,将会反向播放上述的动画。 + +#### 交织动画的基础结构 + +* 所有的动画都是由相同同样的 `AnimationController` 控制。 +* 无论动画在现实时间中播放多长时间,控制器的值必须在 0.0 和 1.0 之间,包括 0.0 和 1.0。 +* 每个动画都有一个 `Interval`,这个值必须在 0.0 和 1.0 之间,包括 0.0 和 1.0。 +* 对于每一个间隔内产生动画的属性,创建一个 `Tween`。 `Tween` 指定此属性的开始值和结束值。 +* `Tween` 产生一个由动画控制器管理的 `Animation` 对象。 + +#### 要设置这样一个动画 + +* 创建一个 `AnimationController` 管理所有的 `Animations`。 +* 为每一个有动画的属性创建一个 `Tween`。 +* 为 `Tween` 设置不同的值。 +* `Tween` 的 `animate()` 方法需要一个 `AnimationController` 来用这些属性生成一个动画。 +* 通过修改 `Animation` 构造器中的 `curve` 属性指定动画的间隔时间 + +**如何在 Flutter 中使用交织动画:** + +下面的代码为 avatarSize 这一属性定义了一个补间动画。它构造了一个 [**CurvedAnimation**](https://api.flutter.cn/flutter/animation/CurvedAnimation-class.html) 动画类并且指定了动画曲线为一条 elasticOut 曲线。要查看更多的预设动画曲线,请访问网页 [**Curves**](https://api.flutter.cn/flutter/animation/Curves-class.html) 。 + +```dart +avatarSize = Tween( + begin: 50.0, + end: 150.0, +).animate( + CurvedAnimation( + parent: controller, + curve: Interval( + 0.125, 0.250, + curve: Curves.elasticOut, + ), + ), +), +``` + +> `AnimationController` 和 `Animation` 定义了类 `AnimationController` 的实例 +> 以下是 `AnimateController` 以及 5 个用于控制动画的进展的 `Animation` 的实例,其中 `` 用于获取一个用于定义动画过程的数值,该数值必须在 0 到 1 之间。 + +```dart +final AnimationController controller; +final Animation barHeight; +final Animation avatarSize; +final Animation titleOpacity; +final Animation textOpacity; +final Animation imageOpacity; +``` + +> 我们应该在控件的定义中覆写 `initState` 方法以在其中完成对 `AnimationController` 的初始化,在定义语句中,我们实际是在设置动画的参数。下面的例子我们将动画时长设置为 3 秒。 + +```dart +// 译者注:代码从 Flutter 库中截取,路径 /lib/src/animation/animation_controller.dart:150 +@override +void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, // 对 SingleTickerProviderStateMixin 的引用 + duration: widget.duration, + ); +} +``` + +**如何在代码中实现:** + +你需要在代码中实现以下内容: + +* 添加一个 `StatefulWidget` (带有状态的)控件 +* 然后将这个控件与 `SingleTickerProviderStateMixin` Mixin,以让 `AnimationController` 确定它的动画时长为 3500 毫秒。 + +控制器将会播放一个动画,然后会在 widget 树上创建一个无动画的部分。当在屏幕上检测到点击事件时,开始播放动画。动画一开始会顺序播放,然后会倒序播放。 + +```Dart +import 'package:flutter/material.dart'; +import 'package:stag_animation/trekking/staggered_trekking.dart'; + +class StaggeredTrekkingAnimation extends StatefulWidget { + @override + _StaggeredTrekkingAnimationState createState() => + _StaggeredTrekkingAnimationState(); +} + +class _StaggeredTrekkingAnimationState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(milliseconds: 3500), + vsync: this, + ); + _controller.forward(); + } + + Future _playAnimation() async { + try { + await _controller.forward().orCancel; + await _controller.reverse().orCancel; + } on TickerCanceled { + // 这个动画被暂停了,可能因为该控件被 dispose 了。 + } + } + + @override + void dispose() { + super.dispose(); + _controller.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + _playAnimation(); + }, + child: StaggeredTrekking( + controller: _controller, + ), + ); + } +} +``` + +在 Staggered Trekking Enter 动画中,我们使用了补间去决定动画的进展。 + +接下来,你会完成一个无状态的控件的 [Staggered Trekking 动画](https://github.com/ShaiqAhmedkhan/Flutter_Staggered_Animation/blob/master/lib/trekking/staggered_trekking.dart)。我们会用 `build()` 函数为这个控件的动画初始化定义一个 [**AnimatedBuilder**](https://api.flutter.cn/flutter/widgets/AnimatedBuilder-class.html)。同时,我们需要创建一个名为 `_buildAnimation()` 的函数,负责更新用户界面,并将其分配给 `builder` 属性. + +```Dart +import 'package:flutter/material.dart'; + +class StaggeredTrekkingEnterAnimation { + StaggeredTrekkingEnterAnimation(this.controller) + : barHeight = Tween(begin: 0, end: 150).animate( + CurvedAnimation( + parent: controller, + curve: Interval(0, 0.3, curve: Curves.easeIn), + ), + ), + avatarSize = Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: controller, + curve: Interval(0.3, 0.6, curve: Curves.elasticOut), + ), + ), + titleOpacity = Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: controller, + curve: Interval(0.6, 0.65, curve: Curves.easeIn), + ), + ), + textOpacity = Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: controller, + curve: Interval(0.65, 0.8, curve: Curves.easeIn), + ), + ), + imageOpacity = Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: controller, + curve: Interval(0.8, 0.99, curve: Curves.easeIn), + ), + ); + + final AnimationController controller; + final Animation barHeight; + final Animation avatarSize; + final Animation titleOpacity; + final Animation textOpacity; + final Animation imageOpacity; +} +``` + +`AnimatedBuilder` 将侦听来自动画控制器的通知,然后会标记该控件的值的改变。对于动画的每一帧,这些值会因为调用 `_buildAnimation()` 而都被更新。 + +在下面发布的视频中,你将看到交织动画的工作方式。当你在屏幕上的任意位置点击时,它将启动动画并在向前播放动画之后自动向后播放动画。在这代码中,你还可以控制动画播放的速度。 + +![](https://cdn-images-1.medium.com/max/2000/1*vQm1tBYamr7UZSaoApsAdg.gif) + +这就是交织动画的基本示例。在这里我们做了一个简单的示例,你可以尝试学习它。 + +**单击下面的 GitHub 链接以找到交织动画的源代码:** + +[**flutter-devs/Flutter-StaggeredAnimation**](https://github.com/flutter-devs/Flutter-StaggeredAnimation) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast.md b/article/2021/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast.md new file mode 100644 index 00000000000..95a8b5dddc9 --- /dev/null +++ b/article/2021/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast.md @@ -0,0 +1,96 @@ +> * 原文地址:[System Design Interview: All or None, Ordered Peer-to-Peer Broadcast](https://levelup.gitconnected.com/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast-45b33fb2f6be) +> * 原文作者:[Eileen Pangu](https://medium.com/@eileen-code4fun) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast.md](https://github.com/xitu/gold-miner/blob/master/article/2021/system-design-interview-all-or-none-ordered-peer-to-peer-broadcast.md) +> * 译者: +> * 校对者: + +# System Design Interview: All or None, Ordered Peer-to-Peer Broadcast + +## Prologue + +Let me state upfront, this is not an easy system design interview question. If you don’t have a good understanding of distributed systems, you may not even know where to start. It’s no doubt difficult. But unless you’re in a domain specific interview, chances are that the interviewer probably just wants to test your ability of navigating complex system design problems. So I’m hoping to present exactly that — working through this question bit by bit and see how far we’d get. In the end, we’ll not only arrive at some solutions, but also practice problem solving in the context of system design interviews. By the way, if you’re interested in more system design interviews, I have some other [blog posts](https://github.com/eileen-code4fun/SystemDesignInterviews) that you can check out. + +## Reframe The Question + +To frame this question a bit better, consider what problem we’re trying to solve. It’s a peer-to-peer message broadcast system. Usually when we say broadcast, we tend to only think about the sending end. However, that’s not enough here. The network could drop and delay messages. Machines (using “nodes” thereinafter just to be idiomatic) could crash. If we control only the sending end, it’s impossible to guarantee the desired “all or none” and “ordered” delivery semantics. So we have to control the receiving end as well. + +A better way to think about this problem is to imagine building a communication middleware. The middleware hides the complexity of retrying, deduping, ordering, and peer coordination behind a simple interface, providing a communication abstraction to the upper layer application. Whenever the upper layer application wants to broadcast a message to all peers, it invokes a `broadcast` method in the middleware, which in turn transmits the message to the peers and make sure they get it. When the middleware receives a message, it does whatever necessary to preserve the delivery semantics, and then invokes a `deliver` callback submit the message to the upper layer application. + +That turns the question into building a communication middleware which runs on all nodes, exposes the `broadcast` and `deliver` interface, and provides the delivery semantics guarantees. In a system design interview, we need to confirm with the interviewer to see if we can proceed with this question reframing. Here we assume the interviewer approves, and we’ll move on to discuss the delivery semantics. + +## “All or None” Delivery Semantics + +### The Definition of “All or None” + +We need to elaborate on what we mean by “all or none” first: if a message is delivered by any node, we want it to be delivered by all correct nodes. Notice that we call out the “all or none” requirement only for nodes being “correct”, which, in the context of distributed systems, essentially means they haven’t crashed. + +It’s worth highlighting that “all or none” is a form of atomicity. A message is either not delivered by anyone, or is delivered by all nodes eventually. A variance of “all or none” is “majority or none”. Since any node can fail at any time, and there is no reliable way to synchronously detect failure in distributed systems, we often make do with a quorum rather than insisting on “all”. The idea of quorum atomicity allows the overall system to make progress in the event of partial failure. + +### Details of the Design + +A tempting but flawed design is to have the sender retry until all (or a majority of) nodes acknowledge. This design seems valid. It does not, however, survive the crash of the sender in the middle of the broadcast. It stands to reason that we can’t rely on any single sender as they can always crash halfway, leaving the overall system in an inconsistent state. Therefore, even though one node will start the broadcast initially, every other node, upon receiving the message, should take part in helping spread the message. + +Concretely, each node keeps a record of a list of seen message IDs (constructed to be unique) so that it can tell whether an inbound message is new or seen. When a node receives a new message, it immediately resends the message to all peers. At the same time, each node maintains a mapping of `\`. When the node receives a message from a peer, it adds the peer node ID into the `acked_peer_ids` for that `message_id`. The node delivers a message once the corresponding `acked_peer_ids` grows to include all or a majority of peers. See figure-1 for an overall illustration. + +![](https://cdn-images-1.medium.com/max/2340/1*bX2e8zvGXSDjSQCU-Xzlog.png) + +**Figure-1. (a): every node got acks from all peers and thus could deliver the message. (b): node 1 crashed after sending the message to node 2. Node 2 and node 3 continued the broadcast and could deliver the message because either they relied on quorum, or they detected the crash of node 1 and thus excluded it. (c): node 1 crashed after sending the message to node 2. Node 2 crashed after sending the message to node 3. Node 3, node 4 and node 5 continued the broadcast. (d): node 1 crashed after sending the message to node 2. Node 2 crashed before sending the message out to any peer. The message was not delivered by any node.** + +Every message is first sent to all peers, which in turn resend the message to all their peers. The total number of message transmissions is `O(n²)`, assuming `n` nodes. The redundancy is needed to defend against partial failures. Readers who’re familiar with distributed systems concepts and algorithms may recognize that this is essentially the uniform reliable broadcast. + +## Variances of the Design + +A downside of this design is that every node is required to deal with sending and receiving messages to/from all other nodes. The heavy load resulting from the large fanout may be detrimental especially when `n` is large. One way to mitigate the impact is to organize the nodes into overlapping clusters so that the fanout can be constrained within cluster membership. But that comes with a lot of operational burdens. A design that’s hard to maintain probably wouldn’t impress the system design interviewer. It doesn’t hurt to mention it as an option though. + +Another option would be to send the message to a few randomly selected peers instead of all peers. This is called probabilistic broadcast. Initially, the message is only known to one node, which is the original sender. In the first round, the original sender gossips the message to `k` nodes. In the second round, each of those `k` nodes in turn gossips the message to `k` other nodes. + +This process continues. There will be wasted effort as some nodes will have already gotten the message from earlier rounds. Gossiping the message to those nodes does not increase the node coverage. In addition, since those nodes have seen the message before, they will not spread the message to others in the next round. The no spreading old messages to others is by design, otherwise the broadcast can’t terminate. + +Let’s say the expected number of nodes that get the message exactly in the `**r**th` round is `g(r)`. We have `g(0)=1`. In round `r`, each node from `g(r-1)` randomly gossips the message to `k` peers, which are sampled from the rest of `n-1` nodes. Since some of those `n-1` peers might have already seen the message, we need to discount that in the calculation. Denote `E(r)` to be the total node coverage after round `r`, `E(r)=g(0)+g(1)+…+g(r)`. It’s easy to see that for all `r>0`, g(r)=g(r-1)*k*(n-E(r-1))/(n-1). You can check that `g(1)=k`. `E(r)` approaches `n` asymptotically as `r` increases. We could continue the math and analyze the trade-off between `k` and `r` but I’d consider it beyond the scope of a typical system design interview, given that we still have other important areas to cover. + +## Bridging the Two Delivery Semantics + +We’ll leverage the “all or none / quorum” delivery semantics to develop the “ordered” delivery semantics so that the “ordered” delivery semantics doesn’t need to worry about the atomicity of the message, and can therefore focus on the ordering part of the puzzle. This layered abstraction model is a typical way of tackling problems in computer science and frankly many other disciplines. + +![](https://cdn-images-1.medium.com/max/2000/1*pIsK7air0l0o-C5rzzub4w.png) + +**Figure-2** + +As shown in figure-2, from now on, when we say “broadcast” in the “ordered” delivery semantics design, we mean invoking the `broadcast` interface in the underlying atomic delivery component. Likewise, when we say “receive” in the “ordered” delivery semantics design, we mean getting the `deliver` callback from the underlying atomic delivery component. When we say “deliver” in the “ordered” delivery semantics design, we mean actually delivering the message to the upper layer application. + +## “Ordered” Delivery Semantics + +### The Definition of “Ordered” + +Before we dive into the design, It’s important to clarify the ordering guarantee we want to support. Consider this: if one node broadcasts a message `m1`, and another node broadcasts a message `m2`, what should be the order between them? The short answer is that we don’t know. It doesn’t matter whether the broadcast of `m1` is before or after the broadcast of `m2` in the sense of absolute clock, they’re concurrent from the view of the overall system. + +There are three ways an order is considered established between two messages. Firstly, the broadcast of `m1` happens before the broadcast of `m2` on the same node. Secondly, the delivery of `m1` happens before the broadcast of `m2` on the same node. In these two cases, we say `m1` precedes `m2`. Lastly, order is transitive. So if there is a `m’` where `m1` precedes `m’`, and `m’` precedes `m2`, then `m1` precedes `m2`. This is called causal order in distributed systems. It makes intuitive sense because the broadcast of a message is likely a result of (having a causal dependency on) the broadcast or delivery of a previous message on the same node. + +### A Naive Solution + +A simple method to preserve ordering is to always piggyback the entire history of the messages broadcast or delivered by the node whenever it broadcasts a new message. This ensures that the recipient nodes will always get all the messages that precede the new message. Every recipient node will go through the received history from inception to the current, and deliver the undelivered messages in order. Clearly, this is prohibitively expensive because the history grows indefinitely and linearly over time. But no harm mentioning it to demonstrate our thought process in the interview. A quick optimization is to have each node send out acks — either individually or in batches — as they deliver messages. Upon receiving acks from all or quorum of nodes for a message, the node can prune the the message and all preceding messages in its history. This effectively garbage-collects the history as the node learns that a message has been correctly delivered by all/quorum, and therefore by induction all its preceding messages are also delivered. + +### Using Vector Clocks + +Even with the garbage-collected history, it may still be too expensive to send those past messages, not to mention the incurred cost of the additional acks. Instead, the nodes can buffer the received messages locally and use vector clocks to gate when it’s safe to deliver the messages. + +Specifically, each node `i` maintains a local vector `V` such that `V[j]` denotes the number of messages from node `j` that node `i` has delivered. When `i==j`, `V[i]` denotes the number of messages node `i` has broadcast. Whenever node `i` broadcasts a new message `m`, it always piggybacks the latest local vector `V`. Node `i` increments `V[i]` after the broadcast. When node `i` receives a message `m` from node `j`, it puts the message `m` (and the corresponding `V_m`) in a buffer. It only delivers `m` when `V_m[k]\<=V[k]` for all `k`. After `m` is delivered, node `i` increments its local `V[j]` — because it has just delivered one more message from the message sender node `j`. + +This approach may seem a bit arbitrary at first glance. We can think of it this way. Continuing on with our denotation, the sender is node `j`, the recipient is node `i`. `V_m` is the vector that comes with the message `m` from node `j`. `V` is the local vector on node `i`. Generally speaking, when `V_m[k]>V[k]`, there are messages from node `k` that the sender node `j` has already delivered but the recipient node `i` has not. There two special cases of `k`. The first case is when `k==j`: `V_m[j]>V[j]` means that the sender node `j` has previously broadcast other messages that the recipient node `i` has not yet delivered. The second case is when `k==i`: `V_m[i]` has to be already smaller than or equal to `V[i]` because `V[i]` is incremented when node `i` broadcasts a messages while `V_m[i]` is incremented when node `j` delivers that message. In conclusion, `V_m[k]` represents the number of messages from node `k` that precede the new message `m`. Therefore, the recipient node `i` needs to wait for those messages first. As node `i` delivers those preceding messages, it increments its local vector `V`. The message `m` is safe to be delivered when `V_m[k]\<=V[k]` for all `k`. See figure-3 for an example. + +![](https://cdn-images-1.medium.com/max/2102/1*Mo7NtP6DZFFgaof35XCBvA.png) + +**Figure-3. Node 3 couldn’t deliver m2 until it delivered m1 due to the vector clock condition.** + +You may wonder why we need the number broken down per node, why can’t we collapse them to a single counter on each node that stores the total number of messages preceding a new broadcast. It’s easy to construct a counter-example wherein a node keeps broadcasting new messages but never get around to deliver any message. Its local counter will eventually become sufficiently large to accept any inbound message even though the node has not deliver a single required preceding message. + +## Epilogue + +I should reiterate, unless you’re in a domain specific interview focusing on distributed systems, the interviewer is probably just challenging you to see how you tackle a complex problem. So don’t feel discouraged if you didn’t have a clue when you first saw this question. Hopefully this blog post has provided a slight bit of inspiration. For more system design interview blog posts, please refer to this [list](https://github.com/eileen-code4fun/SystemDesignInterviews). + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use.md b/article/2021/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use.md new file mode 100644 index 00000000000..dcca372f940 --- /dev/null +++ b/article/2021/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use.md @@ -0,0 +1,203 @@ +> * 原文地址:[The Dark Side of Javascript: A Look at 3 Features You Never Want to Use](https://blog.bitsrc.io/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use-83b6f0b3804b) +> * 原文作者:[Fernando Doglio](https://medium.com/@deleteman123) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use.md](https://github.com/xitu/gold-miner/blob/master/article/2021/the-dark-side-of-javascript-a-look-at-3-features-you-never-want-to-use.md) +> * 译者: +> * 校对者: + +# The Dark Side of Javascript: A Look at 3 Features You Never Want to Use + +![Image by [Free-Photos](https://pixabay.com/photos/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1081873) from [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1081873)](https://cdn-images-1.medium.com/max/3840/1*kSqZcIr9JLkFQgqwe4LEOQ.jpeg) + +JavaScript has been around for quite a while already (around 26 years) and during that time, the language has evolved, a lot. + +Most of this evolution has served a purpose, and especially in the latest iterations, the community of developers has managed to influence some of these changes, making JavaScript a very flexible and useful language. + +However, during all these years of evolution, one could say that there are some vestiges of a bygone era, features that haven’t yet been taken out but that really serve no purpose (or rather, aren’t very efficient at that) anymore. + +Here are three features of JavaScript that even if they’re still available under the runtime you’re using, you still want to avoid. + +## Void operator + +You’ve probably seen this bad boy in action at one point. Back in the day, whenever you had a link that would fire a JavaScript function when clicked, you would add `href="javascript:void(0)"` to make sure the default action wouldn’t fire. + +But what exactly did that mean? + +The `void` operator is a way to generate the `undefined` value in JavaScript. That’s right, it takes an expression, any expression, and returns `undefined` every single time. + +I know what you’re thinking: why not just use the actual `undefined` keyword, already available? Well, you see, before ECMAScript 5, the `undefined` keyword wasn’t a constant value. That’s right, you could define `undefined` which if you think about it, isn’t that something we all wanted to do at one point? + +Although of course, doing that makes no sense which is why eventually it was re-defined as a constant value, and changing it is no longer an option. However, because you could change it back in the day, `void` would allow you to access the coveted `undefined` value, even if the constant was no longer working. + +In fact, a great way to re-define the constant only for your namespace, avoiding any issues with 3rd party libraries, would be by creating your own IIFEs where one of the parameters received, was indeed, `undefined`, like this: + +```JavaScript +(function (window, undefined) { + //your logic here, where you can treat undefined as expected +})(window, void(0)) +``` + +Of course, today the `void` operator still has its uses, but they’re non-essential. For example, the best use case in today’s JavaScript is to help avoid unintended returns on single-line arrow functions. + +As you probably know, a single-line arrow function will return the result of that line, even if you don’t specifically use the `return` statement. + +```JavaScript +const double = x => x * 2; //returns the result of X times 2 + +const callAfunction = () => myFunction(); //returns what myFunction returns, even when i dont want to +``` + +Both these functions will return **something**. Clearly, for the `double` function, that’s intended, but the other one might not be, you might just want to call this function, but you’re not interested in its result value. There you can do: + +```JavaScript +const callAfunction = () => void myFunction(); //returns what myFunction returns, even when i dont want to +``` + +And that would immediately obscure the returned value and make sure your call only returns `undefined`. + +This behavior, to me, provides a minimal benefit, rendering `void` useless in this time and age of JavaScript. + +I would suggest you avoid it and let it wither into a deprecated state. + +## With statement + +This one is yet one of those constructs that JavaScript has but you’ve probably never heard about it because it’s not really promoted. In fact, even MDN’s official documentation discourages you from using it, because it can lead to very confusing code. + +You see, the `with` statement allows you to extend the scope chain for a given statement. In other words, it allows you to inject an expression into the scope of a given statement, ideally, simplifying said statement. + +Here is an example so you get what I’m awkwardly trying to say: + +```JavaScript +function greet(user) { + + with(user) { + console.log(`Hello there ${name}, how are you and your ${kids.length} kids today?`) + } +} + +greet({ + name: "Fernando", + kids: ["Brian", "Andrew"] +}) +``` + +Notice the “magic” of the `with` statement inside the `greet` function. Now this is a basic example showing the “happy path” of the expression. But let’s take a look at another case where things get a bit more complicated: + +```JavaScript +function greet(user, message) { + with(user) { + console.log(`Hey ${name}, here is a message for you: ${message}`) + } +} + +//happy path: +greet({ + name: "Fernando" +}, "You got 2 emails") + +//kinda sad path +greet({ + name: "Fernando", + message: "Unrelated message" +}, "you got email") +``` + +What do you think would be the output from that execution? + +``` +Hey Fernando, here is a message for you: You got 2 emails +Hey Fernando, here is a message for you: Unrelated message +``` + +You’ve unwillingly overwritten the second argument of your function by adding an equally named property to your object. Something, I might add, that is completely normal, since one would never expect both to be at the same scope level. However, thanks to `with` we’ve mixed both scopes and the result is not ideal. + +This is all to say, avoid `with`, while it might seem like a great way to save some keystrokes, you’ll create code that can turn very complex very fast, and mentally parsing it can be a challenge for someone else (or you, two weeks in the future). + +## Labels + +If you’re old enough (like me), you’ve experienced the hate for go-to statements in other languages such as C. That was terrible, that was a feature that made a lot of sense back in the day, but that eventually, with newer solutions to the same problem, became so obsolete and bad that it turned into an anti-pattern. + +So of course, JavaScript had to implement it. Kind of. + +A go-to statement is a way for you to place a marker **anywhere** on your code, and then jump there, from **anywhere** else. You could be jumping to the middle of a function, or inside an `IF` statement, it was like a magic portal to anywhere inside your code. I’m sure you can see how that can be a problem, it’s just too much power, too much flexibility, of course we’re going to miss use it! + +JavaScript however, implemented a similar, yet not identical construct: labels. + +A labeled statement in JavaScript is a mark you put before a statement which you can then either `break` out of or `continue`. Notice how there is no more `go-to` which is a definite plus. + +You can write something like this: + +```JavaScript +label1: { + console.log(1) + let condition = true + if(condition) { + break label1 + } + console.log(2) +} +console.log("end") +``` + +And the output would be: + +``` +1 +end +``` + +Of course, that example looks an awful lot like an `if..else` statement. And you can perfectly say that it doesn’t look that bad. However, you’re breaking from the normal flow of the code and skipping statements. If you’re aiming to do that, an `if..else` is much easier to mentally parse by others. + +The problem with labels becomes a bit more evident when we include their interaction with loops and the `continue` statement. + +```JavaScript +let i, j; + +loop1: +for(i = 0; i < 10; i++) { + loop2: + for(j = 0; j < 10; j++) { + + if(j == 3 && i == 2) { + continue loop2; + } + console.log({i, j}) + if(j % 2 == 0) { + continue loop1; + } + } +} +``` + +Can you mentally parse the above code and tell me exactly what the output will be? It’s not impossible, but it’ll take you a while. The above script will print: + +``` +{ i: 0, j: 0 } +{ i: 1, j: 0 } +{ i: 2, j: 0 } +{ i: 3, j: 0 } +{ i: 4, j: 0 } +{ i: 5, j: 0 } +{ i: 6, j: 0 } +{ i: 7, j: 0 } +{ i: 8, j: 0 } +{ i: 9, j: 0 } +``` + +Essentially, the second `if` is evaluating `true` on `0` so the `continue` statement affects the outer loop, causing it to move to the next index value, which in turn, resets the inner loop, causing it to go back to zero, and the same thing happens, over and over, ten times. The first `if` , in case you’re wondering, never gets to evaluate to `true`, because `j` never reaches any value other than `0`. + +Labels can be tricky little fellas, and even if you get them to work, they make a lot of sense from an interpreter perspective, but you should be writing code for humans, not for machines. Someone else is going to come and read it (or even you in 3 weeks), and the moment they lay eyes on the labels, they’ll hate you forever — and of course, they’ll take a lot longer to understand the basic flow of your code, but that’s a secondary problem at this point. + +## Conclusion + +I love JavaScript, don’t get me wrong, I’ve been interacting with it in different ways since I started working as a web developer 18 years ago. I’ve seen the language evolve and, like a fine wine, get better with time. However, I’d be lying if I said there aren’t some dark corners of the language where I just don’t like to get myself into. And these 3 elements show exactly that. + +The good news is that in my years of experience, I’m yet to see either `with` or labels be implemented and deployed into production. That’s not to say there aren’t cases like that, but the fact that I’ve never seen one makes me think not many code-review processes let them pass. + +How about you? Have you seen any of these constructs being used in modern-day JavaScript? + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/the-different-types-of-browser-storage.md b/article/2021/the-different-types-of-browser-storage.md new file mode 100644 index 00000000000..0e1819cecb1 --- /dev/null +++ b/article/2021/the-different-types-of-browser-storage.md @@ -0,0 +1,665 @@ +> * 原文地址:[The Different Types of Browser Storage](https://medium.com/better-programming/the-different-types-of-browser-storage-82b918cb3cf8) +> * 原文作者:[Albin Issac](https://medium.com/@techforum) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/the-different-types-of-browser-storage.md](https://github.com/xitu/gold-miner/blob/master/article/2021/the-different-types-of-browser-storage.md) +> * 译者:[flashhu](https://github.com/flashhu) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin),[k8scat](https://github.com/k8scat) + +# 不同类型的浏览器存储 + +![[@kundeleknabiegunie](http://twitter.com/kundeleknabiegunie) unsplash.com](https://cdn-images-1.medium.com/max/2000/0*6UmrGOz0O2pvmwHT) + +现代浏览器为如何在用户浏览器中存储网站数据提供了多样的选择,允许按需查询这些数据。这使得网站所有者能长期保留数据,保存网页内容或文档供离线使用,存储用户偏好,应用状态等。 + +在本教程中,我们将讨论可以在用户浏览器上存储网站数据的不同类型的浏览器存储。 + +#### 浏览器存储的使用场景 + +* 个性化网站偏好 +* 持久化站点活动 +* 存储登录状态 +* 本地保存数据和资源以便快速下载或离线使用 +* 本地保存 Web 应用生成的文档供离线使用 +* 提升网站性能 +* 减少对后端服务器的请求 + +#### 浏览器存储的类型 + +* Cookies +* 本地存储(localStorage) +* 会话存储(sessionStorage) +* IndexedDB +* Web SQL +* 缓存存储(CacheStorage) + +## Cookies + +它是在客户端存储数据的传统方法,因为在 HTML5 出现前,这是浏览器存储的唯一选择。 + +Cookie 保存客户端的数据,为网站访问者提供个性化的体验。Cookie 在服务端生成,随响应发到客户端,每次请求都会与服务器交换数据。服务器可以根据 cookie 中的数据向用户发送个性化的内容。 + +Cookie 可以通过 JavaScript 中的 `document.cookie` 被创建,更新或读取。`HTTPOnly` cookie 标志可在 JavaScript 中被用于限制 cookie 访问,从而减少一些安全隐患,如被跨站脚本读取(这类 cookie 仅供服务器端访问)。 + +#### Cookie 属性 + +``` +Set-Cookie: = +Set-Cookie: =; Expires= +Set-Cookie: =; Max-Age= +Set-Cookie: =; Domain= +Set-Cookie: =; Path= +Set-Cookie: =; Secure +Set-Cookie: =; HttpOnly + +Set-Cookie: =; SameSite=Strict +Set-Cookie: =; SameSite=Lax +Set-Cookie: =; SameSite=None; Secure + +// 也可以同时提供多个属性,例如: +Set-Cookie: =; Domain=; Secure; HttpOnly +``` + +Cookie 可分为两类:会话期 cookie 和持久性 cookie。 + +**会话期 cookie** + +会话期 cookie 不需要指定 `Expires` 或 `Max-Age` 属性,在浏览器关闭时会被移除。 + +**持久性 cookie** + +持久性 cookie 指定 `Expires` 或 `Max-Age` 属性。Cookie 不会在浏览器关闭时过期,但是会在特定的日期(`Expires`)或时间长度(`Max-Age`)过期。 + +通过在 cookie 头部中设置 `domain` 选项,某个域中的 cookie 可以访问其他子域。 + +``` +Set-Cookie: test=test-value; Domain=example.com - cookie 可用于 example.com 及子域 +``` + +#### Cookie 的局限性 + +* 只能存储 4 KB 的数据,具体限制取决于浏览器 +* 一个域下的 cookie 数量有限制,具体取决于浏览器(如 20 个) +* 跨域 cookie 的总数有限制,具体取决于浏览器(如 300 个)。一旦达到限制数量,为存储新的 cookie,最老的 cookie 将被移除。 +* Cookie 数据在每次请求时都被会发到服务器。这将消耗额外的带宽并影响性能。 +* 可能被第三方读取数据(如第三方 cookie) + +Cookie 会导致多种安全问题,因此现在建议尽可能使用现代化存储 API。 + +## Web Storage API + +Web Storage API 允许 Web 应用在用户浏览器中本地存储数据。 这个 API 已作为 HTML5 标准的一部分。 + +相比 cookie,这类存储的限制更多 —— 比如, 至少 5 MB(实际大小取决于浏览器)。这些信息只在客户端,不会和服务器共享。服务器没有任何访问权限来修改数据。 + +数据不能在域之间共享,包括子域。每个源(协议或域的组合)都将有唯一的存储空间 —— 所有 API 操作都在源对应的存储空间中执行。 + +为了在用户浏览器中存储数据,Web Storage API 提供了两个不同的对象:`sessionStorage` 和 `localStorage`。 + +#### localStorage + +`localStorage` 对象存储没有过期日期的数据。这些数据在浏览器关闭时不会被删除,而且在之后的几天、几周、几年内均可用直到被网站或用户删除。 + +#### sessionStorage + +`sessionStorage` 对象除只存储一个对话的数据外,与 `localStorage` 对象一致。 当用户关闭特定的浏览器标签页时,对应的数据会被删除。 + +Web Storage API 以键/值对形式存储数据。所有数据都存储为字符串,所有被添加到存储空间中的数据会被隐式转换为字符串类型。在查询数据时,它将类型显式转换为所需类型。`JSON.parse()` 和 `JSON.stringify()` 方法可用于序列化和反序列化对象数据。 + +```HTML + + + + Browser Storage Demos - Web Storage API + + + + + Welcome to Browser Storage Demos - Web Storage API
+ +

+ + + + + +``` + +Web Storage API 的调用是同步的,因此它们可能会影响 UI 渲染。也因为如此,我们仅应该使用 Web Storage API 存储和查询少量数据。在用户浏览器上使用 Web Storage API 存储及查询数据是便捷的 —— 所有现代浏览器都支持 Web Storage API。 + +--- + +## IndexedDB 存储 + +IndexedDB 是一个基于 JavaScript 的面向对象数据库。IndexedDB 允许你存储和查询键(主键,如 SSN)索引的对象。任何结构化克隆算法支持的对象(如:视频、图片)都可以被存储。IndexedDB 的使用比 Web Storage API 复杂得多。 + +IndexedDB 是一种在用户浏览器中持久化存储大量数据的方法。IndexedDB 允许你创建具有不用关心网络可用性这一高级功能的 Web 应用。这些应用在线、离线都可以工作。IndexedDB 对需要存储大量数据的应用及工作时不要求网络持续连通的应用而言非常有用。 + +IndexedDB API 是异步的,不会阻塞 UI 渲染。这个 API 使用索引以支持对数据的高性能搜索。 + +创建数据库模式及对象,打开数据库连接,然后在一系列事务中查询和更新数据。IndexedDB 允许存储大量结构化数据。具体大小取决于浏览器。 + +数据库对源(域/协议/端口)是私有的,因此任何网站不能访问其他网站的 IndexedDB 存储。 + +```HTML + + + + Browser Storage Demos - IndexDB API + + + + + + + + Welcome to Browser Storage Demos - IndexDB API
+ +

+ + + + + + + + +``` + +## Web SQL 数据库 + +> “Web SQL 数据库是一个用于将数据存储在数据库中的 Web API,这些数据库可以使用 SQL 的变体进行查询。” —— [维基百科](https://en.wikipedia.org/wiki/Web_SQL_Database) + +该规范基于 SQLite。Web SQL 数据库未被所有浏览器支持 —— 该标准已被 W3C 否决,IndexedDB 应该会成为替代品。 + +尽管如此,它仍可以在支持的浏览器中使用,如 Safari,Chrome,Opera 及 Edge。 + +```HTML + + + + Browser Storage Demos - Web SQL API + + + + + Welcome to Browser Storage Demos - Web SQL API
+ +

+ + + + + + + +``` + +## CacheStorage + +> “CacheStorage 是一种浏览器中的存储机制,用于存储和查询网络请求和响应。它存储一对 Request 和 Response 对象,Request 作为键,Response 作为值。” +> +> —— [Chidume Nnamdi](undefined) 的 [Bits and Pieces](https://blog.bitsrc.io/introduction-to-the-cache-storage-a-new-browser-cache-pwa-api-a5d7426a2456) 专栏 + +CacheStorage API 可以在 Window 上下文(DOM 上下文)中使用,也可以和 Service Worker API 一起使用以实现离线访问。在本教程中,我们将更多地讨论 DOM 上下文。 + +CacheStorage 用于在网站中存储网络请求和响应,也可以作为存储工具。例如,我们可以存储个性化数据(如用户偏好)在缓存中,按需查询这些数据。`put` 方法可用于将个性化响应对象存储在缓存存储中。 + +CacheStorage API 允许我们从跨域网站获取和缓存数据。CacheStorage API 是异步的,不会阻塞 UI 渲染。CacheStorage 选项是最新加入浏览器存储的,有些浏览器仍未支持。 + +```HTML + + + + Browser Storage Demos - Cache Storage API + + + + + Welcome to Browser Storage Demos - Cache Storage API
+ +

+ + + + + + + + + +``` + + + +相关演示参见[浏览器存储演示](https://github.com/techforum-repo/youttubedata/tree/master/browser-storage-demos)(这个演示是在 Node.js 上使用 Express.js 构建的)。 + +在用户浏览器上存储数据有多样的选择 —— 根据你的使用场景进行选择。 + +你可以选择使用 CacheStorage API 存储供离线访问的数据,而在存储大量应用或用户生成的数据的情况下,IndexedDB 是更好的选择。当然,Cookie 仍可以用于存储用于服务器识别的小型数据。 + +本地存储(localStorage)和会话存储(sessionStorage)则可用于存储少量数据。本地存储和会话存储的 API 是同步的,因此它们会影响 UI 渲染。但与此同时,它们这两个 API 易于在项目中使用。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/the-javascript-landscape-in-2021.md b/article/2021/the-javascript-landscape-in-2021.md new file mode 100644 index 00000000000..4ba8448e592 --- /dev/null +++ b/article/2021/the-javascript-landscape-in-2021.md @@ -0,0 +1,86 @@ +> * 原文地址:[The JavaScript Landscape in 2021](https://medium.com/javascript-in-plain-english/the-javascript-landscape-in-2021-573d5e7a43c6) +> * 原文作者:[Richard Bultitude](https://medium.com/@rbultitudezone) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/the-javascript-landscape-in-2021.md](https://github.com/xitu/gold-miner/blob/master/article/2021/the-javascript-landscape-in-2021.md) +> * 译者: +> * 校对者: + +# The JavaScript Landscape in 2021 + +![Photo by [Sergey Pesterev](https://unsplash.com/@sickle?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/landscape?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/17792/1*seEhUyV_-leofR3E1CYGwg.jpeg) + +In web development our world changes quickly, but what can we pin down what 2021 will bring? By scrutinizing data from the 2020 developer surveys, I’ve highlighted what I think the big JavaScript stories will be. + +Before going into the detail, a quick note on JavaScript surveys. Sadly, the next edition of the excellent [Front End Tooling Survey](https://ashleynolan.co.uk/blog/frontend-tooling-survey-2019-results), will not be published for some time, which makes finding trends a little harder. Whilst we may be down one good survey, a new one has popped up in its stead: [The State of Front End](https://tsh.io/state-of-frontend/). Though there’s no previous annual data to help us see trends, it was filled in by a whopping 4,500 developers from around the world, so it’s definitely a valuable resource. + +Let’s dive in and explore the insights I’ve garnered from the data. + +## Package Managers + +[Last year](https://medium.com/engineered-publicis-sapient/the-javascript-landscape-in-2020-b8e5898b847e) I suggested we watch out for the rise of [PNPM](https://pnpm.js.org/), which aims to avoid version conflicts and play well with monorepos. It has some [passionate advocates](https://medium.com/better-programming/the-case-for-pnpm-over-npm-or-yarn-2b221607119) and reached 9.5k stars on Github last year, so it’s clearly winning developers over. However, I feel it’s unlikely to seriously [compete on usage](https://www.npmtrends.com/yarn-vs-pnpm-vs-npm) in 2021, given how embedded [Yarn](https://yarnpkg.com/) and [NPM](https://www.npmjs.com/) are in live projects and how much energy both have put into shipping new features. Some of these features have been developed in direct response to PNPM, in particular [Workspaces](https://classic.yarnpkg.com/en/docs/workspaces/). This just goes to show how important competition is in driving open source software forward. + +## Testing + +In 2019, [Cypress](https://www.cypress.io/) and [Puppeteer](https://github.com/puppeteer/puppeteer) stood out as high new entries and both of them have continued to be successful in 2020. However, Microsoft have brought a new E2E testing tool to the party in the form of [Playwright](https://github.com/microsoft/playwright), which seemed to appear out of nowhere and gained just under 20k stars in 2020 alone. As one of the world’s biggest software companies they have the clout to widely promote their wares, but that only partially explains the tool’s popularity. The main reason is its feature set and simple migration path from [Puppeteer](https://pptr.dev/). + +![Playright tops the Rising Stars testing frameworks chart despite not having featured at all in 2019](https://cdn-images-1.medium.com/max/2000/1*uYLDgxsDdacIUtiOnAWTFw.png) + +Since [Nadella](https://en.wikipedia.org/wiki/Satya_Nadella) took over as CEO, Microsoft have developed a habit of producing popular and powerful open source tools. [VSCode anyone](https://2020.stateofjs.com/en-US/other-tools/#text_editors)? + +## JavaScript Flavours + +I said last year that [TypeScript](https://www.typescriptlang.org/) had, slowly but surely, taken over the JavaScript world; that trend has intensified. Countless open source projects eagerly list it as asupported feature. [Deno](https://deno.land/), which was **the** [most starred Github project in 2020](https://risingstars.js.org/2020/en#section-all), comes with the Typescript compiler built in. + +Last [year I suggested we keep an eye on PureScript](http://www.purescript.org/), given the interest in static types **and** functional programming, that it enforces. However, uptake wasn’t so strong in 2020, with only 641 new stars on Github and [interest dropping by 3%](https://2020.stateofjs.com/en-US/technologies/javascript-flavors/). Looking at the [huge usage gap](https://www.npmtrends.com/typescript-vs-elm-vs-coffee-script-vs-purescript-vs-reason) between TypeScript and its competitors, it feels like the language war is over and Microsoft’s product has won out. Any newcomer will struggle to get our attention after years of deliberation in the community and an atmosphere of language overload. + +This is an area I am relieved to see the community converge on. Now, we avoid the distraction of different super-sets and focus more on the language itself. + +## UI frameworks + +[Vue](https://vuejs.org/) was the most starred framework of 2019, which was big news at the time and sent a clear message: developers **love** it. [It’s the same story in 2020](https://risingstars.js.org/2020/en#section-framework). However, the [React](https://reactjs.org/) market share is still enormous when we look at [NPM downloads](https://www.npmtrends.com/react-vs-vue-vs-svelte). + +![React downloads in the past year](https://cdn-images-1.medium.com/max/2332/1*PJFyaoF6Bz3AKmt9Npzx6w.png) + +There are two other useful metrics: tags in GitHub and advertised jobs. Currently there are over 80k repos tagged ‘React’ on GitHub, compared with 25k as ‘Vue’. Looking at the job market, last May Career Karma reported [10,005](https://www.indeed.com/q-React-Developer-jobs.html?vjk=2873485b3446c4bc) jobs on Indeed.com for React Developers in the USA with only [1,025](https://www.indeed.com/q-Vue-Js-Developer-jobs.html?vjk=9216260d28c3fda3) for Vue. React is ubiquitous and is weathering some stiff competition. + +I can’t conclude this section without mentioning [Svelte](https://svelte.dev/) and [Angular](https://angularjs.org/). Angular is still very popular — it gained [13.3k new stars last year](https://risingstars.js.org/2020/en#section-framework) and gets almost 2.5million downloads a week on NPM. This may come as a surprise to some, given React’s dominance, but these stats deserve recognition. Svelte, is very young by comparison, but [tops the satisfaction chart in State of JS](https://2020.stateofjs.com/en-US/technologies/front-end-frameworks/). However, I only expect it to make modest gains in 2021 due to the steep learning curve for React and Vue devs. + +## Backend + +This is now a complicated space where frameworks for static site generation sit alongside ones for API production. If we break it down a little and take a look at server only frameworks, we can see [Express](https://expressjs.com/) still sitting pretty with 51.5k stars. However, [Nest](https://nestjs.com/) has exploded onto the scene with a staggering 10.3k **new** stars in 2020, taking its total to 33.6k. Developers have taken to it because they’re attracted to its opinionated approach, which can speed up development and simplify maintenance. Oh and did I mention it uses TypeScript? + +Looking at the proliferation of full-stack frameworks, there is a very important battle for hearts and minds going on in this space because they have such a big impact on architecture, performance and ways of working. The two React-based frameworks, [NextJS](https://nextjs.org/) and [Gatsby](https://www.gatsbyjs.com/), are still considerably more popular than their VueJS counterparts in terms of usage, but that only confirms what we already know about the UI framework ecosystem. What’s really noteworthy is how much [Gatsby’s satisfaction rating has gone down](https://2020.stateofjs.com/en-US/technologies/back-end-frameworks/). Anecdotal evidence suggests that it has a confusing [DX](https://medium.com/swlh/what-is-dx-developer-experience-401a0e44a9d9), though there is plenty of evidence to refute that online. With NextJS being developed by [Vercel](https://vercel.com/) and adding features like static site generation to its arsenal, I can only see it going from strength to strength this year. + +## Build tools + +This area has some noteworthy competition right now. Despite complaints about Webpack’s DevX, it reigned supreme for a long time and [still has the highest usage](https://www.npmtrends.com/webpack-vs-gulp-vs-rollup-vs-parcel) among the majors. Last year, we saw [Rome](https://github.com/rome/tools) challenging this space and this year we have [esbuild](https://github.com/evanw/esbuild), [Snowpack](https://www.snowpack.dev/) and Vite making their way up the [Rising stars charts](https://risingstars.js.org/2020/en#section-build). Esbuild’s remit is simple: speed up build time. This is clearly really valuable to many engineering teams and explains the move towards it. + +![esbuild and Snowpack are joint top of the State of JS 2020 build tools chart](https://cdn-images-1.medium.com/max/2000/1*LqoAdgne6TToTpeX4qBhYg.png) + +Whilst GitHub stars are one metric, Snowpack tops the **Interest** chart in the State of JS survey, but more importantly, it’s joint top of the [**Satisfaction** chart](https://2020.stateofjs.com/en-US/technologies/build-tools/). Whilst usage may still be quite low, I feel its time is coming. Snowpack and Vite’s popularity sends an important message: native ES modules are being taken seriously by the community. This is a huge topic because of its implications on the build process, caching and dev/prod module symmetry. + +## State management + +What UI framework would be complete without its companion state manager? Setting aside debates about complexity vs future proofing, this area is particularly interesting because Redux is being challenged from two angles: from within React itself and independent newcomers. + +I know from personal experience how powerful React’s Hooks and Context APIs can be, but they do have their limitations. Either way, they’re certainly a big hit with React developers, with [almost half the State of Front End participants](https://tsh.io/state-of-frontend/#frameworks) stating they use them. + +![State of Front End 2020 Survey State Management Category](https://cdn-images-1.medium.com/max/2000/1*GbKC2D1NEt8Fj_bjNwHmKA.png) + +## Conclusion + +In last year’s article, I explored the theme of **consolidation**. After years of diverging patterns, frameworks and libraries it feels like we’re aligning on patterns and practices. Whilst I feel that the trend continued in 2020, it’s clear that JavaScript’s popularity has led to a proliferation of tools in markets that were previously the preserve of other languages; illustrated by the growing number of E2E testing and machine learning tools. + +The key theme that emerged from the 2020 data is that the JavaScript landscape is being defined by the big software vendors. Microsoft’s TypeScript is becoming an industry standard and projects that are built on it have a better chance of success, NestJS and NextJS (not to be confused) being great examples. + +The influence of the [JAMStack](https://jamstack.org/) approach and need for speed are influencing factors too, with static site generators and tools like ESbuild rising to prominence very quickly. + +The JavaScript landscape just keeps on expanding, fueled by rapid evolution of features, browser support, runtimes and an ever-widening digital horizon. + +> This article was kindly reviewed by George Adamson and Joanne Parkes. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/the-new-king-of-bundlers-is-here-all-bow-before-vitejs.md b/article/2021/the-new-king-of-bundlers-is-here-all-bow-before-vitejs.md new file mode 100644 index 00000000000..8e96c569054 --- /dev/null +++ b/article/2021/the-new-king-of-bundlers-is-here-all-bow-before-vitejs.md @@ -0,0 +1,125 @@ +> * 原文地址:[The New King of Bundlers Is Here: All Bow Before Vitejs](https://blog.bitsrc.io/the-new-king-of-bundlers-is-here-all-bow-before-vitejs-fe6f42c97ce9) +> * 原文作者:[Fernando Doglio](https://medium.com/@deleteman123) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/the-new-king-of-bundlers-is-here-all-bow-before-vitejs.md](https://github.com/xitu/gold-miner/blob/master/article/2021/the-new-king-of-bundlers-is-here-all-bow-before-vitejs.md) +> * 译者: +> * 校对者: + +# The New King of Bundlers Is Here: All Bow Before Vitejs + +![Photo by [Paweł Furman](https://unsplash.com/@pawelo81?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/king?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/13714/1*LlgpXcXbw-wEPTqxiRDDDw.jpeg) + +Back when I started coding, JavaScript was used only to add some fancy effects to your website. Remember that trailing effect you could add to your mouse? Or how you could change the colors of your links during a hover event? + +Of course, web development has evolved so much over the years that now the amount of JavaScript used on web applications is growing exponentially. It is because of that, that JavaScript is becoming its own bottleneck due to bundle size. + +Bundle size for some applications are starting to affect the time users need to begin using your application (they can’t use it until the bundled code is downloaded), the bundling process itself is causing development times to increase (sometimes changing a single line of code can trigger a bundling process that takes several minutes), and while there are techniques around to help solve this problem, not all of them are hitting the mark and the ones that do require a lot of effort to achieve — which as a user of these tools, you shouldn’t care, but if you’re working on them, then it becomes a real pain to maintain. + +That is why today I want to tell you about a tool that promises to solve all these problems: [ViteJS](https://vitejs.dev/). + +## What makes ViteJS so great? + +That is, without a doubt, the first question you should be asking yourself. + +There are way too many bundlers out there already, do you need one more? Yes, yes you do. + +ViteJS is not just a bundler, and that is the key aspect of it. In fact, ViteJS is aiming to be your go-to tool for starting any new JavaScript-based project. It changes the way normal bundlers think about dependencies by working directly with ES Modules and letting the browser do some of the work. + +It also relies heavily on HTTP to cache non-changing code. So, instead of working with a huge bundled file where you’re sending all the code to the client, it is the client that decides what to keep and what to refresh often (more on this in a second). + +Some of the main features from ViteJS that you might want to pay attention to are: + +* **Built with speed in mind.** The little bundling and transpiling ViteJS does, does so using [esbuild](https://esbuild.github.io/), which is built in Go. This in turn provides a faster experience (10x to 20x times faster than any JavaScript-based bundlers according to them). +* **Compatible with TypesScript**. While it does not perform type-checking, normally your IDE will take care of that, and you can even add a quick one-liner to the build script to do it for you (a quick `tsc --noEmit` and that’s it). +* **It has support for Hot Module Replacement (HMR)**. ViteJS provides an [API](https://vitejs.dev/guide/api-hmr.html#hot-data) for any ESM-compatible framework to use. +* **Improved code-splitting techniques**. ViteJS implements some improvement over the browser’s normal chunk-loading process. This ensures that if there is a chance to load several chunks in parallel, they will be loaded that way. + +The list of interesting features goes on actually, so make sure to check out their site for more details. + +## The plugin system + +One of the main advantages of ViteJS is that it has a plugin system built-in, which means the community can (and has) add extra features and integrations with other frameworks (such as React and Vue). + +### Using ViteJS for your Vue projects + +[The list of plugins for Vue](https://github.com/vitejs/awesome-vite#vue) is quite extensive, the only thing you need to pay attention to, is that they’re not all compatible with the same version of the framework (some of them work for Vue 2, while others only for Vue 3, and some work for both). + +To get your Vue App started, you can use a plugin such as [Vitesse](https://github.com/antfu/vitesse) which you can simply clone and rename. It comes prepacked with multiple built-in features and plugins, such as: + +* [**WindiCSS**](https://github.com/windicss/windicss) as its UI framework and **[WindiCSS Typography](https://windicss.netlify.app/guide/plugins.html#typography).** +* [**Iconify**](https://iconify.design/) allows you to use icons from multiple icon sets around the web. +* **ViteJS’ [Vue i18n plugin](https://github.com/intlify/vite-plugin-vue-i18n)**. So that’s already backed-in, no need to worry about adding internationalization support. +* **A group of VS Code extensions** (for Vite’s dev server, i18n ally, WindiCSS, Iconify Intellisense, and others), which is great if you’re a VS Code user, otherwise they won’t do any good. + +There are more built-in features, so make sure to check out their [Repo](https://github.com/antfu/vitesse). + +If, on the other hand, you just want to start from scratch, and build your own thing, you can also simply use ViteJS’ CLI tool: + +```bash +# If you're using npm 7 +$ npm init @vitejs/app my-vue-app -- --template vue + +# If you're using npm 6 +$ npm init @vitejs/app my-vue-app --template vue + +# And if you're a yarn-biased developer +$ yarn create @vitejs/app my-vue-app --template vue +``` + +Either one of these commands will generate the same output: + +![](https://cdn-images-1.medium.com/max/2860/1*2pPul6Se15bcLeUJpwTHDA.png) + +It’s really fast (under a second) and after following those 3 extra steps, your Vue app is up and running. + +![](https://cdn-images-1.medium.com/max/2092/1*hfPIpmBPpAffHUcwhMa1Qg.png) + +#### ViteJS and React + +You’re not a Vue type of dev? No problem, Vite has you covered. + +Just use the same line as before, but instead of `vue` use `react` or `react-ts` and you’re done. + +```bash +$ npm init @vitejs/app my-react-app --template react-ts +$ cd my-react-app +$ npm install +$ npm run dev +``` + +The above lines will output the equivalent React application using TypeScript: + +![](https://cdn-images-1.medium.com/max/2368/1*UMWnw5t9qw1Lj2Ffo-UxLA.png) + +Do you want more presets? You can find 2 plugins, depending on your needs: + +1. If you’re looking for a React project with TypeScript, [Chakra](https://chakra-ui.com/) and [Cypress](https://www.cypress.io/), you have [this plugin](https://github.com/Dieman89/vite-reactts-chakra-starter). +2. If instead of Chakra, you’re looking to create an Electron app, you have [this one.](https://github.com/maxstue/vite-reactts-electron-starter) This one also comes with [TailwindCSS](https://tailwindcss.com/) included. + +Both options work with TypeScript, and if you’re familiar with any of those combinations, I would suggest picking them up instead of starting from scratch. Mind you, the default starter project is perfectly fine, but you get part of your boilerplate setup already done with these plugins. + +## What about other bundlers? + +ViteJS is not the first tool to attempt to do this, and it’s definitely not the most known either. But it was created because the current ruling class is not tackling the performance problem with the latest trends in the industry. They’re still trying to solve problems that given today’s state-of-the-art shouldn’t exist. + +The main difference between Vite and other bundlers such as Webpack, is that the latter will try to go through your dependency tree, compile and optimize the packaged code in a way that is better for any browser to get your code. Notice the word “any” there, since that will be the major problem for Vite. This process however, takes time, and if you’ve been using any of these established bundlers you probably know what I mean. It takes a while, but the end result is good for any client. + +On the other side of the spectrum, we have Vite, which like I already mentioned, takes advantage of the browser’s ES Module support. This means the browser will be in charge of capturing the `import` and `export` and request them individually. This means you can get your app running in no time, but it also means only new browsers will be compatible with your app. + +As you can see, from the following table showing support for `import` taken from [Mozilla’s site](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), support is coming along nicely, however, older versions will never be able to catch up: + +![Screen taken from Mozilla’s site](https://cdn-images-1.medium.com/max/4020/1*A3skPd6C2oiKF743LgwO0A.png) + +There is still work to be done compatibility-wise, so if you’re thinking about using ViteJS for your next project, make sure your target audience tends to update their browsers regularly. + +--- + +ViteJS has the potential of dethroning the current industry standards when it comes to bundler tools. It has the technology, it has the plugin ecosystem and it has the required features. The only thing stopping it from getting the crown of de-facto bundler, is its compatibility with older browsers. + +This is definitely a problem today, but it’s a problem for a diminishing section of our industry, so keep an eye open for Vite, since it’ll be growing as browsers get older. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/the-why-and-how-of-microservice-messaging-in-kubernetes.md b/article/2021/the-why-and-how-of-microservice-messaging-in-kubernetes.md new file mode 100644 index 00000000000..e41c9c6027a --- /dev/null +++ b/article/2021/the-why-and-how-of-microservice-messaging-in-kubernetes.md @@ -0,0 +1,83 @@ +> * 原文地址:[The Why and How of Microservice Messaging in Kubernetes](https://levelup.gitconnected.com/the-why-and-how-of-microservice-messaging-in-kubernetes-1d54a4717bf1) +> * 原文作者:[Michael Bogan](https://medium.com/@michael.bogan) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/the-why-and-how-of-microservice-messaging-in-kubernetes.md](https://github.com/xitu/gold-miner/blob/master/article/2021/the-why-and-how-of-microservice-messaging-in-kubernetes.md) +> * 译者: +> * 校对者: + +# The Why and How of Microservice Messaging in Kubernetes + +## Introduction + +Struggling with connecting and maintaining your microservices in Kubernetes? As the number of microservices grows, the difficulty and complexity of maintaining your distributed fleet of services grows exponentially. Messaging can provide a clean solution to this issue, but legacy message queues come with their own set of problems. + +In this article, I’ll share the benefits of messaging in Kubernetes and the difficulties that can come with legacy solutions. I’ll also briefly look at KubeMQ, which attempts to address some of the traditional problems with messaging in Kubernetes. + +## Why Messaging in Kubernetes? + +As a microservice-based architecture grows, it can be difficult to connect each of these distributed services. Issues of security, availability, and latency have to be addressed for each point-to-point interaction. Furthermore, as the number of services increases, the number of potential connections also grows. For example, consider an environment with only three services. These three services have a total of three potential connections: + +![](https://cdn-images-1.medium.com/max/2000/0*MnLbG8FpmHAHgqIh) + +However, as that increases to say five services, the number of potential connections increases to 10: + +![](https://cdn-images-1.medium.com/max/2000/0*toIa18YoswmvefdJ) + +With 20 services, the number of potential connections is 190! For reference, see the table below: + +![](https://cdn-images-1.medium.com/max/2750/1*YICTJvUjgWg2V1-8FHWrjA.png) + +This is clearly not sustainable for organizations with a large portfolio of services. However, through the use of a message queue, we can centralize those connections. Since the number of connections is equal to the number of services, this results in a solution which scales linearly. See below: + +![](https://cdn-images-1.medium.com/max/2328/0*0RiyaZI4dgiwTRAB) + +For a large microservice fleet, this significantly simplifies the security and availability issues, as each microservice needs to communicate primarily with the message queue. This is the very reason implementing a message queue architecture is considered best practice when running large numbers of microservices in Kubernetes. As a result, the selection of the message queue is a critically important decision, as the entire architecture will depend on the reliability and scalability of that message queue. + +Finally, deploying the message queue in Kubernetes allows you to avoid platform lock-in. There are a number of platform-specific messaging solutions from the major cloud providers, but running a platform-agnostic solution allows you to keep your microservices architecture consistent, regardless of your platform. Kubernetes is the de facto orchestration solution and has support from all major cloud providers. + +Now that we’ve established why messaging is helpful, let’s dig a little deeper. This seems like such a simple solution, so what could be so hard about it? + +## What’s hard about messaging in Kubernetes? + +There are a number of pain points when attempting to run a message queue in Kubernetes. Let’s consider the differences between a typical microservice and your standard message queue. I’ve summarized some of the differences in the following table: + +![](https://cdn-images-1.medium.com/max/2000/1*x8OmpOvNMcnLAexbDeQVxA.png) + +First, microservices are designed to be resource-light. This is in some ways a natural result of being a microservice — each service performs a single purpose, and thus can be smaller and more nimble. In contrast, legacy message queues are large, resource-intensive applications. The latest version of IBM MQ at time of writing has [significant hardware requirements](https://www.ibm.com/software/reports/compatibility/clarity-reports/report/html/softwareReqsForProduct?deliverableId=E3F333600B7F11EABCF401BE73544226&osPlatforms=Linux&duComponentIds=D005%7CS011%7CS006%7CS010%7CS008%7CS007%7CS009%7CA004%7CA003%7CA001%7CA002&mandatoryCapIds=16&optionalCapIds=30%7C341%7C47%7C12%7C9%7C1%7C25%7C20%7C28%7C184%7C185%7C70%7C16%7C15%7C26#!). For example, > 1.5 GB disk space and 3 GB of RAM. + +Additionally, a typical microservice is stateless, as it does not contain any part of the state of the application in itself. However, many legacy message queues function effectively as databases and require persistent storage. Persistent storage in Kubernetes is best handled with the [Persistent Volume API](https://kubernetes.io/docs/concepts/storage/persistent-volumes/), but this requires workarounds for legacy solutions. + +These differences in resource usage lead naturally to the next point — microservices are simple to deploy. Microservices are designed to deploy quickly and as part of a cluster. On the other hand, due to their resource-intensive nature, legacy message queues have complex deployment instructions and require a dedicated team to set up and maintain. + +Next, microservices are designed to be horizontally scalable. Horizontal scaling is done through the deployment of additional instances of a service. This allows a service to scale nearly infinitely, have high availability, and is generally cheaper. In contrast, due to the aforementioned resource requirements and deployment pains, legacy message queues must be scaled vertically — in other words, a bigger machine. In addition to the physical limitations (a single machine can only be so powerful), larger machines are expensive. + +These issues typically require significant investment and time to resolve, reducing the value that the message queue provides to your overall architecture. However, none of these issues are inherent to messaging; they are instead an artifact of when the major message queues were designed and conceived. + +So how can we address these issues? Let’s take a look at one option: using a Kubernetes-native message queue such as KubeMQ. + +## A Kubernetes-native Approach + +[KubeMQ](https://kubemq.io/) is an product that attempts to solve Kubernetes-related messaging issues. Let’s take a look at a few ways it does this. + +First, it is **Kubernetes-native**, which means that it integrates well with Kubernetes and is simple to deploy as a Kubernetes cluster. [Operators](https://operatorhub.io/operator/kubemq-operator) that allow you to automate tasks **beyond** what Kubernetes natively provides come with the product for lifecycle management. [Cluster persistency](https://docs.kubemq.io/learn/cluster-scale#cluster-persistency) is supported through both local volume and PVCs. Being Kubernetes-native also means that it is cloud-agnostic, and thus it can also be deployed on-premises or into hybrid cloud environments. + +Additionally, it is **lightweight** — the Docker container is roughly ~30 MB, a far cry from the GB of required space from legacy solutions. This allows it to be deployed virtually anywhere and enables new use cases, such as edge deployments for Internet-of-Things device support. Despite its small size, it has support for [a variety of messaging patterns](https://kubemq.io/product-messaging-patterns/). + +Finally, it is **extensible**. Through the use of [Bridges](https://kubemq.io/kubemq-bridges/), [Targets](https://kubemq.io/kubemq-targets/), and [Sources](https://kubemq.io/kubemq-sources/), these pre-built connectors allow it to connect to a variety of other applications and services, reducing the need for custom integrations. Bridges allow KubeMQ clusters to pass messages between one another, enabling KubeMQ to connect various cloud, on-premises, and edge environments. + +Since KubeMQ is small, you can try it out for yourself with a [local installation of minikube](https://minikube.sigs.k8s.io/docs/start/) or access to any other Kubernetes cluster. + +1. [Sign up](https://account.kubemq.io/login/register) for a (free) account and get a license token. +2. Run kubectl apply -f [https://get.kubemq.io/deploy?token=](https://get.kubemq.io/deploy?token=)\ + +You can verify the status of your cluster with kubectl get kubemqclusters -n kubemq. For more information, check out the [official docs](https://docs.kubemq.io/getting-started/quick-start). + +## Summary + +In this article, I reviewed the benefits of a message queue, looked at difficulties around implementing messaging in Kubernetes, and took a quick look at [KubeMQ](https://kubemq.io/) — a lightweight and Kubernetes-native solution that can provide several advantages over legacy solutions. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/top-3-css-grid-features-to-start-using-in-production.md b/article/2021/top-3-css-grid-features-to-start-using-in-production.md new file mode 100644 index 00000000000..592a437b664 --- /dev/null +++ b/article/2021/top-3-css-grid-features-to-start-using-in-production.md @@ -0,0 +1,375 @@ +> * 原文地址:[Top 3 CSS Grid Features To Start Using in Production](https://medium.com/better-programming/top-3-css-grid-features-to-start-using-in-production-b0fe59b2e0f7) +> * 原文作者:[Jose Granja](https://medium.com/@dioxmio) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/top-3-css-grid-features-to-start-using-in-production.md](https://github.com/xitu/gold-miner/blob/master/article/2021/top-3-css-grid-features-to-start-using-in-production.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Usualminds](https://github.com/Usualminds)、[zqp1226358](https://github.com/zqp1226358) + +# 3 个最棒的最值得你去在产品中使用的 CSS Grid 功能 + +![由 [Sigmund](https://unsplash.com/@sigmund?utm_source=medium&utm_medium=referral) 拍摄并在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上传的图片](https://cdn-images-1.medium.com/max/8096/0*mWiTIfu6BVlYQ5lf) + +Grid 最初是由 Microsoft 团队起草的,并于 2011 年在 IE 10 中落实的。经过近 9 年的发展,我们现在可以说,浏览器对 Grid 的支持已经变得足够好,这样我们可以安心在生产环境中中使用 Grid 了。 + +本篇文章我们主要讨论浏览器支持且使用频率最高的 3 个 Grid 布局相关的特性。即使有一些更酷的新功能的出现,例如 `subgrid` 等的问世,也请注意谨慎在生产中不要使用这些功能。在发布产品前,请先检查 [Can I Use](https://www.caniuse.com) 网站上的浏览器支持信息。养成这样一个好习惯,百利而无一害。 + +## 一个简要的复习 + +究竟什么是 Grid?Grid 其实就是一个以容器为中心的多维布局系统。简而言之:它可以在任何 x / y 方向上拓展,并且所有布局信息都存储在父节点中,而子节点则大多掌握有关如何将自己放置在 Grid 上的信息。 + +![一维布局与二维布局](https://cdn-images-1.medium.com/max/2000/1*6YeEVVXSRcJwnZBHo2EgpQ.png) + +在使用 Grid 开发时,建议使用 Firefox 浏览器,因为它的 Dev Tools 比其他浏览器的都要好 —— 支持 Grid 相关属性最棒的浏览器,而且它也是目前唯一支持 `subgrid` 属性的浏览器。 + +现在,让我们深入研究可用于生产的三大 CSS Grid 功能。 + +## 1. Grid 模板区域 + +这是我一直以来最喜欢的 CSS Grid 功能,允许我们以声明的方式定义 Grid 布局。 + +我们可以使用几行 CSS 行创建一个非常复杂且响应迅速的布局: + +```HTML + + + + Grid Playground + + + + + +
+ +
Left
+
Content
+
Right
+ +
+ + +``` + +![复杂的 Grid 布局](https://cdn-images-1.medium.com/max/2000/1*kxxETOv_yi4ECBfYz_D-mw.png) + +所有的变化都由 `grid-templates-areas` 和 `grid-area` 两个属性产生。前者定义了所有 Grid 轨迹,而后者将 Grid 元素定位在那些区域上。 + +提示: Grid 轨迹是两条 Grid 线之间的空间。 + +让我们使用 Firefox Inspector 审查页面元素,能够清晰地了解我们所创建的 Grid 布局。 + +![ Grid 布局的内部](https://cdn-images-1.medium.com/max/2090/1*U9o4_M-wfMeBHindl1H4sw.png) + +如果我们想在内容周围留一些空白,而不是直接挨着左右两列,我们可以使用`.` / `...` 符号。 + +```css +#grid { + background-color: #73937E; + height: calc(100vh - 20px); + display: grid; + grid-template-rows:1fr 2fr 1fr; + grid-template-areas: + "navigation navigation navigation navigation" + ". content content ." + "footer footer footer footer"; +} +``` + +![在主要内容两边定义空白 Grid](https://cdn-images-1.medium.com/max/2074/1*frMRKP1wKAGbxlAuQVI_SQ.png) + +注意:使用 `grid-template-areas` 时,需要注意以下几点: + +* 每个区域名称只能定义一次。如果没有连接具有相同区域名称的单元,则将会被视为两个声明。 +* Grid 区域单元必须形成一个矩形。如果不是,则声明无效。 + +```css +/* 一个无效的 Grid */ +#grid { + background-color: #73937E; + height: calc(100vh - 20px); + display: grid; + grid-template-areas: + "navigation navigation navigation navigation" + "left content content right" + "content content content content" + "left content content right" + "footer footer footer footer"; +} +``` + +上面的示例不起作用。因为 `right` 和 `left` 的定义都重复了。删除 `content content content content` 一行,让 `left` 和 `right` 连接起来,就能够解决该问题。 + +```css +/* 一个无效的 Grid */ +#grid { + background-color: #73937E; + height: calc(100vh - 20px); + display: grid; + grid-template-areas: + "navigation navigation navigation navigation" + "content right" + "content content" + "right" + "footer"; +} +``` + +上面的示例不起作用,因为我们定义了描述了一个非矩形区域,而 Grid 并非为此而建,也不支持它。 + +提示:我们可以将 `grid-template-rows` 和 `grid-template-areas` 结合使用,但是结果将有所不同。我们必须选择一种适合我们特定场景的方案。 + +```css +/* 方法 A */ +#grid { + grid-template-rows: 1fr 3fr 1fr; + grid-template-areas: + "navigation navigation navigation navigation" + "left content content right" + "footer footer footer footer"; +} + +/* 方法 B */ +#grid { + grid-template-areas: + "navigation navigation navigation navigation" + "left content content right" + "left content content right" + "left content content right" + "footer footer footer footer"; +} +``` + +![方法 A](https://cdn-images-1.medium.com/max/2090/1*U9o4_M-wfMeBHindl1H4sw.png) + +![方法 B](https://cdn-images-1.medium.com/max/2082/1*18VMr9MkDmUHOS-biKfckQ.png) + +提示:使用 `grid-template-area` 可以简单创建 Grid 线。这意味着即使使用 `grid-template-area`,我们仍然可以使用 Grid 线的位置逻辑。接下来,让我们简要介绍一下负索引 `-1`。 + +```css +.customContent { + background-color: white; + grid-row: 1 / -1; + grid-column: 1; +} +``` + +添加负索引会使我们的 CSS 更强大。我们可能会对 Grid 线的数量不了解:通过负索引,我们可以将内容设置为扩展到最后一个 Grid 线。 + +![行上面使用负索引的结果](https://cdn-images-1.medium.com/max/2078/1*mFCCFIxCWZ_EA5H80t-BjQ.png) + +## 2. Grid 间隔 + +Grid 的 `gap` 特性的使用是很简捷的。我们仅需使用 `column-gap`、`row-gap` 或 `gap` 就能定义 Grid 布局中的间隙。 + +```css +#grid { + background-color: #73937E; + height: calc(100vh - 20px); + display: grid; + row-gap: 5px; + column-gap: 15px; + grid-template-areas: + "navigation navigation navigation navigation" + "left content content right" + "content content content content" + "left content content right" + "footer footer footer footer"; +} +``` + +![使用 gap 功能](https://cdn-images-1.medium.com/max/2000/1*aajG-IirnfyHHYyPb2YKsw.png) + +注意:请勿使用 `grid-gap`、`grid-column-gap` 或 `grid-column-gap`:现在它们已过时,浏览器的支持会不断下降。 + +## 3. MinMax + +起初,`MinMax` 看起来并不像一个令人兴奋的功能。这个功能非常简单: + +``` +minmax(min, max) +``` + +它将在 `min` 和 `max` 之间获取最大值。它接受:`length`、`percentage`、`max-content`、`min-content` 和 `auto` 五种类型的值。它就是专门为 Grid 打造的,因此能够在 Grid 上发挥出超强的作用。 + +让我们创建一个包含三列的布局,并使用 `minmax` 将其扩展到整个 Grid 区域。 + +``` +grid-template-columns: repeat(3, minmax(100px, 1fr)); +``` + +![使用 minmax 定义三列布局](https://cdn-images-1.medium.com/max/2000/1*DqLyXYT5DlN7k8NHejQ1nQ.png) + +注意:这看起来很棒,但是有一个很大的缺点 —— 如果容器小于 `3 * 100px + 2 * 10px`,则内容将溢出。 + +![没有足够的空间来渲染最小宽度为 100px 的三列布局](https://cdn-images-1.medium.com/max/2000/1*q-y32_HSK0RUABQregRtJw.png) + +我们该如何解决?直接以响应方式构建 Grid 布局!我们可以让 Grid 容器通过使用 `auto-fill` 或 `auto-fit` 来确定列数。 + +通过简单的更改,我们的三列布局现在可以响应视口的大小: + +```HTML + + + + Grid Playground + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +``` + +![响应式 Grid 布局](https://cdn-images-1.medium.com/max/2000/1*wu16vXlLxgjnrI8Gragp1g.png) + +那就是我们所有变化所发生的源头: + +``` +grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); +``` + +我们告诉 Grid 布局创建填充 Grid 空间的轨迹,并且它们的最小值应为 `200px`,最大值应为 `1fr`。 + +注意:我们不能使用 `auto-fill` 来设置最大列数。但这并不是要那样工作。为了设置最大列数,我们必须使用媒体查询并调整 `minMax` 的值。 另一种选择是使用 `css变量`。任一选项都需要使用媒体查询。 + +```css +/* 使用媒体查询 + CSS 变量去构建响应式的固定栏目布局 */ + +.grid { + --repeat: auto-fit; +} + +@media screen and (max-width: 700px) { + .grid { + --repeat: 3; + } +} + +/* 使用: grid-template-columns: repeat(var(--repeat, auto-fit), minmax(200px, 1fr)); */ +``` + +最后,让我们进一步了解 `auto-fill` 和 `auto-fit` 之间的区别: + +*`auto-fill`:尝试在给定约束条件下用尽可能多的列填充行 +*`auto-fit`:行为与`auto-fill`相同,但是任何空的重复轨道将被折叠,它将扩展其他轨道以占用所有可用空间(如果有)。 + +![自动填充与自动调整](https://cdn-images-1.medium.com/max/2000/1*Be3yz9t1oZ-OzfWghQ_l0g.png) + +当有足够的元素填充 Grid 时,两个属性的效果将相同。这意味着根据分辨率的不同,它们可能渲染的效果是一样的。这就是为什么了解他们的内部情况是很重要的。 + +![在某些分辨率下,它们的作用效果可能相同](https://cdn-images-1.medium.com/max/2000/1*bjQpF-R9e7ki-5u2c5zOwg.png) + +## 总结 + +![[Denys Nevozhai](https://unsplash.com/@dnevozhai?utm_source=medium&utm_medium=referral) 拍摄并发布于 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 的照片](https://cdn-images-1.medium.com/max/10944/0*qOzhnK7sH5tZyk_T) + +我们介绍了最突出的三个 Grid 特性并深入探讨了如何以最恰当的方式使用它们。现在,我想我们已经可以使用更少的 CSS 代码以更高效的方式构建布局。使用 Flex API 的日子已经过去了,现在就让我们一起使用 Grid 功能来美化我们的页面吧~ + +不幸的是,我们无法等待 IE 11 的终结,因为它至少在 4 年内不会发生,毕竟它仍然在企业级别被广泛地使用着。现在我们需要添加一些 polyfill 确保 100% 的用户都能够正常地使用。 + +我希望我的文章能为阅读的你提供开始在生产中使用 Grid 的信心。毕竟一旦开始使用它,就再也没有回头路了,这玩意真是太好用了! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/top-5-icon-packs-for-web-apps-in-2021.md b/article/2021/top-5-icon-packs-for-web-apps-in-2021.md new file mode 100644 index 00000000000..e5968bb693c --- /dev/null +++ b/article/2021/top-5-icon-packs-for-web-apps-in-2021.md @@ -0,0 +1,190 @@ +> * 原文地址:[Top 5 Icon Packs for Web Apps in 2021](https://blog.bitsrc.io/top-5-icon-packs-for-web-apps-in-2021-f0321653980e) +> * 原文作者:[Chameera Dulanga](https://medium.com/@chameeradulanga) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/top-5-icon-packs-for-web-apps-in-2021.md](https://github.com/xitu/gold-miner/blob/master/article/2021/top-5-icon-packs-for-web-apps-in-2021.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin) + +# 2021 年 Web 应用开发常用的五个图标库 + +![](https://cdn-images-1.medium.com/max/5760/1*uPK9UAnb1ni6GDB690LYig.jpeg) + +在过去的十年里,网络和移动应用已经成为我们日常生活的一部分。如今,我们可以找到很多解决同一问题的应用程序。因此,应用程序的功能显然不再是唯一的区别。 + +此外,为用户提供良好的整体体验对这些应用程序的成功起着重要作用。为了实现这一点,我们还需要更好的用户界面(UI)。 + +作为开发人员,我们必须确保应用程序的外观和视感符合更高的标准,以便吸引新用户并保留现有用户。我希望这些事实能让你相信 UI 设计的重要性。 + +> 谈到 UI 设计,我们使用的图标体现了它的个性。 + +## 图标库 + +图标或许很小,但即便是没有一个单词文本的图标,也能给用户提供强有力的信息。说到图标,我们可以使用现成的图标库,或者独立构建图标。然而,鉴于以下原因,我建议使用图标库。 + +* 图标库能使得整个应用程序保持独特的外观。 +* 图标库能节省应用开发时间,因为你不需要从头开始构建图标。 +* 最重要的是,可以通过选择大多数用户已经熟悉的图标子集使得应用程序个性化。 +* 如果你有一整套应用程序,你可以在应用程序中统一使用这些图标库。 + +在本文中,我将讨论现有的五个常用图标库的用法以及优缺点。 + +## 1. ICONS8 + +![Source: [https://icons8.com/icons](https://icons8.com/icons)](https://cdn-images-1.medium.com/max/3146/1*cTiGQ9fSlPjnivRZdcKUDg.png) + +[Icons8](https://icons8.com/icons) 是最受设计师和开发者欢迎的图标库之一。它提供超过 140000 个图标,涵盖 35 个不同类别供你使用。 + +为开发项目找到最合适的图标组合是你最忙碌耗时的任务之一。有了 Icons8,你可以选择一种风格,并立即得到一个庞大图标组合。你还可以通过添加轮廓、不同颜色、文本效果来自定义它们,而不会浪费宝贵的时间。 + +此外,Icons8 通过为你的项目提供像素完美的图标来消除模糊效果,同时允许你下载任意标准格式的图标,包括 PNG、SVG、嵌入式 HTML 和 PDF。 + +![Screenshot by Auther: Customizing icons in Icons8](https://cdn-images-1.medium.com/max/3068/1*Mv5Z09kKyMafb0PlZLONLw.png) + +#### Icons8 的主要特点 + +* 并不是所有的图标都需要注明出处。 +* 在下载之前完成自定义图标设置。 +* 你可以找到任意颜色、大小和格式的图标。 +* 有不同的图标样式可供选择。(填充图标、线条图标、实心图标等。) +* 免费增值服务。从 13 美元起,有不同的图标、照片、插图供你选择。 +* 免费套餐包括可达 100 像素的 PNG 图标,你需要更改为付费套餐才能下载其他格式。 + +**缺点** + +* 需要注册才能下载图标。 +* 在下载图标并在项目中使用它们之前,你必须仔细检查,因为有些图标需要注明出处。 + +## 2. Flaticon + +![Source: [https://www.flaticon.com/packs](https://www.flaticon.com/packs)](https://cdn-images-1.medium.com/max/3776/1*BGohqk4R6c5r42XK45mLvA.png) + +[Flaticon](https://www.flaticon.com/home) 是另一个有名的图标库,我们可以将其用于 UI 设计,它以免费和高级软件包的形式提供了超过 200 万个不同的图标。像 Icons8 一样,你可以在下载之前编辑 Flaticon 图标。但是,Flaticon 不提供像 Icons8 那样丰富的编辑选项。 + +另一方面,你可以下载分辨率可达 512 像素的 PNG 版本图标。如前所述,Flaticon 还分为免费和付费版本,用户可以在付费版本中使用大量更高级的图标。 + +如果你是 Flaticon 的游客用户,你只能创建一个收藏,并且每天只能下载 10 个图标。你可以通过在 Flaticon 注册,每天最多扩展到 3 个收藏和下载 100 个图标,而不会产生任何费用。最重要的是,他们的高级版本允许你创建无限的图标集合,每天下载 2000 个图标。 + +![Screenshot by Auther: Customizing icons in Flaticon](https://cdn-images-1.medium.com/max/3092/1*rtcwQJSb3TlvMDMAQQOg7A.png) + +#### Flaticon 的主要特点 + +* 提供 SVG、EPS、PSD、BASE 64 和 PNG 格式。 +* 为 Adobe 的创意云套件(CC)提供了扩展。(校对者注:目前并没有搜索到相关扩展,官网链接已失效,可能是该扩展已下架) +* 能在下载之前进行自定义图标设计。 +* 高级套餐的价格为每月 9.99 欧元。 +* 高级套装提供无限数量的图标,包括三百万多个高级图标的集合。 +* [可以在 GSuite 应用程序中直接使用 Flaticon 图标。](https://www.flaticon.com/for-google) +* [可以使用 Flaticon 为演示文稿、故事、博客和网站创建背景图像。](https://www.flaticon.com/pattern-generator) + +**缺点** + +* 使用免费版本时需要提供注明出处。 + +## 3. Font Awesome + +![Source: [https://fontawesome.com/icons?d=gallery](https://fontawesome.com/icons?d=gallery)](https://cdn-images-1.medium.com/max/3746/1*EIJXAiWtSbQW-JuFOpczSQ.png) + +[Font Awesome](https://fontawesome.com/) 是开发者常用的另一个流行图标库,主要是因为它直接支持 Bootstrap 和 CSS。然而,Font Awesome 图标比 Icons8 和 Flaticon 少。因为 Font Awesome 是 Bootstrap CSS 框架中使用的默认图标集,它成为了任何使用 Bootstrap 开发项目的默认选择。 + +如果深入探究会发现,Font Awesome 中有两个库,分别为免费版和专业版。免费版仅包含 1,598 个图标,而专业版包含额外的 6,250 个图标和其他功能。 + +顾名思义,Font Awesome 使用字体而不是图像,因此在免费版和专业版中,它都提供了像素完美的图标,简单的 CSS 样式,托管的工具包,强大的转换以及轻松的升级。 Font Awesome 没有提供 Icon8 或 Flaticoin 之类的编辑选项,但为你提供了 CSS 类,可以直接在 HTML 中定义使用。 + +使用免费版,你只能下载所选择图标的完整版本,如果你希望使用 Regular、Light 或 Duotone 等字体,则需要切换到专业版。 + +![Screenshot by Auther: Customizing icons in Font Awesome](https://cdn-images-1.medium.com/max/3614/1*_GvBDBIHrbXi82AmPWXYxg.png) + +#### Font Awesome 的主要特点 + +* 从 Font Awesome 3.0 版本开始,不再需要注明出处。 +* 支持 CSS 和 Bootstrap。 +* 提供 CSS 类,Unicode 和 SVG 格式的图标。 +* 可以使用纯 CSS 直接更改图标的基本属性(颜色、阴影、背景等)。 +* 可以轻松升级到最新版本。 +* Font Awesome 全局 CDN 和缓存可用于更快地加载图标。 +* 专业版价格为每年 99 美元,包括自定义设置,人工技术支持,专业版下载,标准专业证书和其他功能。 + +## 4. Fontisto + +![Source: [https://fontisto.com/icons](https://fontisto.com/icons)](https://cdn-images-1.medium.com/max/2784/1*cCFElZNhCB0BUvdKR1-WMQ.png) + +与我们讨论的前三个图标包不同,[Fontisto](https://fontisto.com/) 是一个完全免费的矢量图标库,你可以将其用于项目开发和设计目的。你只需从它网站点击几下就可以定制图标。添加旋转效果、动画、边框等简单的修改,你可以用字体来完成。你也可以下载图标的 CSS 类。由于 Fontisto 支持 CSS,所以可以直接对图标的 CSS 属性进行修改,包括图标大小、颜色、背景等。 + +除此之外,Fontsto 提供了几种方法来开始项目,比如使用 CDN,通过将整个 Fontsto 目录复制到项目中来直接使用 CSS。你可以使用包管理器,如 npm、yarn 或者 bower 等。使用以下命令: + +使用 Fontisto CDN: + +```html + +``` + +使用 CSS: + +```html + + + + + + + + + + + + + +``` + +使用包管理: + +```bash +npm install fontisto // npm +yarn add fontisto // yarn +bower install fontisto // bower +composer require kenangundogan/fontisto // composer +``` + +#### Fontisto 的主要特点 + +* 完全免费用于商业用途。 +* 不需要使用 Javascript。 +* 支持使用 CSS。 +* 完美适配高分辨率显示器。 +* 图标是可伸缩的。 + +你可以在[项目文档](https://fontisto.com/get-started)中找到更多关于 Fontisto 的使用信息。 + +## 5. Streamline Icons + +![Source: [https://streamlineicons.com/](https://streamlineicons.com/)](https://cdn-images-1.medium.com/max/3654/1*6XPQ3ubWvNZ6Mlhyw1uFfA.png) + +[Streamline Icons](https://streamlineicons.com/) 是另一个优秀的图标库,你可以在项目开发中使用。Streamline 大约有 30000 个漂亮的可适应性图标,包括 50 多个类别。Streamline 图标库以其对优化草图的支持而出名,这使得操作图标宽度和颜色变得容易。你可以在 Streamline 中创建一个免费账户并开始使用图标,也可以直接将整个图标集下载到你的设备上。像 Icon8、Font Awesom 和 FlatiCoin 一样,Streamline 支持在下载所需图标之前进行编辑。你可以轻松更改像素大小、格式,并在类似设计之间切换。但是,除非升级软件包,否则无法更改图标的颜色。 + +![Screenshot by Auther: Customizing icons in Streamline Icons](https://cdn-images-1.medium.com/max/3092/1*ZMkeZRebdIvYGxGYR5J9TQ.png) + +#### Streamline Icons 的主要特点 + +* 提供 Sketch、AI、EPS、PDF、PNG 和 SVG 格式。 +* 用于搜索和编辑图标的 Web 应用程序。 +* 三个套餐版本,包括免费版、基础版和旗舰版。 +* 免费版中有 30000 个图标可供使用。 +* 基础版包含 12000 多个图标,有 .iconjar .sketch .fig .xd .svg .ai .pdf .png 等类型,售价 194 美元,而旗舰版包含 31500 多个图标。 + +**缺点** + +* 除非你购买了付费高级套餐,否则必须注明出处。 + +## 总结 + +以上图标库只是互联网上许多可用库的子集,由于它们的实用性和丰富的功能集而流行。然而,一个优秀的图标库只是开发者选择图标库的一个方面。最好要考虑图标升级的适用性、易用性,以及使用所选图标库在开发项目的启动速度。 + +此外,决定是购买图标还是坚持使用免费图标也很重要,因为你可能需要考虑其中一些图标需要注明出处。可定制性和可用格式也是选择这些图标的考虑因素,大多数时候,每个图标库都包含其独特的设计类别,如材质、矢量、CSS、SVG 等。 + +因此,在为开发项目选择图标库之前,请考虑一下从本文中学到的知识。我相信这会让你的工作流程更顺畅。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/ultimate-guide-to-swiftui2-application-lifecycle.md b/article/2021/ultimate-guide-to-swiftui2-application-lifecycle.md new file mode 100644 index 00000000000..4de919a9a4c --- /dev/null +++ b/article/2021/ultimate-guide-to-swiftui2-application-lifecycle.md @@ -0,0 +1,297 @@ +> * 原文地址:[The Ultimate Guide to the SwiftUI 2 Application Life Cycle](https://peterfriese.dev/ultimate-guide-to-swiftui2-application-lifecycle/) +> * 原文作者:[Peter Friese](https://peterfriese.dev/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/ultimate-guide-to-swiftui2-application-lifecycle.md](https://github.com/xitu/gold-miner/blob/master/article/2021/ultimate-guide-to-swiftui2-application-lifecycle.md) +> * 译者:[zhuzilin](https://github.com/zhuzilin) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[zenblo](https://github.com/zenblo) + +![Image based on [Rocket](https://thenounproject.com/kavya261990/collection/space/?i=3437783) by [Icongeek26](https://thenounproject.com/kavya261990) on [The Noun Project](https://thenounproject.com/)](https://cdn-images-1.medium.com/max/2880/1*nhb0C-BMierO2SW0bvtKqA.png) + +# SwiftUI 2 应用生命周期的终极指导 + +在很长一段时间里,iOS 开发者们都是使用 `AppDelegate` 作为应用的主要入口。随着 SwiftUI 2 在 WWDC 2020 上发布,苹果公司引入了一个新的应用生命周期。新的生命周期几乎(几乎)完全与 `AppDelegate` 无关,为类 DSL 方法铺平了道路。 + +在本文中,我会讨论引入新的生命周期的原因,以及你该如何在已有的应用或新的应用中使用它。 + +## 指定应用入口 + +我们的第一个问题是,该如何告诉编译器哪里是应用的入口呢?[SE-0281](https://github.com/apple/swift-evolution/blob/master/proposals/0281-main-attribute.md) 详述了**基于类型的程序入口(Type-Based Program Entry Points)**的工作方式: + +> Swift 编译器将识别标注了 `@main` 属性的类型为程序的入口。标有 `@main` 的类型有一个隐式要求:类型内部需要声明一个静态 `main()` 方法。 + +创建新的 SwiftUI 应用时,应用的主类(main class)如下所示: + +```swift +import SwiftUI + +@main +struct SwiftUIAppLifeCycleApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} +``` + +那么 SE-0281 提到的静态 `main()` 函数在哪儿呢? + +实际上,框架可以(并且应该)为用户提供方便的默认实现。你会从上面的代码片段注意到 `SwiftUIAppLifeCycleApp` 遵循 `App` 协议。对于 `App` 协议,苹果提供了如下协议扩展: + +```swift +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +extension App { + + /// 初始化并运行应用。 + /// + /// 如果你在你的 ``SwiftUI/App`` 的实现类(conformer)的声明前加上了 + /// [@main](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626) + /// 属性,系统会调用这个实现类的 `main()` 方法来启动应用。 + /// SwiftUI 提供了该方法的默认实现,从而能以适合平台的方式处理应用启动流程。 + public static func main() +} +``` + +这下你就懂了吧 —— 这个协议扩展提供了处理应用启动的默认的实现。 + +由于 SwiftUI 框架不是开源的,所以我们看不到苹果是如何实现此功能的,但是 [Swift Argument Parser](https://github.com/apple/swift-argument-parser) 是开源的,并且也用了这个办法。查看 `ParsableCommand` 的源码,就能了解它是如何用协议扩展来提供静态 `main` 函数的默认实现,并将其用作程序入口的: + +```swift +extension ParsableCommand { +... + public static func main(_ arguments: [String]?) { + do { + var command = try parseAsRoot(arguments) + try command.run() + } catch { + exit(withError: error) + } + } + + public static func main() { + self.main(nil) + } +} +``` + +如果上述这些听起来有点复杂,好消息是实际上在创建新的 SwiftUI 应用程序时你不必关心它:只需确保在 **Life Cycle** 下拉菜单中选择 **SwiftUI App** 来创建你的应用程序就行了: + +![**创建一个新的 SwiftUI 项目**](https://cdn-images-1.medium.com/max/2000/0*XWa5RgMK2WllmlHk.png) + +让我们来看一些常见的情况。 + +## 初始化资源 / 你最喜欢的 SDK 或框架 + +大多数应用程序需要在启动时执行这些步骤:获取一些配置值,连接数据库或者初始化框架或第三方 SDK。 + +通常,您可以在 `ApplicationDelegate` 的 `application(_:didFinishLaunchingWithOptions:)` 方法中进行这些操作。由于已经没有应用委托了,我们需要找到其他方法来初始化我们的应用程序。根据您的特定需求,有以下策略: + +* 为你的主类实现一个构造函数(initializer)(详见[文档](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID205)) +* 为存储属性设置初始值(详见[文档](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID206)) +* 用闭包设置属性的默认值(详见[文档](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID232)) + +```swift +@main +struct ColorsApp: App { + init() { + print("Colors application is starting up. App initialiser.") + } + + var body: some Scene { + WindowGroup { + ContentView() + } +} +``` + +如果上述几种策略都无法满足你的需求,你可能还是需要一个 `AppDelegate`。后文会介绍如果能在应用中加入一个 AppDelegate。 + +## 处理你的应用的生命周期 + +了解你的应用程序处于哪种状态有时很有用。例如,你可能希望应用处于活动状态时立即获取新数据,或者在应用程序变为非活动状态并转换到后台后清除所有缓存。 + +通常,您可以在你的 `ApplicationDelegate` 上实现 `applicationDidBecomeActive`,`applicationWillResignActive` 或 `applicationDidEnterBackground`。 + +从 iOS 14.0 起,苹果提供了新的 API,该 API 允许以更优雅,更易维护的方式跟踪应用程序状态:`[ScenePhase](https://developer.apple.com/documentation/swiftui/scenephase)`。你的项目可以有多个场景(scene),不过有时只有一个场景。这些场景将由 `[WindowGroup](https://developer.apple.com/documentation/swiftui/windowgroup)` 展示。 + +SwiftUI 追踪环境中场景的状态,你可以使用 `@Environment` 属性包装器来获取 `scenePhase` 的值,然后使用 `onChange(of:)` modifier 来监听该值的变化: + +```swift +@main +struct SwiftUIAppLifeCycleApp: App { + @Environment(\.scenePhase) var scenePhase + + var body: some Scene { + WindowGroup { + ContentView() + } + .onChange(of: scenePhase) { newScenePhase in + switch newScenePhase { + case .active: + print("App is active") + case .inactive: + print("App is inactive") + case .background: + print("App is in background") + @unknown default: + print("Oh - interesting: I received an unexpected new value.") + } + } + } +} +``` + +值得注意的是,你可以从应用中的其他位置读取该值。当在应用的顶层读取该值时(如上面的代码片段所示),你将获得应用程序中所有阶段(phase)的汇总。`.inactive` 表示你应用中的所有场景均未激活。当在视图中读取 `scenePhase` 时,你将收到包含该视图的阶段值。请记住,你的应用程序在在同一时刻可能包含在不同阶段的多个场景。想了解有关场景阶段的更多详细信息,请阅读苹果的[文档](https://developer.apple.com/documentation/swiftui/scenephase)。 + +## 处理深层链接(Deeplink) + +之前,在处理深层链接时,你需要实现 `application(_:open:options:)`,并将传入的 URL 转给最合适的处理程序。 + +新的应用生命周期模型可以更容易地处理深层链接。在最顶层的场景上添加 `onOpenURL` 就可以处理传入的 URL 了: + +```swift +@main +struct SwiftUIAppLifeCycleApp: App { + var body: some Scene { + WindowGroup { + ContentView() + .onOpenURL { url in + print("Received URL: \(url)") + } + } + } +} +``` + +真正酷的是:你可以在整个应用程序中装上多个 URL 处理程序 —— 让进行深层链接变得很轻松,因为你可以在最合适的位置处理传入的链接。 + +可能的话,你应该使用 [universal links](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content)(或者 [Firebase Dynamic Links](https://firebase.google.com/docs/dynamic-links),它使用了 [universal links for iOS apps](https://firebase.google.com/docs/dynamic-links/operating-system-integrations)),因为它们使用了关联域(associated domain)来创建网站和你的应用之间的链接 —— 这会让你可以安全地共享数据。 + +不过,你仍可以使用[自定义 URL scheme](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app) 来链接应用内部的内容。 + +无论哪种方式,触发应用中的深层链接的一种简单方法是在开发计算机上使用以下命令: + +```bash +xcrun simctl openurl booted +``` + +![Demo: Opening deep links and continuing user activities](https://cdn-images-1.medium.com/max/2000/1*RMYt_zbKht6oqYJdTn9S_w.gif) + +## 继续用户 activity + +如果你的应用使用 `NSUserActivity` 来[集成](https://developer.apple.com/documentation/foundation/nsuseractivity) Siri、Handoff 或 Spotlight,你需要处理用户继续进行的 activity。 + +同样,新的应用生命周期模型通过提供两个 modifier 使你更容易实现这一点。这些 modifier 使你可以声明 activity 并让用户可以继续进行它们。 + +下面是一个展现如何声明 activity 的代码片段。在一个具体的视图里: + +```swift +struct ColorDetailsView: View { + var color: String + + var body: some View { + Image(color) + // ... + .userActivity("showColor") { activity in + activity.title = color + activity.isEligibleForSearch = true + activity.isEligibleForPrediction = true + // ... + } + } +} +``` + +为了允许继续进行这个 activity,你可以在最顶层的导航视图中注册 `onContinueUserActivity` 闭包,如下所示: + +```swift +import SwiftUI + +struct ContentView: View { + var colors = ["Red", "Green", "Yellow", "Blue", "Pink", "Purple"] + + @State var selectedColor: String? = nil + + var body: some View { + NavigationView { + ScrollView { + LazyVGrid(columns: columns) { + ForEach(colors, id: \.self) { color in + NavigationLink(destination: ColorDetailsView(color: color), + tag: color, + selection: $selectedColor) { + Image(color) + } + } + } + .onContinueUserActivity("showColor") { userActivity in + if let color = userActivity.userInfo?["colorName"] as? String { + selectedColor = color + } + } + } + } + } +} +``` + +## 请帮帮我 —— 上述的那些对我都不管用! + +新的应用声明周期(截止当前)并非支持 `AppDelegate` 的所有回调函数。如果上述这些都不满足你的需求,你可能还是需要一个 `AppDelegate`。 + +另一个需要 AppDelegate 的原因是你使用的第三方 SDK 会使用 [method swizzling](https://pspdfkit.com/blog/2019/swizzling-in-swift/) 来把它们注入应用生命周期。[Firebase](https://firebase.google.com/) 就是一个[典型的例子](https://stackoverflow.com/a/62633158/281221)。 + +为了帮助上述情况中的你摆脱困境,Swift 提供了一种将 `AppDelegate` 的一个实现类与你的 `App` 实现相连接的方法:`@UIApplicationDelegateAdaptor`。使用方法如下: + +```swift +class AppDelegate: NSObject, UIApplicationDelegate { + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + print("Colors application is starting up. ApplicationDelegate didFinishLaunchingWithOptions.") + return true + } +} + +@main +struct ColorsApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} +``` + +如果你是在复制现有的 `AppDelegate` 实现,不要忘记删除 `@main` 属性 —— 不然,编译器该向你抱怨存在多个应用入口了。 + +## 总结 + +至此,让我们讨论一下苹果为什么要进行这些改变。我觉得有以下的几个原因: + +[SE-0281](https://github.com/apple/swift-evolution/blob/master/proposals/0281-main-attribute.md#motivation) explicitly states that one of the design goals was **“to offer a more general purpose and lightweight mechanism for delegating a program’s entry point to a designated type.”** + +苹果选择的基于 DSL 来处理应用生命周期的方法和 SwiftUI 的声明式 UI 搭建方法相契合。两者采用相同的概念可以更方便新加入的开发者们理解。 + +声明式方法的主要好处是:框架/平台将替代开发者承受实现特定功能的负担。如果需要进行任何更改,这种模式可以在不破坏许多开发人员的应用的情况下进行发布,这也使发布更改变得更容易 —— 理想情况下,开发人员无需更改其实现,因为框架将把一切都搞定。 + +总体而言,新的应用生命周期模型使实现应用程序的启动更加简单。你的代码将变得更加简洁,更易于维护 —— 要我说,这总是一件好事。 + +我希望本文能帮你了解新的应用生命周期的来龙去脉。如果你有关于本文的任何疑问或评论,欢迎[在 Twitter 上关注](https://twitter.com/peterfriese)并私信我,或者在 [GitHub 上的样例项目](https://github.com/peterfriese/Colors)中提 issue。 + +感谢你的阅读! + +## 扩展阅读 + +想了解更多,请查看下面的这些资料: + +* [Swift Evolution SE-0281 - @main: Type-Based Program Entry Points](https://github.com/apple/swift-evolution/blob/master/proposals/0281-main-attribute.md) +* [The App Protocol](https://developer.apple.com/documentation/swiftui/app) +* [Allowing Apps and Websites to Link to Your Content](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/undefined-null-revisited.md b/article/2021/undefined-null-revisited.md new file mode 100644 index 00000000000..d115cde6074 --- /dev/null +++ b/article/2021/undefined-null-revisited.md @@ -0,0 +1,486 @@ +> * 原文地址:[undefined vs. null revisited](https://2ality.com/2021/01/undefined-null-revisited.html) +> * 原文作者:[Dr. Axel Rauschmayer](http://dr-axel.de/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/undefined-null-revisited.md](https://github.com/xitu/gold-miner/blob/master/article/2021/undefined-null-revisited.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Moonball](https://github.com/Moonball)、[felixliao](https://github.com/felixliao) + +# 重新审视 undefined 和 null + +很多的编程语言都有一种表示空值的类型,叫做 `null`。它指示了一个变量当前并没有指向任何对象 —— 例如,某个变量还没有初始化的时候。 + +作为不同,JavaScript 则拥有两种表示空值的类型,一种是 `undefined`,另一种则是 `null`。在这篇文章中,我们将测试它们的区别,以及如何去挑选最佳的类型或避免去使用它们。 + +## `undefined` vs. `null` + +两个值都很是相像,并且通常被相互替代着使用,也因此,他们之间的区别很是细微。 + +### `undefined`、`null` 在ECMAScript 语言标准上的对比 + +ECMAScript 语言标准按照如下内容描述他们: + +* `undefined` 是在一个变量还没有被赋值时候使用的。[出处](https://tc39.es/ecma262/#sec-undefined-value) +* `null` 表示任何有意地缺省对象值。[出处](https://tc39.es/ecma262/#sec-null-value) + +我们等下就会探索一下作为程序员,我们应该如何去以最佳的方式使用这两个值。 + +### 两个空值 —— 一个不能弥补的错误 + +在 JavaScript 中同时有两个表示空值的值现在被认为是一个设计错误(哪怕是 JavaScript 之父 Brendan Eich 也这么认为)。 + +那么为什么不从 JavaScript 中删除这两个值之一呢?JavaScript 的一项核心原则是永不破坏向后的兼容性。该原则具有[好处](https://exploringjs.com/impatient-js/ch_history.html#backward-compatibility),但同时也拥有着最大的缺点,即无法弥补设计错误。 + +### `undefined` 和 `null` 的历史 + +在 Java(影响了 JavaScript 很多方面的语言)中初始值依赖于一个变量的静态类型: + +* 以对象值为类型的变量初始化为 `null`。 +* 每个基本类型都拥有它的初始值,例如 `int` 整型对应 `0`。 + +在 JavaScript 中,每一个变量都可以存储对象值或原始值,意味着如果 `null` 表示不是一个对象,那么 JavaScript 也同时需要一个初始值表示既不是一个对象也不拥有原始值,这就是 `undefined`。 + +## `undefined` 的出现场合 + +如果一个变量 `myVar` 还没有被初始化,那么它的值就是 `undefined`: + +```js +let myVar; +assert.equal(myVar, undefined); +``` + +如果一个属性 `.unknownProp` 不存在,访问这个属性就会生成 `undefined` 值: + +```js +const obj = {}; +assert.equal(obj.unknownProp, undefined); +``` + +如果一个函数没有明确返回任何内容,那么默认就会返回 `undefined`: + +```js +function myFunc() { +} + +assert.equal(myFunc(), undefined); +``` + +如果一个函数拥有一个 `return` 语句但没有指定任何返回值,那么也会默认返回 `undefined`: + +```js +function myFunc() { + return; +} + +assert.equal(myFunc(), undefined); +``` + +如果一个参数 `x` 没有传实参,那么就会被初始化为 `undefined`: + +```js +function myFunc(x) { + assert.equal(x, undefined); +} + +myFunc(); +``` + +通过 `obj?.someProp` 访问的[可选链](https://exploringjs.com/impatient-js/ch_single-objects.html#optional-chaining)在` obj` 是 `undefined` 或 `null` 的时候返回 `undefined`: + +```repl +> undefined?.someProp +undefined +> null?.someProp +undefined +``` + +## `null` 的出现场合 + +一个对象的原型要么是另一个对象,要么是原型链末尾的 `null`。`Object.prototype` 没有原型: + +```repl +> Object.getPrototypeOf(Object.prototype) +null +``` + +如果我们使用一个正则表达式(例如 `/a/`)匹配一个字符串(例如 `x`),我们要么得到一个存储着匹配数据的对象(如果匹配成功),要么得到 `null`(如果匹配失败)。 + +```repl +> /a/.exec('x') +null +``` + +[JSON 数据格式](https://exploringjs.com/impatient-js/ch_json.html) 不支持 `undefined`,只支持 `null`: + +```repl +> JSON.stringify({a: undefined, b: null}) +'{"b":null}' +``` + +## 专门用来对付 `undefined` 和 `null` 的操作符 + +### `undefined` 以及默认参数值 + +一个参数的默认值会在以下情况下被使用: + +* 这个参数被我们忽略掉了。 +* 这个参数被赋予 `undefined` 值。 + +举个例子: + +```js +function myFunc(arg = 'abc') { + return arg; +} + +assert.equal(myFunc('hello'), 'hello'); +assert.equal(myFunc(), 'abc'); +assert.equal(myFunc(undefined), 'abc'); +``` + +当指向它的值为一个元值时,`undefined` 也会触发默认参数值。 + +以下的例子示范了这个特性有用的地方: + +```js +function concat(str1 = '', str2 = '') { + return str1 + str2; +} + +function twice(str) { // (A) + return concat(str, str); +} +``` + +在 A 行,我们并没有制定参数 `str` 的默认值,而当这个参数被忽略掉的时候,我们将该状态转发到 `concat()`,让其选择默认值。 + +### `undefined`,解构默认值 + +解构下的默认值的工作方式与参数默认值类似 —— 如果变量在数据中不匹配或与 `undefined` 匹配,则使用它们: + +```js +const [a = 'a'] = []; +assert.equal(a, 'a'); + +const [b = 'b'] = [undefined]; +assert.equal(b, 'b'); + +const {prop: c = 'c'} = {}; +assert.equal(c, 'c'); + +const {prop: d = 'd'} = {prop: undefined}; +assert.equal(d, 'd'); +``` + +### `undefined`、`null` 和可选链 + +如果通过 `value?.prop` 使用了[可选链](https://exploringjs.com/impatient-js/ch_single-objects.html#optional-chaining): + +* 如果 `value` 是 `undefined` 或 `null` 的,将会返回 `undefined`。也就是说,如果 `value.prop` 抛出错误,就会返回 `undefined`。 +* 否则会返回 `value.prop`. + +```js +function getProp(value) { + // 可选的静态属性访问 + return value?.prop; +} + +assert.equal( + getProp({prop: 123}), 123); +assert.equal( + getProp(undefined), undefined); +assert.equal( + getProp(null), undefined); +``` + +以下的两个操作也很是类似的工作: + +```js +obj?.[«expr»] // 可选的动态属性访问 +func?.(«arg0», «arg1») // 可选的函数或方法调用 +``` + +### `undefined`、`null` 和空合并 + +[空合并操作符 `??`](https://exploringjs.com/impatient-js/ch_operators.html#nullish-coalescing-operator) 可让我们在一个值是 `undefined` 或 `null` 时,使用默认值: + +```repl +> undefined ?? 'default value' +'default value' +> null ?? 'default value' +'default value' + +> 0 ?? 'default value' +0 +> 123 ?? 'default value' +123 +> '' ?? 'default value' +'' +> 'abc' ?? 'default value' +'abc' +``` + +[空合并赋值操作符 `??=`](https://2ality.com/2020/06/logical-assignment-operators.html) 合并了空合并操作符与赋值操作符: + +```js +function setName(obj) { + obj.name ??= '(Unnamed)'; + return obj; +} + +assert.deepEqual( + setName({}), + {name: '(Unnamed)'} +); +assert.deepEqual( + setName({name: undefined}), + {name: '(Unnamed)'} +); +assert.deepEqual( + setName({name: null}), + {name: '(Unnamed)'} +); +assert.deepEqual( + setName({name: 'Jane'}), + {name: 'Jane'} +); +``` + +## 处理 `undefined` 与 `null` + +以下的部分解释了在我们代码中最常见的处理 `undefined` 和 `null` 的方法: + +### 实际值既不是 `undefined` 也不是 `null` + +例如,我们可能希望属性 `file.title` 始终存在并且始终是字符串,那么有两种常见的方法可以实现此目的。 + +请注意,在此博客文章中,我们仅检查 `undefined` 和 `null`,而不检查值是否为字符串。你需要自己决定是否要添加检查器,作为附加的安全保障措施。 + +#### 同时禁止 `undefined` 和 `null` + +例如: + +```js +function createFile(title) { + if (title === undefined || title === null) { + throw new Error('`title` must not be nullish'); + } + // ··· +} +``` + +为什么选择这个方法? + +* 我们希望以相同的方式处理 `undefined` 和 `null`,因为 JavaScript 代码就是经常那样做,例如: + + ```js + // 检查一个属性是否存在 + if (!obj.requiredProp) { + obj.requiredProp = 123; + } + + // 通过空合并操作符使用默认值 + const myValue = myParameter ?? 'some default'; + + ``` + +* 如果我们的代码中出现了问题,让 `undefined` 或 `null` 出现了,我们需要让它尽早结束执行并抛出错误。 + +#### 同时对 `undefined` 和 `null` 使用默认值 + +例如: + +```js +function createFile(title) { + title ??= '(Untitled)'; + // ··· +} +``` + +我们不能使用参数默认值,因为它只会被 `undefined` 触发。在这里,我们依赖于[空合并赋值运算符 `??=`](https://2ality.com/2020/06/logical-assignment-operators.html)。 + +为什么选择这个方法? + +* 我们希望以相同方式对待 `undefined` 和 `null`(见上文)。 +* 我们希望我们的代码无声但有力地对待 `undefined` 和 `null`。 + +### `undefined` 或 `null` 是一个被忽略的值 + +例如,我们可能希望属性 `file.title` 是字符串或是被忽略的值(即 `file` 没有标题),那么有几种方法可以实现此目的。 + +#### `null` 是被忽略值 + +例如: + +```js +function createFile(title) { + if (title === undefined) { + throw new Error('`title` 不应该是 undefined'); + } + return {title}; +} +``` + +或者,`undefined` 也可以触发默认值: + +```js +function createFile(title = '(Untitled)') { + return {title}; +} +``` + +为什么要选择这个方法? + +* 我们需要一个空值来表示被忽略。 +* 我们不希望空值触发参数默认值并破坏默认值。 +* 我们想将空值字符串化为 JSON(这是我们无法对 `undefined` 进行的处理)。 + +#### `undefined` 是被忽略的值 + +例如: + +```js +function createFile(title) { + if (title === null) { + throw new Error('`title` 不应该是 null'); + } + return {title}; +} +``` + +为什么选择这种方法? + +* 我们需要一个空值来表示被忽略。 +* 我们确实希望空值触发参数或解构默认值。 + +`undefined` 的一个缺点是它通常是在 JavaScript 中意外赋予的 —— 在未初始化的变量,属性名称中的错字,忘记从函数中返回内容等。 + +#### 为什么不同时将 `undefined` 和 `null` 看作是被忽略的值? + +当接收到一个值时,将 `undefined` 和 `null` 都视为 “空值” 是有意义的。 但是,当我们创建值时,我们不希望模棱两可,以避免不必要的麻烦。 + +这指向了另一种角度:如果我们需要一个被忽略的值,但又不想使用 `undefined` 或 `null` 作为被忽略值时该怎么办?看看下文吧: + +### 其他处理被忽略值的方法 + +#### 特殊值 + +我们可以创建一个特殊值,每当属性被忽略时 `.title` 时就使用该值: + +```js +const UNTITLED = Symbol('UNTITLED'); +const file = { + title: UNTITLED, +}; +``` + +#### Null 对象模式 + +**Null 对象模式** 来自 OOP(面对对象编程): + +* 一个公共超类的所有子类都具有相同的接口。 +* 每个子类实现一种不同的模式供其实例使用。 +* 这些模式之一是 `null`。 + +在下文中,`UntitledFile` 继承了 “null” 模式。 + +```js +// Abstract superclass +class File { + constructor(content) { + if (new.target === File) { + throw new Error('Can’t instantiate this class'); + } + this.content = content; + } +} + +class TitledFile extends File { + constructor(content, title) { + super(content); + this.title = title; + } + + getTitle() { + return this.title; + } +} + +class UntitledFile extends File { + constructor(content) { + super(content); + } + + getTitle() { + return '(Untitled)'; + } +} + +const files = [ + new TitledFile('Dear diary!', 'My Diary'), + new UntitledFile('Reminder: pick a title!'), +]; + +assert.deepEqual( + files.map(f => f.getTitle()), + [ + 'My Diary', + '(Untitled)', + ]); +``` + +我们也可以只为标题(而不是整个文件对象)使用空对象模式。 + +#### “也许”类型 + +“也许”类型是一种函数编程技术: + +```js +function getTitle(file) { + switch (file.title.kind) { + case 'just': + return file.title.value; + case 'nothing': + return '(Untitled)'; + default: + throw new Error(); + } +} + +const files = [ + { + title: {kind: 'just', value: 'My Diary'}, + content: 'Dear diary!', + }, + { + title: {kind: 'nothing'}, + content: 'Reminder: pick a title!', + }, +]; + +assert.deepEqual( + files.map(f => getTitle(f)), + [ + 'My Diary', + '(Untitled)', + ]); +``` + +我们本可以通过数组对 "just" 和 "nothing" 进行编码,但我们的方法的好处是 TypeScript 对其有很好的支持(通过[可辨识联合](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminate-unions))。 + +## 我的方法 + +我不喜欢将 `undefined` 用作被忽略的值的原因有三个: + +* `undefined` 通常是在 JavaScript 中意外出现的。 +* `undefined` 会触发参数和解构的默认值(出于某些原因,某些人更喜欢 `undefined`)。 + +因此,如果需要特殊值,可以使用以下两种方法之一: + +* 我将 `null` 用作被忽略的值。(顺便说一句,TypeScript 相对较好地支持了这种方法。) +* 我通过上述的其中一种技术避免了同时出现 `undefined` 和 `null` 的情况,优点在乎让代码更干净,而缺点在于需要做出更多的工作。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/understanding-css-grid.md b/article/2021/understanding-css-grid.md new file mode 100644 index 00000000000..4f58044ad81 --- /dev/null +++ b/article/2021/understanding-css-grid.md @@ -0,0 +1,200 @@ +> * 原文地址:[Responsive CSS Grid: The Ultimate Layout Freedom](https://medium.muz.li/understanding-css-grid-ce92b7aa67cb) +> * 原文作者:[Christine Vallaure](https://medium.com/@christinevallaure) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/understanding-css-grid.md](https://github.com/xitu/gold-miner/blob/master/article/2021/understanding-css-grid.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[zenblo](https://github.com/zenblo)、[Chorer](https://github.com/Chorer)、[lsvih](https://github.com/lsvih) + +# 自适应 CSS 栅格:自由布局的最终版本 + +![](https://cdn-images-1.medium.com/max/2800/0*MJfiLHUiFLi5M2sm.png) + +CSS 栅格布局(Grid)是一种全新的在 Web 上创建二维布局的方法。我们仅需几行 CSS,就可以创建一个之前不用 JavaScript 根本不可能实现的栅格布局。我们不需要任何插件或复杂的安装步骤,不需要繁琐的附加文件,同时也不需要局限于 12 列的栅格布局(译者注:指 Bootstrap 提供的 12 栅格系统)。 + +## 我们可以使用什么栅格? + +简而言之:我们实际上可以使用**几乎所有能够想到的栅格布局**,并且还不限于此。我们可以自由地选择不同栅格的尺寸、大小和位置。你可以在[栅格示例](https://gridbyexample.com/examples/)中找到最常见的带有标记的栅格的概述。 + +### 让我们从构建示例的 HTML 标记开始吧! + +一个类名为 `container` 的 `div` 元素容纳了 5 个子 `div` 元素,或称之为项目(当然,可以比 5 个更多或者更少)。如果你愿意,我们可以直接从 [CodePen 中的 HTML 和 CSS 标记](https://codepen.io/chrisvall/pen/YJJdxQ)代码入手。 + +```html +
+
item-1
+
item-2
+
item-3
+
item-4
+
item-5
+
+``` + +![我额外添加了一些 CSS 代码让大家更好理解,与 Grid 实现毫无关系](https://cdn-images-1.medium.com/max/2800/0*lCX1UQBdGhuXCuJl.jpeg) + +### 基础:在 CSS 中设置栅格和行列 + +在 CSS 中,我们可以通过 `display: grid` 定义将 `.container` 类的元素变为栅格布局。通过使用 `grid-template-columns`,我们划分了所需的列(本例中将划分 5 列,每列设置为 250px)。通过使用 `grid-template-rows`,我们可以设置行的高度(如果需要的话),本例中是 150px。完成以上步骤之后,我们就实现了第一个栅格布局! + +```css +.container { + display: grid; + grid-template-columns: 250px 250px 250px 250px 250px; + grid-template-rows: 150px; +} + +/* 缩写: + grid-template-columns: repeat(5, 250px); */ +``` + +![](https://cdn-images-1.medium.com/max/2800/0*yYYJTjLzTLzogzyu.jpeg) + +### 设置间隔 + +我们可以使用 `grip-gap` 来设置每一项之间的间隔,也可以使用 `column-gap` 和 `row-gap` 分别设置水平和垂直的间隔。顺便提一句,我们可以使用所有通用单位,例如使用 `px` 用于设置固定的间隔,或使用 `%` 来设置自适应的间隔。 + +```css +.container { + display: grid; + grid-template-columns: repeat(5, 250px); + grid-template-rows: 150px; + grid-gap: 30px; +} +``` + +![需要注意的是容器的左边会将间隔减半,因此在本例中他们的间隔是 15px(对大多数其它的栅格同理)](https://cdn-images-1.medium.com/max/2800/0*CR0ENpYQu_-fNCuD.png) + +### 使用 `fr` 自动填充剩余空间 + +这可是每一个设计师的梦想!我们可以使用 **分数单位**(Fractional Units)或简写 `fr`,根据我们自己的想法分配可用空间!例如,在这里,我们将屏幕空间划分为 6 个部分。 第一列占用空间的 1/6 = 1fr,第二列 3/6 = 3fr,第三列 2/6 = 2fr。当然,我们也可以根据需要添加 `grid-gap`。 + +```css +.container { + display: grid; + grid-template-columns: 1fr 3fr 2fr; +} +``` + +![](https://cdn-images-1.medium.com/max/2980/0*yh7hFOcFs43LM9q8.gif) + +现在所有的行都是自适应的! + +### 混合使用 `px` 和 `fr` 构建自适应而又固定的列 + +`px` 和 `fr` 的按需同时使用可以让栅格适应可用的空间,这非常好用! + +```css +.container { + display: grid; + grid-template-columns: 300px 3fr 2fr; +} +``` + +![第一列用了 `px` 去固定尺寸,而剩余的布局是自适应的](https://cdn-images-1.medium.com/max/2000/0*9buHg29Y9pG0bJir.gif) + +### 排序上的绝对自由 + +私以为,最棒的是在栅格中,我们可以自由设置每一项所占用的尺寸!我们可以用 `grid-column-start` 设置起点,并用 `grid-column-end` 设置终点,或采用缩写方式 `grid-column: startpoint / endpoint;`: + +```css +.container { + display: grid; + grid-template-columns: 1fr 3fr 2fr; +} + +.item-1 { + grid-column: 1 / 4; +} + +.item-5 { + grid-column: 3 / 4; +} +``` + +![](https://cdn-images-1.medium.com/max/2800/0*fGVZP5_NMbf9UJs3.png) + +别被栅格线所迷惑,它们总是在第一项的开始! + +### 同样适用于垂直或全区域的分布! + +在这方面 CSS Grid 耀眼十足,表现出了对比 Bootstrap 和 Co 的优越性 —— 借助 `grid-row`,每一项都可以定义任意的位置及宽度。正如我们将在下一个示例中看到的那样,这对于适应不同屏幕尺寸和设备具有绝对优势: + +```css +.container { + display: grid; + grid-template-columns: 1fr 3fr 2fr; +} + +.item-2 { + grid-row: 1 / 3; +} + +.item-1 { + grid-column: 1 / 4; + grid-row: 3 / 4; +} +``` + +![任何垂直方向上的宽度和位置 ](https://cdn-images-1.medium.com/max/2800/0*a3fS5-GjETjWhArV.png) + +### 想要适应不同的屏幕尺寸和设备?当然没问题! + +CSS Grid 与常规栅格相比也具有明显的优势,根据屏幕大小,我们不仅可以通过媒体查询从自适应值切换到固定值,还可以调整整个项目的位置! + +```css +.container { + display: grid; + grid-template-columns: 250px 3fr 2fr; +} + +.item-1 { + grid-column: 1 / 4; +} + +.item-2 { + grid-row: 2 / 4; +} + +@media only screen and (max-width: 720px) { + .container { + grid-template-columns: 1fr 1fr; + } + + .item-1 { + grid-column: 1 / 3; + grid-row: 2 / 3; + } + + .item-2 { + grid-row: 1 / 1; + } +} +``` + +![](https://cdn-images-1.medium.com/max/2856/0*zF54G2_cLwYLyNh-.gif) + +## 浏览器支持 + +现在,所有现代浏览器(Safari、Chrome、Firefox、Edge)都原生地支持 CSS Grid。凭借 87.85% 的全球支持率(译者注:截止至译文发布时,支持率已达到 95.47%),CSS Grid 已经成为 Boostrap 和 Co 的替代品。 + +![2021 年 3 月的状态,数据来自 [caniuse.com](https://caniuse.com/#search=CSS%20Grid)](https://github.com/PassionPenguin/gold-miner-images/blob/master/understanding-css-grid-caniuse.com__search=CSS%2520Grid.png?raw=true) + +## CSS 栅格的实践案例 + +- [christinevallaure.com,](http://www.christinevallaure.com),UX/UI 设计 +- [moonlearning.io](https://moonlearning.io/),UX/UI 在线课程 +- [Slack](https://slack.com/intl/de-de/),企业网站 +- [Medium](https://medium.com/),原文发布的地方 +- [Skyler Hughes](https://photo.skylerhughes.com/),摄影网站 +- [Max Böck](https://mxb.at/),前端开发者网站 +- [Design+Code](https://designcode.io/),Web 设计师站点 +- [Hi Agency, Deck](http://www.hi.agency/deck/),模版页面 + +## 在你开始使用 Grid 之前 + +我想你可能还会喜欢我在 [moonlearning.io](https://moonlearning.io/) 或[完整的设计移交到开发课程](https://www.udemy.com/course/design-handoff/?referralCode=1296BF141742FFA166C2) 上发布的其它文章和课程(有关如何使用 Grid 的更多信息!)。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/understanding-rust-ownership-borrowing-lifetimes.md b/article/2021/understanding-rust-ownership-borrowing-lifetimes.md new file mode 100644 index 00000000000..037613173ee --- /dev/null +++ b/article/2021/understanding-rust-ownership-borrowing-lifetimes.md @@ -0,0 +1,467 @@ +> * 原文地址:[Understanding Rust: ownership, borrowing, lifetimes](https://medium.com/@bugaevc/understanding-rust-ownership-borrowing-lifetimes-ff9ee9f79a9c) +> * 原文作者:[bugaevc](hhttps://medium.com/@bugaevc) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/understanding-rust-ownership-borrowing-lifetimes.md](https://github.com/xitu/gold-miner/blob/master/article/2021/understanding-rust-ownership-borrowing-lifetimes.md) +> * 译者:[大宁的洛竹](https://github.com/youngjuning) +> * 校对者:[霜羽 Hoarfroster](https://github.com/PassionPenguin)、[Zz招锦](https://github.com/zenblo) + +# 理解 Rust:所有权、借用、生命周期 + +我对这些概念的理解是,你一旦掌握了它,所有这些语法都会看起来自然且优雅。 + +我不会从零开始展开教学,也不会机械地重复官方文档的内容(虽然说有时会 🙈)—— 如果你还不了解这些概念,那么你现在应该读一下[对应章节](https://kaisery.github.io/trpl-zh-cn/ch04-00-understanding-ownership.html)的内容,因为本文是对书上内容的补充,而不是要替代它。 + +另外,我也建议你读一下[这篇](http://blog.skylight.io/rust-means-never-having-to-close-a-socket/)出色的文章。它实际上是在讲述相近的话题,但关注点不一样,也值得一读。 + +让我们先来谈谈资源是什么。资源是宝贵的、“沉重的”、可以获取和释放(或销毁)的东西,比如一个套接字,一个打开的文件,一个信号量,一个锁,一个堆内存区域。按照传统,所有这些事情都是通过调用一个函数来创建的,该函数返回对资源本身的某种引用(一个内存指针或一个文件描述符),当程序认为自己已完成对资源的处理时,需要程序员 👨🏻‍💻 显式关闭该文件。 + +这种方法存在着问题。人非圣贤,孰能无过。通常我们很容易忘记释放某些资源,从而导致发生所谓的**内存泄漏**。更糟糕的是,人们可能会尝试访问已经释放的资源(即在释放之后使用)。如果运气好,他们会收到一条报错消息,这可能会帮助他们识别和修复错误,也可能不会。反之,它们所具有的引用(尽管就逻辑而言是无效的)可能仍是引用某个“内存位置”,而该“内存位置”已经被其他资源占用。例如说已存储其他内容的内存,其它打开的文件所使用的文件描述符等。试图通过无效的引用访问旧资源可能会破坏其他资源或使得程序完全崩溃。 + +我们讨论这些问题并不是杞人忧天,因为它们无时无刻伴随着我们。比如,在 [Google Chrome 发布博客](http://googlechromereleases.blogspot.ru/search/label/Stable%20updates)中就存在着大量因为使用了被释放的资源引发的漏洞和崩溃的修复记录 —— 这也极大的浪费了人力物力,去识别和修复它们。 + +并不是说开发人员是愚蠢和健忘的,因为逻辑流程本身就容易出错:它需要你显示释放资源,但是并不强制你做这些。此外,我们通常不会注意到资源被忘记释放,因为这个问题很少会有着什么明显的影响。 + +有时要实现简单的目地就需要发明复杂的解决方案,而这些解决方案会带来更复杂的逻辑。我们很难避免在庞大的代码库中迷失,并且 Bug 总是在这里或那里突然冒出来,我们最终也见怪不怪了。其中大多数的问题都很容易被发现,但是与资源相关的错误却很难被发现。因此,一旦如果资源被野指针利用,便会非常危险。 + +![](https://i.loli.net/2021/03/01/xBOd1QFu27Kfkp6.png) + +当然,像 Rust 这样的新语言无法为你解决 Bug,但是,它可以成功地影响你的思维方式,将一些架构带入你的思想,从而使这类错误的发生几率大大降低。 + +Rust 为你提供了一种安全清晰的方法来管理资源。而且,它不允许你以其他任何方式对其进行管理。这是非常严格的,但这不正是我们的目的吗? + +这些限制之所以很棒,有几个原因: + +- 它们能让你以正确的方式思考。在有了一些 Rust 开发经验后,即使在其他语言的语法中没有内置这些概念时,你也经常会发现自己尝试应用相似的概念。 +- 它们能让你编写的代码更安全。除了几个很稀有的[极端案例](https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html),Rust 基本上可以保证你所有的代码都不会涉及我们正在谈论的错误。 +- 虽然如果有垃圾收集机制,Rust 就会像高级语言一样令人愉悦(我可没说 JavaScript 是令人愉悦的!),但是 Rust 与其他低级编译语言一样快且接近底层。 + +考虑到这一点,让我们来看一下 Rust 的一些优点。 + +## 所有权 + +在 Rust 中,关于资源属于哪块代码有很明确的规则。在最简单的情况下,是代码块创建了代表资源的对象。在代码块的末尾,对象被销毁且资源被释放。这里重要的区别是对象不是某种容易忘记的“弱引用”。在内部,该对象只是用于完全相同引用的包装器,而从外部看,它似乎是它表示的资源。当到达拥有资源的代码块的末尾时,资源将会自动且可预测地释放。 + +当编译到拥有该内存的代码的尾部,程序会自动且安全地释放资源。妈妈再也不用担心忘记释放资源了!因为该行为是全自动且可预测的,它完全会按照你的预期来完成。 + +这时你可能会问,为什么我要描述这些琐碎而明显的事情,而不是仅仅告诉你聪明人称之为 [RAII](https://zh.wikipedia.org/wiki/RAII) 的概念? 好吧,让我们继续聊一下。 + +这个概念适用于临时对象。比如以下操作:`将一些文本写入文件` -> `专用代码块(例如,一个函数)将打开一个文件`(结果是得到一个文件对象(包装文件描述符))-> `然后对其进行一些处理` -> `然后在该块的末尾将得到文件对象` -> `最后删除并且文件描述符关闭`。 + +但是在很多场景中这个概念并不管用。你可能希望将资源传递给其他人,在几个“用户”之间甚至在线程之间共享它。 + +让我们来看看这些。首先,你可能希望将资源传递给其他人(转移所有权),被转移的人便会拥有资源,可以对资源进行任何操作,甚至更重要的是负责释放资源。Rust 很好的支持了这一点,实际上,当你将资源提供给其他人时,默认便会发生这种情况。 + +```rust +fn print_sum(v: Vec) { + println!("{}", v[0] + v[1]); + // v 被移除随后被释放 +} + +fn main() { + let mut v = Vec::new(); // 资源在这里被创建 + for i in 1..1000 { + v.push(i); + } + // 在这里, 可变变量 v 被使用 + // 不少于 4000 字节的内存 + // ------------------- + // 转移所有权给 print_sum 函数 + print_sum(v); + // 我们不拥有并且不能以任何方式控制变量 v + // 在这里尝试访问 v 将引发编译时错误 + println!("We're done"); + // 这里并不会发生任何释放动作 + // 因为 print_sum 此时负责可变变量 v 的一切 +} +``` + +所有权转移的过程也称为**移动**,因为资源是从旧位置(例如,局部变量)被移动到了新位置(例如,一个函数参数)的。从性能角度来看,这只是“弱引用”被移动,因此这个过程很快。但是对于代码来说,好像我们实际上将整个资源都移到了新地方。 + +移动和复制是有区别的。广义来说,它们都意味着复制数据(如果 Rust 允许复制资源的话,这种情况下将是“弱引用”),但移动后,原始变量的内容将被视为不再有效或不再重要。Rust 实际上会将该变量视为“ [逻辑上未初始化](https://doc.rust-lang.org/nomicon/checked-uninit.html)”,也就是说,充满了一些垃圾,例如刚刚创建的那些变量。这类变量是被禁止使用的(除非你使用新值重新初始化它),此时也不会发生资源的重新分配:现在拥有资源的人有责任在完成后进行清理。 + +移动不仅限于传递参数。你可以移动给一个变量。你还可以移至返回值。为此,你可以从返回值、变量、函数参数移动。基本上到处都是隐式和显示的分配。 + +尽管移动语法是处理资源的完全合理的方式,我将在稍后演示对于普通的旧原始数字类型变量来说,这将是一场灾难(设想无法复制一个 int 类型变量的值给另一个变量)。幸运的是,Rust 有 [Copy 特征](https://doc.rust-lang.org/std/marker/trait.Copy.html)。实现它的类型(所有原始类型都使用)在分配时使用复制语法,所有其他类型都使用移动语法。这非常容实现,如果你希望自己的类型是可以被复制的,则只需要可选地实现 `Copy` 特征。 + +```rust +fn print_sum(a: i32, b: i32) { + println!("{}", a + b); + // 被复制的 a 和 b 变量在这里被移除和释放 +} + +fn main() { + let a = 35; + let b = 42; + // 复制和传递值 + // 被复制的值传递的所有权传递给 print_sum: + print_sum(a, b); + // 我们仍然保留对原始a和b变量的完全控制权 + println!("We still have {} and {}", a, b); + // 原始的 a 和 b 被移除并随后被释放 +} +``` + +现在,我们来探讨下为什么移动语法会有用呢?如果没有他们,一切都显得那么完美。好吧,也不完全是。有时候,这是最合乎逻辑的事情。比如 [with_capacity](https://doc.rust-lang.org/std/string/struct.String.html#method.with_capacity) 函数会分配一个字符串缓冲区,然后将其返回给调用方。所有权被转移了,并且该函数不再关心缓冲区的生死。而调用者可以完全控制缓冲区,包括负责缓冲区的释放。 + +在 C 语言中是一样的。诸如 `strdup` 之类的功能将分配内存,将其内存管理交给你,并期望你进行管理并最终对其进行分配。区别在于它只是一个指针,它们所能做的就是在完成后要求或提醒你使用 `free()`。上面所说的移动特性几乎无法做到,而在 Rust 中,这是该语言不可分割的一部分。 + +另一个示例是迭代器适配器,比如 [count](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count) 这种无论如何之后都没有访问迭代器的意义。 + +相反的问题是,在什么情况下,我们需要对同一资源有多个引用。最明显的用例是进行多线程处理的场景。否则,如果所有操作都按顺序执行,则移动语法可能总是起作用的。尽管如此,一直来回移动东西还是很不方便的。 + +有时,尽管代码严格按顺序运行,但仍然感觉好像同时发生了几件事。想象一下在 vector(可变数组)上进行迭代。循环完成后,迭代器可以将你对相关 vector 的所有权转移给你,但你将无法在循环内获得对 vector 的任何访问权限。也就是说,除非你每次迭代都在你的代码和迭代器之间拥有所有权,否则那将是一团糟。似乎也无法在不破坏堆栈的情况下遍历一棵树,然后重新构造并备给以后做其他事情时用。 + +同时,我们将无法执行多线程,这就很不方便甚至让人厌烦。值得庆幸的是,还有一个很酷的 Rust 概念可以为我们提供帮助。那就是借用! + +## 借用 + +> 当一个函数使用引用而不是值本身作为参数时,我们便不需要为了归还所有权而特意去返回值,毕竟在这种情况下,我们根本没有取得所有权。这种通过引用传递参数给函数的方法也被成为借用。——《Rust 权威指南》 + +我们有多种角度解读借用: + +- 它使我们在拥有资源的多个引用的同时仍坚持“单一所有者,单一责任”的概念。 +- 引用类似于 C 语言中的指针。 +- 引用也是一个对象。可变引用被移动,不可变引用被复制。删除引用后,借用将终止(取决于生命周期规则,请参见下一节)。 +- 在最简单的情况下,引用的行为就像在没有明确地进行所有权操作的情况下来回移动所有权。 + +下面这段代码就是最后一条的意思: + +```rust +// 没有借用发生 +fn print_sum1(v: Vec) -> Vec { + println!("{}", v[0] + v[1]); + // 返回 v 把所有权返回 + // 顺便一提,由于 Rust 是基于表达式的,所有这里不需要使用 return 关键字便可返回值 + v +} + +// 有借用,明确的引用 +fn print_sum2(vr: &Vec) { + println!("{}", (*vr)[0] + (*vr)[1]); + // vr 是一个引用,在这里被移除,因为借用结束了 +} + +// 这就是你应该做的 +fn print_sum3(v: &Vec) { + println!("{}", v[0] + v[1]); + // 同 print_sum2 +} + +fn main() { + let mut v = Vec::new(); // 创建可变数组 + for i in 1..1000 { + v.push(i); + } + // 此时, v 被使用 + // 不超过 4000 字节的内存 + + // 传递 v 的所有权给 print_sum 并在执行结束后反会 v + v = print_sum1(v); + // 现在,我们重新取得了 v 的所有权 + println!("(1) We still have v: {}, {}, ...", v[0], v[1]); + + // 取 v 的引用传递给 print_sum2(借用它) + print_sum2(&v); + // v 现在仍然可以被使用 + println!("(2) We still have v: {}, {}, ...", v[0], v[1]); + + // 此时仍可以 + print_sum3(&v); + println!("(3) We still have v: {}, {}, ...", v[0], v[1]); + + // v 被移除并在此处被释放 +} +``` + +让我们看看这里发生了什么。第一个函数中,我们可以始终转移所有权,但是我们已经确信有时这并不是我们想要的。 + +第二个函数中,我们对 vector 进行引用,然后将其传递给函数。和 C 语言很像,我们通过解引用来获取对象。由于没有复杂的生命周期,因此一旦删除引用,借用便会终止。虽然它看起来像第一个示例,但是有一个重要的区别。`main` 函数拥有 vector 的所有权,在借用 vector 时只能对它做些限制。在这个示例中,`main` 函数在借用 vector 时甚至没有机会观察向量,因此这没什么大不了的。 + +第三个函数结合了第一个函数不需要解引用和第二个函数不弄乱所有权的优点。这之所以可行是因为 Rust 的[自动解除引用规则](http://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules)。这些有点复杂,但是在大多数情况下,它们可以使你几乎就像使用引用指向的对象一样编写代码,这和 C++ 的引用很相似。 + +这里是另一个示例: + +```rust +// 通过不可变引用获取 v +fn count_occurences(v: &Vec, val: i32) -> usize { + v.into_iter().filter(|&&x| x == val).count() +} + +fn main() { + let v = vec![2, 9, 3, 1, 3, 2, 5, 5, 2]; + // 为迭代借用 v + for &item in &v { + // the first borrow is still active + // 第一个借用仍生效 + // 我们在这里第二次借用 + let res = count_occurences(&v, item); + println!("{} is repeated {} times", item, res); + } +} +``` + +你无需关心 `count_occurrences` 函数内部发生的事情,只需要知道它借用了 vector 即可(再次提醒,没有移动它)。循环也借用了 vector,因此我们有两个借用处于同时活动状态。循环结束后,`main` 函数将删除 vector。 + +哈哈,我会有点不地道了。我前面提到多线程是需要引用的主要原因,但是我展示的所有示例都是单线程的。如果你真的有兴趣,可以在 Rust 中获得有关多线程的一些[详细信息](https://doc.rust-lang.org/book/concurrency.html)。 + +获取和删除引用似乎很有效,好像涉及到垃圾回收一样。但实际并不是这样的。这一切都在编译时完成。为此,Rust 需要另一个神奇的概念。让我们看下以下示例代码: + +```rust +fn middle_name(full_name: &str) -> &str { + full_name.split_whitespace().nth(1).unwrap() +} + +fn main() { + let name = String::from("Harry James Potter"); + let res = middle_name(&name); + assert_eq!(res, "James"); +} +``` + +这是可以被成功编译的,但下面的代码是无法被编译的: + +```rust +fn middle_name(full_name: &str) -> &str { + full_name.split_whitespace().nth(1).unwrap() +} + +fn main() { + let res; + { + let name = String::from("Harry James Potter"); + res = middle_name(&name); + // `name` 在这里被移除并随后被释放 + } + assert_eq!(res, "James"); +} +``` + +首先,让我们解释下 [`string` 类型](http://doc.rust-lang.org/book/strings.html)。`String` 拥有字符串缓冲区,一个 `&str`(字符串切片)是 `String` 类型的一段或其他内存的一段(在这里并不重要)。 + +为了解释地更加明显,我用 C 语言编写类似的内容: + +> 顺便一提:在 C 语言中,你不能获取字符串的中间部分,因为标记字符串的结尾将需要更改字符串,因此我们仅限于在此处查找姓氏。 + +```c +#include +#include +#include + +const char *last_name(const char *full_name) +{ + return strrchr(full_name, ' ') + 1; +} + +int main() { + const char *buffer = strcpy(malloc(80), "Harry Potter"); + const char *res = last_name(buffer); + free(buffer); + printf("%s\n", res); + + return 0; +} +``` + +你现在明白了吗?在使用结果之前,将删除缓冲区并重新分配缓冲区。这是一个在释放后使用资源的特殊例子。 如果 `printf` 的实现不会立即将内存用于其他用途,则此 C 代码可以编译并运行良好。不过,在一个不那么特殊的示例中,它仍然是崩溃、错误和安全漏洞的来源。正是在介绍所有权之前我们所说的。 + +你甚至无法在 Rust 中进行编译(我的意思是上面的 Rust 代码)。这种静态分析机制已内置在语言中,并且在整个生命周期可用。 + +## 生命周期 + +资源在 Rust 中是有生命周期的。他们从被创造的那一刻起一直存在到被移除的那一刻。生命周期通常被认为是作用域或代码块,但这实际上并不是一个准确的表述,因为资源可以在代码块之间移动,正如我们已经看到的那样。我们无法引用尚未创建或已删除的对象,我们很快就会看到这个要求是如何被强制执行。否则,这一切看起来都与所有权概念并没有什么不同。 + +这是比较难理解的一部分。引用以及其他对象也具有生存期,并且这些生存期可能与它们的借用的生存期不同(所谓的关联生命周期)。 + +让我们来改写下代码。借用的持续时间可能长于它所控制的引用的时间。这通常是因为可以使用另一个引用,该引用取决于借用是否处于活动状态——可以借用相同的对象或只借用其一部分,例如上例中的字符串切片。 + +实际上,每个引用都会记住它所代表的借用期限,也就是说,每一个引用都有一个生命周期。像所有与“借用检查”相关的事情一样,这是在编译时完成的,并且不占用任何运行时开销。与其他事物不同,你有时必须明确指定生命周期详细信息。 + +综上所述,让我们用代码深入探讨下: + +``` rust +fn middle_name<'a>(full_name: &'a str) -> &'a str { + full_name.split_whitespace().nth(1).unwrap() +} + +fn main() { + let name = String::from("Harry James Potter"); + let res = middle_name(&name); + assert_eq!(res, "James"); + + // 不会被编译: + + /* + let res; + { + let name = String::from("Harry James Potter"); + res = middle_name(&name); + } + assert_eq!(res, "James"); + */ +} +``` + +在前面的示例中,我们不必明确地指出生命周期,因为生命周期的细致程度足以让 Rust 编译器自动找出来(请参阅[lifetime elision](https://doc.rust-lang.org/book/lifetimes.html #lifetime-elision))。无论如何,我们已经在这里演示了它们的工作原理。 + +`<>` 表示该函数在整个生命周期内都是通用的,我们称其为 `a`。也就是说,对于具有关联生命周期的任何引用传入,它将返回具有相同关联生命周期的另一个引用。友情提示,关联的生命周期是指借用的生命周期,而不是引用的生命周期。 + +在实践中,它的含义可能不是显而易见的,所以让我们从相反的角度来看它。返回的引用被存储在 `res` 变量中,该变量在 `main()` 的整个范围内都有效。那是引用的生命周期,因此借用(相关的生命周期)至少存在了很长的时间。这意味着函数传入参数的关联生命周期必须相同,因此我们可以得出结论,必须为整个函数借用 `name` 变量。 + +在释放后使用的示例中(此处已注释),`res` 的生命周期仍然是整个函数,而 `name` 的生存周期没有足够长的时间,以至于借用不能在整个函数中有效。如果你尝试编译此代码,毫无疑问会触发编译错误。 + +Rust 编译器尝试使借用的生命周期尽可能短,理想情况下,一旦引用被移除就结束了(这是我在**借用**部分开始时所说的“最简单的情况”)。“借用应有尽可能长的生命周期” 的约束却是以另一种相反的方式运作的,比如从 `result` 到原始借用的生命周期会延伸地很长。只要满足所有约束条件,此过程就会停止,如果无法实现,则会出错。 + +你无法欺骗 Rust 让函数的返回的借用的值与生命周期完全无关,因为那样的话,在函数中你将得到相同的 `does not live long enough` 报错信息,因为不相关的生命周期可能比传入的生命周期长很多。 + +让我们来看下这个示例: + +```rust +fn search<'a, 'b>(needle: &'a str, haystack: &'b str) -> Option<&'b str> { + // 想象这里有一些聪明的算法 + // 返回了一个原始字符串的切片 + let len = needle.len(); + if haystack.chars().nth(0) == needle.chars().nth(0) { + Some(&haystack[..len]) + } else if haystack.chars().nth(1) == needle.chars().nth(0) { + Some(&haystack[1..len+1]) + } else { + None + } +} + +fn main() { + let haystack = "hello little girl"; + let res; + { + let needle = String::from("ello"); + res = search(&needle, haystack); + } + match res { + Some(x) => println!("found {}", x), + None => println!("nothing found") + } + // 输出 "found ello" +} +``` + +`search` 函数接受两个引用,这些引用具有完全不相关的生命周期。尽管 `haystack` 受到限制,但关于 `needle` 的唯一要求是在函数本身执行时借用必须有效。完成后,借用立即结束,我们可以安全地重新分配关联的内存,同时仍然保持函数结果不变。 + +`haystack`是用字符串字面量初始化的。这些是 `&’static str` 类型的字符串切片(一个始终有效的借用)。因此我们可以在需要时将 `res` 变量保持在有效范围内。这是借用期限尽可能短规则的例外。你可以将其视为对“借用字符串”的另一个限制:字符串字面量借用必须持续整个程序的整个执行时间。 + +最后,我们返回的不是引用本身,而是一个内部的复合对象。这是完全支持的并且不会影响我们的一生逻辑。 + +因此,在此示例中,该函数接受两个参数,并且在两个生存期内都是通用的。让我们看看如果我们将生命周期设置为相同,会发生什么情况: + +```rust +fn the_longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { + if s1.len() > s2.len() { s1 } else { s2 } +} + +fn main() { + let s1 = String::from("Python"); + // 明确借用以确保借入的持续时间长于s2 + let s1_b = &s1; + { + let s2 = String::from("C"); + let res = the_longest(s1_b, &s2); + println!("{} is the longest if you judge by name", res); + } +} +``` + +我在内部代码块之外进行了明确的借用,因此借用会在 `main()` 的其余部分都有效。这明显和 `&s2` 的生命周期不一样。如果仅接受两个具有相同生命周期的参数,那么这里为什么可以调用该函数? + +事实证明,相关的生命周期会受到 [类型强制](https://en.wikipedia.org/wiki/Type_conversion) 的约束。与大多数语言(至少是我所熟知的那些语言)不同,Rust 中的原始(整数)值不会强制转换,为此你必须始终明确地强制转换它们。你可以在一些不太明显的地方找到强制转换,例如这些关联的生命周期和 [dynamic dispatch with type erasure](http://doc.rust-lang.org/book/trait-objects.html#dynamic-dispatch)。 + +我们用 C++ 代码进行比较: + +```c++ +struct A { + int x; +}; + +struct B: A { + int y; +}; + +struct C: B { + int z; +}; + +B func(B arg) +{ + return arg; +} + +int main() { + A a; + B b; + /* + * 这很好用:B值是有效的A值 + * 换句话说,只要期望A值,就可以使用B值 + */ + a = b; + /* + * 另一方面,这将是一个错误 + */ + + // b = a; + + // 这能很好地工作 + C arg; + A res = func(arg); + return 0; +} +``` + +派生类型强制为其基本类型。 当我们传递 `C` 的实例时,它强制转换为 `B`,然后返回,强制转换为 `A`,然后存储在 `res` 变量中。 + +同样,在 Rust 中,更长的借用可以被强制缩短。它不会影响借用本身,而只会在需要较短借用的地方起作用。因此,你可以为函数传递寿命比预期更长的借用(它将被强制执行),并且可以强制将返回的借用的生命周期缩短。 + +再考虑一下这个示例: + +```rust +fn middle_name<'a>(full_name: &'a str) -> &'a str { + full_name.split_whitespace().nth(1).unwrap() +} + +fn main() { + let name = String::from("Harry James Potter"); + let res = middle_name(&name); + assert_eq!(res, "James"); + + // 不会被编译: + + /* + let res; + { + let name = String::from("Harry James Potter"); + res = middle_name(&name); + } + assert_eq!(res, "James"); + */ +} +``` + +人们通常会想知道这样的函数声明是否意味着参数的关联生命周期必须(至少)与返回值一样长,反之亦然。 + +答案现在应该很明显。对函数来说,两个生命周期完全相同。但是由于可以强制,你可以将其借用更长的时间,甚至可以在获得结果之后缩短结果的关联生命周期。因此正确的答案是参数必须至少与返回值一样长。 + +而且,如果你创建一个通过引用接受多个参数的函数,并声明它们必须具有相等的关联生命周期(如在我们之前的示例中一样),则该函数的实际参数将被强制为其中最短的生命周期。这只是意味着结果不能超过任何借用的参数。 + +这与我们之前讨论的反向约束规则可以很好地配合。被调用者并不关心这些-它只是获得并返回相同生命周期的借用。 + +另一方面,调用者确保参数的关联生命周期永远不会比结果的生命周期短,可以通过扩展它们来实现。 + +## 小技巧 + +- 你不能移走借用的值,因为在借用结束后该值必须保持有效。即使你在下一行中移回某些内容,也无法将其移出。但是 `[mem::replace](https://doc.rust-lang.org/std/mem/fn.replace.html)` 特征可以让你同时做这两件事。 +- 如果你想拥有一个像 C++ 中的 `unique_ptr` 一样的指针,可以使用 `[Box](https://doc.rust-lang.org/std/boxed/index.html)` 类型。 +- 如果你想进行一些基本的引用计数-例如 C ++ 中的 `shared_ptr` 和 `weak_ptr`,可以使用 [这些标准模块](https://doc.rust-lang.org/std/rc/index.html) +- 如果你确实需要摆脱 Rust 所施加的限制,则可以随时求助于 [unsafe code](https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html) + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/using-immer-with-react-a-simple-solutions-for-immutable-states.md b/article/2021/using-immer-with-react-a-simple-solutions-for-immutable-states.md new file mode 100644 index 00000000000..abd3d06c24d --- /dev/null +++ b/article/2021/using-immer-with-react-a-simple-solutions-for-immutable-states.md @@ -0,0 +1,193 @@ +> * 原文地址:[Using Immer with React: a simple Solutions for Immutable States](https://blog.bitsrc.io/using-immer-with-react-a-simple-solutions-for-immutable-states-a6ebb8b0bfa) +> * 原文作者:[Madushika Perera](https://medium.com/@LMPerera) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/using-immer-with-react-a-simple-solutions-for-immutable-states.md](https://github.com/xitu/gold-miner/blob/master/article/2021/using-immer-with-react-a-simple-solutions-for-immutable-states.md) +> * 译者:[zenblo](https://github.com/zenblo) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[felixliao](https://github.com/felixliao) + +# 在 React 中使用 Immer 管理不可变状态 + +![](https://cdn-images-1.medium.com/max/5760/1*7V7cegDUA84z--4d6GflYg.jpeg) + +在 React 中,使用不可变状态可以快速且高效地比较更改前后的状态树。因此,每个组件可在执行任何成本很高的 DOM 操作之前,决定是否重新渲染。 + +我希望你已经知道: + +> JavaScript 是可变的,我们必须自己实现不可变性。 + +像 Redux 这样流行的状态管理库也遵循着相同的理念。当我们使用 `reducers`(译者注:根级的 reduce 函数 reducer 拆分为多个 reducers)时,它期望我们不要改变状态,以避免产生任何的副作用。但是,对于容易出错的大型项目,手动实现不可变性可能不是最佳选择。 + +> 幸运的是,有着专门的 JavaScript 库例如 [Immer](https://immerjs.github.io/immer/docs/introduction)。它们通过设计,实现了状态树的不可变性。 + +## Immer 简介与使用 + +Immer 是一个小型库,它基于写时拷贝(**copy-on-write** )机制帮助开发者实现不可变状态,这是一种用于在可修改资源上实现复制操作的技术。 + +在 Immer 中,主要有三种状态: + +1. Current State:实际状态数据。 +2. Draft State:所有更改都将应用于此状态。 +3. Next State:该状态是基于 Draft State 的变化而产生的。 + +![Immer states](https://cdn-images-1.medium.com/max/2000/1*-LI_oJ_e_DpY2mahvV1Hug.png) + +从性能的角度来看,与使用 JavaScript 中的 **object.assign()** 或展开运算符的浅拷贝(Shallow Copy)相比,Immer 表现得可谓是相当的好。如果你有兴趣了解更多关于性能的比较方面的信息,请参考此文:[Immer vs 浅拷贝 vs 不可变性的测试](https://www.measurethat.net/Benchmarks/Show/6108/0/immer-vs-shallow-copy-vs-immutable-perf-test)。 + +![Immer 与浅拷贝的性能比较](https://cdn-images-1.medium.com/max/2000/1*5m8fOSOiL4W6nb7mwc2AxA.png) + +Immer 还减少了实现上述基准测试结果所需编写的代码量,这也是 Immer 脱颖而出的原因之一。 + +--- + +现在你已经基本了解 Immer,接下来我们来看一下,为什么 Immer 被公认为是解决不可变性的最佳方案之一。 + +## Immer 的工作原理 + +如果你正在处理简单的状态,可能会觉得 Immer 正在使你的代码更复杂。但是,当涉及处理复杂的数据时,Immer 变得非常有用。 + +为了更好地理解这一点,让我们看看著名的 React reducer 示例: + +```js +export default (state = {}, action) => { + switch (action.type) { + case GET_ITEMS: + return { + ...state, + ...action.items.reduce((obj, item) => { + obj[item.id] = item + return obj + }, {}) + } + default: + return state + } +} +``` + +上述代码是一个 React-Redux 的典型简化示例,它使用 ES6 展开运算符,并深入到状态树对象的嵌套级别来更新值。我们可以使用 Immer 轻松地降低上述代码的复杂性。 + +让我们来看看具体如何使用 Immer 降低上述代码的复杂性。 + +```js +import produce from "immer" + +export default produce((draft, action) => { + switch (action.type) { + case GET_ITEMS: + action.items.forEach(item => { + draft[item.id] = item + }) + } +}, {}) +``` + +> 在这个示例中,Immer 简化了用于扩展状态的代码。你还可以看到它通过使用 `forEach` 循环而不是 ES6 的 `reduce` 函数来改变对象。 + +让我们看另一个示例,将 Immer 与 React 结合使用。 + +```js +import produce from "immer"; + +this.state={ + id: 14, + email: "stewie@familyguy.com", + profile: { + name: "Stewie Griffin", + bio: "You know, the... the novel you've been working on", + age:1 + } +} + +changeBioAge = () => { + this.setState(prevState => ({ + profile: { + ...prevState.profile, + age: prevState.profile.age + 1 + } + })) +} +``` + +可以通过更改如下所示的状态来重构这段代码。 + +```js +changeBioAge = () => { + this.setState( + produce(draft => { + draft.profile.age += 1 + }) + ) +} +``` + +如你所见,Immer 极大地减少了代码行数并降低了代码复杂度。 + +## 结合 Hooks 使用 + +Immer 的另一个重要特性是它支持 React Hooks。Immer 使用一个名为 **use-immer** 的附加库来实现此功能。让我们来看一个示例,以便更好地理解。 + +```js +const [state, setState] = useState({ + id: 14, + email: "stewie@familyguy.com", + profile: { + name: "Stewie Griffin", + bio: "You know, the... the novel you've been working on", + age:1 + } + }); + +function changeBio(newBio) { + setState(current => ({ + ...current, + profile: { + ...current.profile, + bio: newBio + } + })); + } +``` + +通过将 `useState` 替换为 `useImmer` Hook,我们可以进一步简化 Hooks 示例,还可以通过更改组件状态来更新 React 组件。 + +```js +import { useImmer } from 'use-immer'; + +const [state, setState] = useImmer({ + id: 14, + email: "stewie@familyguy.com", + profile: { + name: "Stewie Griffin", + bio: "You know, the... the novel you've been working on", + age:1 + } + }); + +function changeBio(newBio) { + setState(draft => { + draft.profile.bio = newBio; + }); + } +``` + +同样,我们也可以使用 Immer 将 `Array` 和 `Sets` 转换为不可变的对象。通过 Immer 创建的 `Map` 和 `Set` 会在对象发生改变时会报错,从而使开发者能够意识到对象发生改变的错误。 + +> 最重要的是,Immer 不局限于结合 React 使用,你还可以轻松地将 Immer 与原生 JavaScript 结合使用。 + +除了在维持不可变方面之外,Immer 还可以通过降低代码库的复杂度,帮助我们维护一个编写良好且可读性强的代码库。 + +## 本文总结 + +根据我对 Immer 的使用经验,我相信 Immer 与 React 结合使用是一个不错的选择。它将简化项目代码,并通过设计帮助管理不可变状态。 + +你可以通过[参考文档](https://immerjs.github.io/immer/docs/introduction)找到更多关于 Immer 的信息。 + +--- + +感谢大家的阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/using-rust-to-scale-elixir-for-11-million-concurrent-users.md b/article/2021/using-rust-to-scale-elixir-for-11-million-concurrent-users.md new file mode 100644 index 00000000000..bae649d0255 --- /dev/null +++ b/article/2021/using-rust-to-scale-elixir-for-11-million-concurrent-users.md @@ -0,0 +1,102 @@ +> * 原文地址:[Using Rust to Scale Elixir for 11 Million Concurrent Users](https://blog.discord.com/using-rust-to-scale-elixir-for-11-million-concurrent-users-c6f19fc029d3) +> * 原文作者:[discord.matt](https://medium.com/@discord.matt) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/using-rust-to-scale-elixir-for-11-million-concurrent-users.md](https://github.com/xitu/gold-miner/blob/master/article/2021/using-rust-to-scale-elixir-for-11-million-concurrent-users.md) +> * 译者: +> * 校对者: + +![1_wtla_J4eY8-ftoQznTPiFA](https://user-images.githubusercontent.com/8282645/108677057-1bc37980-7524-11eb-9b05-890f6b05660f.png) + +# Using Rust to Scale Elixir for 11 Million Concurrent Users + +Over the last year, the Backend Infrastructure team at Discord was hard at work improving the scalability and performance of our core real-time communications infrastructure. + +One big project we undertook was changing how we update the Member List (all those nifty people on the right side of the screen). Instead of sending updates for every single person in the Member List, we could just send down the updates for the visible portion of the Member List. This has obvious benefits such as less network traffic, less CPU usage, better battery life; the list goes on and on. + +However, this posed one big problem on the server side: We needed a data structure capable of holding hundreds of thousands of entries, sorted in a particular way that can accept and process tons of mutations, and can report back indices of where things are being added and removed. + +Elixir is a functional language; its data structures are immutable. This is great for reasoning about code and supporting the massive concurrency you enjoy when you write Elixir. The double-edged sword of immutable data structures is that mutations are modeled by taking an existing data structure and an operation and creating a brand new data structure that is the result of applying that operation to the existing data structure. + +This meant that when someone joined a server — internally referred to as guilds — with a Member List of 100,000 members, we would have to build a new list with 100,001 members in it. The BEAM VM is pretty speedy and [getting faster everyday](http://blog.erlang.org/My-OTP-21-Highlights/). It tries to take advantage of [persistent data structures](https://en.wikipedia.org/wiki/Persistent_data_structure) where it can, but at the scale we operate, these large lists could not be updated fast enough. + +## Pushing Elixir to the Limits + +Two engineers took up the challenge of making a pure Elixir data structure that could hold large sorted sets and support fast mutation operations. This is easier said than done, so let’s put on our Computer Science helmets and go spelunking into the caves of data structure design. + +Elixir ships with a set implementation called MapSet. MapSet is a general purpose data structure built on top of the Map data structure. It’s useful for lots of Set operations, but it provides no guarantees around ordering, which is a key requirement for the Member List. This pretty much ruled out MapSet as a contender. + +Next up would be the venerable List type: wrap the List with a helper that would enforce uniqueness and sort the list after insertion of new elements. A quick benchmark of this approach shows that for small lists — 5,000 elements— insertion time was measured between 500𝜇s and 3,000𝜇s. This was already far too slow to be viable. + +Even worse, the performance of insertion scaled with size of list and depth of position in the list. Worst case that was benchmarked was adding a new element to the end of a 250,000 item list, which came in around 170,000𝜇s: basically an eternity. + +![https://miro.medium.com/max/2300/1*1UCJXCtJk0TNYxRgPk6htw.png](https://miro.medium.com/max/2300/1*1UCJXCtJk0TNYxRgPk6htw.png) + +Two down, but BEAM isn’t out of the competition yet. + +Erlang ships with a module called ordsets. Ordsets are Ordered Sets, so sounds like we found the solution to our problem: Let’s break out the benchmarking to check for viability. When the list is small the performance looks pretty great measuring between 0.008𝜇s and 288𝜇s. Sadly, when the size tested was increased to 250,000 worst-case performance increased to 27,000𝜇s, which was five times faster than our custom List implementation but still not fast enough. + +Having exhausted all the obvious candidates that come with the language, a cursory search of packages was done to see if someone else had already solved and open sourced the solution to this problem. A few packages were checked, but none of them provided the properties and performance required. Thankfully, the field of Computer Science has been optimizing algorithms and data structures for storing and sorting data for the last 60 years, so there were plenty of ideas about how to proceed. + +## SkipList + +The ordsets perform extremely well at small sizes. Maybe there was some way that we could chain a bunch of very small ordsets together and quickly access the correct one when accessing a particular position. If you turn your head sideways and squint real hard, this starts to look like a [Skip List](https://en.wikipedia.org/wiki/Skip_list), which is exactly what was implemented. + +The first incarnation of this new data structure was pretty straightforward. The OrderedSet was a wrapper around a list of Cells, inside each cell was a small ordset: the first item of the ordset, the last item of the ordset, and a count of the number of items. This allowed the OrderedSet to quickly traverse the list of Cells to find the appropriate Cell and then do a very fast ordset operation. By leveraging compile time guards in the implementation of traversal, you can get pretty good performance in the worst case scenarios that stymie ordset. Insertion of an item at the end of a 250,000 item list dropped from 27,000𝜇s to 5,000𝜇s, five times faster than raw ordsets and 34 times faster than the naive List implementation. + +So pop the champagne corks and celebrate, right? Not quite. + +The old worst case was better, but a new worst case of insertion at the beginning of the list had been created; a 250,000 item list was clocking in at 19,000𝜇s. Wat?! + +This makes sense if you think about the data structure. When you insert an item into the front of the OrderedSet it ends up in the first Cell, but that Cell is full, so it evicts its last item to the next Cell, but that Cell is full, so it evicts its last item to the next Cell, and so on. At this point, most engineers would shrug and say “You can’t have your cake and eat it too,” but at Discord we are pushing the envelope on quantum cake technology. + +## OrderedSet + +The problem is that when things fill up, operations can cascade from Cell to Cell. What if we could do something more clever? What if we allow Cells to swell and split, dynamically inserting new Cells in the middle of the list? This is slightly more expensive, but has the benefit that the worst case is a Cell Split instead of 2N Cell operations, where N is the number of Cells. + +Another day of coding data structures and we were ready to benchmark. + +At small list sizes, this new dynamic OrderedSet could perform insertions at any point in the list between 4𝜇s and 34𝜇s. Not bad. The real test came when we cranked up the size to 250,000. Inserting at the beginning of the list took…. drumroll…. 4𝜇s. That’s looking fast. But remember last time we made one number fast, we made another slow. Maybe the end of the list is horrible now, better check. + +With a list size of 250,000 items, inserting an item at the end of the list took 640𝜇s. Looks like we have a winner. + +![https://miro.medium.com/max/2268/1*9c8HPdzJLpot3cdTRMEFFw.png](https://miro.medium.com/max/2268/1*9c8HPdzJLpot3cdTRMEFFw.png) + +## Must. Go. Faster. + +This solution would work for guilds up to 250,000 members, but that was the scaling limit. For a lot of people, this would have been the end of the story. But Discord has been using Rust to make things go fast, and we posed a question: “Could we use Rust to go faster?” + +Rust is not a functional language, and will happily let you mutate data structures. It also has no run-time and provides “zero-cost abstractions.” If we could somehow get Rust to manage this set, it would probably perform much better. + +Our core services aren’t written in Rust, they are Elixir-based. Elixir serves this purpose very well, and lucky for us, the BEAM VM had another nifty trick up its sleeve. The BEAM VM has three types of functions: + +1. Functions that are written in Erlang or Elixir. These are simple user-space functions. +2. Functions that are built into the language and act as the building blocks for user-space functions. These are called BIFs or Built-In Functions. +3. Then there are NIFs or Native Implemented Functions. These are functions that are built in C or Rust and compiled into the BEAM VM. Calling these functions is just like calling a BIF but, you can control what it does. + +There’s a fantastic Elixir project called [Rustler](https://github.com/hansihe/Rustler). It provides nice support on the Elixir and Rust side for making a safe NIF that is well behaved and using the guarantees of Rust is guaranteed not to crash the VM or leak memory. + +We set aside a week to see if this would be worth the effort. By the end of the week, we had a very limited proof-of-concept that we could measure. The first benchmarks were extremely promising. The best case for adding an item to the set was 0.4𝜇s with a worst case of 2.85𝜇s, compared to OrderedSet’s 4𝜇s to 640𝜇s. This was a benchmark just using integers, but it was enough evidence to build out support for a wider range of Erlang Terms and fill out the rest of the functionality. + +With the spike showing so much promise, we continued on building out support for most Erlang Terms and all the functionality we needed for the member list. It was time to benchmark again. We cranked the number of items all the way up to 1,000,000 items. The test machine churned for a few minutes and finally printed out the result: SortedSet best case was 0.61𝜇s and worst case was 3.68𝜇s, testing multiple sizes of sets from 5,000 to 1,000,000 items. + +For the second iteration in a row we were able to make the worst case as good as the previous iterations best-case timings. + +![https://miro.medium.com/max/2284/1*mJ0QzqsUwQXEoi_piLOZ1A.png](https://miro.medium.com/max/2284/1*mJ0QzqsUwQXEoi_piLOZ1A.png) + +The Rust backed NIF provides massive performance benefits without trading off ease of use or memory. Since the library operations all clocked in well under the 1 millisecond threshold, we could just use the built-in Rustler guarantees and not need to worry about reductions or yielding. The SortedSet module looks to the caller to just be a vanilla Elixir module that performs crazy fast. + +## Happily Ever After + +Today, the Rust backed SortedSet powers every single Discord guild: from the 3 person guild planning a trip to Japan to 200,000 people enjoying the latest, fun game. + +Since deploying SortedSet, we’ve seen performance improve across the board with no impact to memory pressure. We learned that Rust and Elixir can work side by side to operate in extremely tight performance constraints. We can still keep our core real-time communications logic in the higher-level Elixir with its wonderful guarantees and easy concurrency while dropping down into Rust when needed. + +If you need a high-speed mutation friendly SortedSet, [we have released SortedSet as an open source library](https://github.com/discordapp/sorted_set_nif). + +If solving hard problems with awesome tools like Elixir and Rust is interesting to you, [go check out our jobs page](https://discordapp.com/jobs?team=engineering). + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/we-collected-500-000-browser-fingerprints-here-is-what-we-found.md b/article/2021/we-collected-500-000-browser-fingerprints-here-is-what-we-found.md new file mode 100644 index 00000000000..bc900655ca7 --- /dev/null +++ b/article/2021/we-collected-500-000-browser-fingerprints-here-is-what-we-found.md @@ -0,0 +1,192 @@ +> * 原文地址:[We collected 500,000 browser fingerprints. Here is what we found.](https://medium.com/slido-dev-blog/we-collected-500-000-browser-fingerprints-here-is-what-we-found-82c319464dc9) +> * 原文作者:[Peter Hraška](https://medium.com/@peterhraka) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/we-collected-500-000-browser-fingerprints-here-is-what-we-found.md](https://github.com/xitu/gold-miner/blob/master/article/2021/we-collected-500-000-browser-fingerprints-here-is-what-we-found.md) +> * 译者:[Usualminds](https://github.com/Usualminds) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin)、[Chorer](https://github.com/Chorer)、[lsvih](https://github.com/lsvih) + +# 基于 50 万个浏览器指纹的新发现 + +![](https://cdn-images-1.medium.com/max/2560/1*pG2Zzgc5OZr5frYc2ovhkg.png) + +你还记得自己上一次在网上寻找想要的商品时,会弹出很多与之相关广告页面吗?这时候你很有可能正在被跟踪,因为你的屏幕分辨率、时区和表情符号集这些信息都暴露在了网上。 + +没错,这种方法甚至可以在你使用无痕浏览模式 (也就是隐身模式) 时跟踪你。 + +![浏览器指纹的功能和价值示例 —— 可以在 [http://fp.virpo.sk](http://fp.virpo.sk) 检查你的浏览器指纹](https://cdn-images-1.medium.com/max/2000/1*PxgUnoZ92Gg75mpgczP2xQ.png) + +在 [Slido](https://slido.com) 上,我们进行了一次最大规模的浏览器指纹识别准确性的公开调查,并且是全球首次针对智能手机上的指纹信息表现进行的全面调查。 + +那么,让我们来看看什么是浏览器指纹,它们怎么被用来跟踪你,及其在这方面做得 “有多好”。 + +## 浏览器指纹是什么? + +我会用一个简单的“相机和打字机”的类比来解释什么是浏览器指纹。 + +相机和打字机都可以很简单地通过它们的输出来进行识别和区分。 + +每台相机都会在图片上留下独特的噪声样式,每台打字机都会以特定的方式在字母周围留下墨迹。 + +通过观察两张照片并比较它们的噪声样式,我们可以准确地判定这是否是同一台相机所拍摄。 + +同样的原则也适用于浏览器。大多数浏览器都启用了 JavaScript 功能,它向外部公开了大量关于你的浏览器的信息。 + +可能是你的屏幕尺寸、表情符号、已安装的字体、语言、时区或显卡型号。所有这些都可以从你的浏览器获得,但是你也许从未注意过这一点。 + +就每个指纹信息本身而言,它们都是微不足道的。但通过组合使用,任何人都可以准确地通过它来识别特定的浏览器。 + +![甚至你设备上的表情符号都可以用来识别你。表情符号可以使用 HTML5 画布提取为位图。](https://cdn-images-1.medium.com/max/2264/1*EWjMItxMhNQCgseB4serOg.jpeg) + +如果你感兴趣的话, 可以在 [我的网站](http://fp.virpo.sk) 上查看你的部分浏览器指纹信息。 + +## 如何使用浏览器指纹信息? + +有人可能会认为浏览器指纹天生就有不好的一面,但事实并非如此。 + +以防诈骗为例。如果你有任何一种需要在线登录的账号,比如银行账户或者社交网络账户,一般情况下只需要通过邮箱和密码就可以登录。 + +如果有一天小偷盗取了你的登录凭证并试图从他的设备上登录,银行或社交网络是可以检测到这种异常行为的,因为浏览器指纹发生了变化。为了防止被诈骗,平台可能会要求你做出进一步的授权,比如短信验证码。 + +然而,迄今为止,浏览器指纹最广泛的应用是个性化的广告推送。“点赞”和“分享”按钮几乎出现在每个社交网站上,它们通常会包含一个 JavaScript 脚本来收集你的浏览器指纹信息,从而进一步获取你的浏览记录。 + +![社交分享按钮常用来收集你的浏览器指纹](https://cdn-images-1.medium.com/max/2164/1*5Ux2MPqwS-XmNJrmSFw3uw.png) + +从某一个设备上收集单个指纹信息并不是很有价值。在一个网站上收集很多指纹信息也没有太大的用处。 + +但是因为与社交相关的按钮 —— 也就是包含浏览器指纹的脚本 —— 几乎无处不在,社交网络甚至知道你是怎么浏览网页的。 + +通过这种方式,那些科技巨头会向你推送你半小时前搜索内容的相关广告。 + +## 我的浏览器在任何地方和时间都能被识别出来吗? + +当然不是。 + +这里有几个网站,比如 [AmIUnique](https://amiunique.org/) 和 [Panopticlick](https://panopticlick.eff.org/),它们会基于数据库内大约 100 万个指纹信息,来确定你的浏览器指纹信息是否唯一。 + +你的浏览器指纹很可能会被标记为唯一的。这听起来很可怕,但请耐心听我说,当我们了解了指纹标记原理时,可能就没那么担心了。 + +这些网站将你的指纹与他们的整个数据库进行比较,该数据库包含了至少两到三年(或 Panopticlick 则是 45 天)收集的数据。 + +然而,45 天和 2 年的时间足够让你的浏览器指纹发生改变,而这不需要你做任何事情。例如,我的浏览器指纹在 60 天内改变了 6 次。 + +导致这种变化的可能是浏览器自动更新、调整窗口大小、安装新字体,甚至调整夏令时。所有这些都会让你的浏览器在很长一段时间内很难再次被唯一识别。 + +## 我们分析的数据 + +[Panopticlick](https://panopticlick.eff.org/static/browser-uniqueness.pdf) 和 [AmIUnique](https://hal.inria.fr/hal-01285470/file/beauty-sp16.pdf) 都发表了关于浏览器指纹的优秀科学论文,他们分析了几十万个浏览器指纹。 + +我们的数据在几个关键方面有所不同。我们相信这有助于我们揭示更多关于浏览器指纹的信息。 + +* 我们分析了 566704 个浏览器指纹,这大约是之前最大的研究分析的指纹数量的两倍 +* 我们的数据集中,65% 的设备是智能手机 +* 数据集包含了 31 个不同的浏览器指纹特征,每个设备都是使用的最先进的浏览器指纹脚本 + +我们非常重视网络隐私,因此所有数据都是匿名分析的。我们尽了很大的努力来确保这些数据除了用于本研究之外,在任何其他方面都是无效的。 + +![在我们的数据库中设备类型的分布](https://cdn-images-1.medium.com/max/3842/1*6TGFW_Ta6xBGPtG3renu_g.png) + +## 结果 + +从我们的数据中得出的最直观的图表可能是显示匿名集大小的图表。 + +匿名设置基本上描述了有多少不同的设备共享了完全相同的浏览器指纹。 + +例如,大小为 1 的匿名集意味着浏览器指纹是唯一的。大小为 5 的匿名集意味着 5 个不同的设备拥有完全相同的指纹,因此,你不能仅仅根据指纹来区分它们。 + +我们数据集中大多数已占用设备类型的匿名设置大小结果如下: + +![匿名设置在我们数据集中占用的设备类型最多。例如,在我们的数据集中,只有 33% 的 iPhone 可以被唯一识别。](https://cdn-images-1.medium.com/max/3652/1*aRYY86WUgiB9OuSMrHil_w.png) + +看完这张图表,可以得出几个比较明确的结论: + +* 74% 的桌面设备能够被唯一识别,而只有 45% 的移动设备能够被唯一识别。 +* 在 iPhone 上收集的浏览器指纹中,只有 33% 是唯一的。 +* 另外 33% 的 iPhone 几乎无法被跟踪,因为有 20 多部 iPhone 显示了完全相同的浏览器指纹。 + +#### 指纹变化率 + +当观察单个设备的浏览器指纹发生变化的频率时,我们看到了另一个有趣的现象。 + +以下图表显示了设备第一次访问和第一次更改浏览器指纹之间的天数: + +![浏览器指纹变化速率。](https://cdn-images-1.medium.com/max/3842/1*girS-UYQ-GwEactOp8bgfg.png) + +我们可以看到,在 24 小时内,我们多次看到的设备中,近 10% 的设备成功改变了指纹。 + +让我们分别看看这在每种设备上的表现: + +![Rate of fingerprint change across different device types.](https://cdn-images-1.medium.com/max/4192/1*-kGLm0LGKQxjbtckW2gyZg.png) + +这张图表显示,19% 的 iPhone 手机在一周内更换了指纹,而同期只有 3% 的 Android。我们的数据表明,iPhone 比 Android 更难进行长时间的跟踪。 + +#### 最少的指纹个数 + +最后,我们讨论了到底需要从浏览器中收集多少指纹特性才能可靠地识别该浏览器。 + +为此,我们通过 [香农信息熵](https://en.wikipedia.org/wiki/Entropy_(information_theory)) 来评估指纹信息到底有多准确。其熵值越高,识别过程越准确。 + +**例如,14.2 的熵意味着每 19000 个浏览器指纹中就有一个与我的浏览器指纹完全相同。将熵值增加到 16.5 意味着,每 92500 个设备中就有一个和我拥有相同的指纹。** + +在我们的实验中,我们找到了最准确的浏览器指纹信息的子集。 + +我们整个数据集的熵为 16.55,所以我们决定从 3 个指纹特征开始,增加子集的大小,直到子集的熵大于 16.5,结果如下: + +![通过收集 9 个而不是 33 个浏览器特性,熵只下降了 0.035](https://cdn-images-1.medium.com/max/3444/1*gMIh_szBYVW1STWYMoEqBA.png) + +实验表明,通过提取 3 个基本的浏览器特征,即日期格式、用户代理字符集和屏幕可用大小(屏幕大小减去程序坞、窗口栏等的大小),我们可以实现 14.2 的熵,在某些情况下,这已经足够识别浏览器(以及用户)。 + +如果我们用更难获得的特性 (如 `Canvas`、已安装字体列表等) 扩展子集,就能够达到熵为 16.5 的目标。 + +这就意味着网站和公司并不需要花太多精力来识别你的身份。 + +## 结论 + +那么我们可以从中得到什么呢? + +* 那些科技巨头可以追踪到你的线上活动,但目前还不完全准确。 +* 智能手机(尤其是 iPhone)比个人电脑更难追踪 +* 设备的浏览器指纹变化非常频繁 +* 浏览器指纹很容易获取 + +然而,如果你担心你的数据隐私,我这里也可以告诉你一些好消息。首先,[苹果宣布了一场针对浏览器指纹识别的保卫战](https://www.howtogeek.com/fyi/safari-battles-browser-fingerprinting-and-tracking-on-macos-mojave/),它推出了最新的 Mac OS Mojave 版本。其次,GDPR 认为浏览器指纹是个人数据,必须进行相应的处理。最后还有许多 [插件和浏览器扩展](https://amiunique.org/tools) 会混淆浏览器指纹脚本。 + +所以,我们的浏览器隐私在未来并不像它看起来那么糟糕。诚然,有时你的浏览器可以被唯一地识别,但很多时候其他设备的浏览器指纹与你的完全相同,这使得你的浏览器更难被跟踪。 + +#### 研究动机 + +在 [Slido](https://slido.com) 上,我们试图使我们的 Web 应用程序的用户体验尽可能简单。当你使用我们的应用程序时,你通常不需要登录,我们希望保持这种方式。 + +我们进行这项研究的动机是:基于浏览器指纹的身份验证是否可以在不损害用户体验的情况下保护用户免受恶意脚本的攻击。 + +需要注意的是,智能手机的指纹信息也很重要,因为我们的应用流量主要来自智能手机。 + +而我们研究的结论是**否定的** + +浏览器指纹本身不足以作为我们进行用户身份验证的充分条件。然而,它们足够准确地把你放在一群有着类似兴趣(比如猫或汽车)的人当中。 + +--- + +这就意味着浏览器指纹的使用在个别场景中是理想的,比如个性化的广告,这种情况下准确性并非其关键,或者防止银行诈骗,通过浏览器指纹追踪,让诈骗者有所畏惧到底是一件好事。 + +如果你想了解更多关于浏览器指纹识别的知识,我写了一篇关于和我自己研究相关的 [60 多页长的论文](http://virpo.sk/browser-fingerprinting-hraska-diploma-thesis.pdf),你可以读读看。 + +你将了解到更多的关于每个浏览器特性提取是如何工作的,如何避免被浏览器指纹跟踪,并对本文中的图像和结果进行更详细的解释,等等。 + +--- + +非常感谢我的导师,RNDr. Michal Forišek 博士,在本次研究中为我提供了很大的帮助。 + +相关链接: + +* [我的关于浏览器指纹的 60 多页的报告](http://virpo.sk/browser-fingerprinting-hraska-diploma-thesis.pdf) +* [http://fp.virpo.sk](http://fp.virpo.sk) —— 了解浏览器指纹是什么 +* [https://panopticlick.eff.org](https://panopticlick.eff.org/static/browser-uniqueness.pdf) —— Panopticlick +* [https://amiunique.org](https://amiunique.org/) —— AmIUnique +* [https://audiofingerprint.openwpm.com](https://audiofingerprint.openwpm.com/) —— audio 特性在浏览器指纹中的应用 +* [https://www.nothingprivate.ml/](https://www.nothingprivate.ml/) —— 无痕浏览并不是无痕的 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/whats-new-in-swift-5-4.md b/article/2021/whats-new-in-swift-5-4.md new file mode 100644 index 00000000000..d4f8da4ddc0 --- /dev/null +++ b/article/2021/whats-new-in-swift-5-4.md @@ -0,0 +1,215 @@ +> * 原文地址:[What’s New in Swift 5.4?](https://medium.com/better-programming/whats-new-in-swift-5-4-88949071d538) +> * 原文作者:[Can Balkaya](https://medium.com/@canbalkaya) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/whats-new-in-swift-5-4.md](https://github.com/xitu/gold-miner/blob/master/article/2021/whats-new-in-swift-5-4.md) +> * 译者:[LoneyIsError](https://github.com/LoneyIsError) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin),[flying-yogurt](https://github.com/flying-yogurt) + +# Swift 5.4 的新特性 + +> 多个可变参数,拓展的隐式成员语法,Result 构建器,等等...... + +![图源作者](https://cdn-images-1.medium.com/max/3840/1*HfwBHnUJOzl56qCflMVQ1w.png) + +Swift 5.4 带来了许多改变,而这也是我喜欢它的原因。在本文中,我们将了解 Swift 5.4 的新特性。 + +> 注意:你可以在 GitHub 上下载 [本文的示例项目和源代码](https://github.com/Unobliging/What-s-New-in-Swift-5.4-) 。要打开和编辑这些文件,你需要使用 Xcode 12.5 beta 版或更高级。你可以点击这里下载 [Xcode 12.5 beta 版]((https://developer.apple.com/download/)),或者你也可以选择直接下载 [Swift 5.4]((https://swift.org/download/))。 + +## 最重要的改进 😄 + +正如任何之前创建过 Xcode 项目或 playground 文件的人所知道的一样,当你创建一个新的 playground 或 Xcode 项目时,下面的值会被写入到这个项目中: + +```Swift +var str = "Hello, playground" +``` + +在 Swift 5.4 中,其值的名称更改如下: + +```Swift +var greeting = "Hello, playground" +``` + +是的,这就是我认为 Swift 5.4 中最有趣的部分。 + +现在我们可以看看那些真正的改进了! + +## 多个可变参数 + +在 Swift 5.4 中,我们可以在函数、方法、下标和初始化器中可以使用多个可变参数。而在此之前,就只能有一个可变参数,就跟下面的代码一样: + +```Swift +func method(singleVariadicParameter: String) {} +``` + +现在,我们可以像下面的代码那样编写多个可变参数: + +```Swift +func method(multipleVariadicParameter: String..., secondMultipleVariadicParameter: String...) {} +``` + +我们可以这样调用上面所写的函数,同样,如果我们想的话,我们可以只传入一个字符串元素。下面的是示例代码: + +```Swift +method(multipleVariadicParameter: "Can", "Steve", "Bill", secondmultipleVariadicParameter: "Tim", "Craig") +``` + +多个可变参数的工作原理与数组类似。当然,在调用参数中的值时,必须事先检查该值是否存在;否则,它将出错并崩溃。代码如下: + +```Swift +func chooseSecondPerson(persons: String...) -> String { + let index = 1 + if persons.count > index { + return persons[index] + } else { + return "There is no second person." + } +} +``` + +## Result 构建器 + +自从 SwiftUI 问世以来,Result 构建器在 Swift 中起着非常重要的作用。现在,随着新的改进,它变得更加重要。 + +我们能用一个输出单个字符串的函数创建几十个字符串吗?如果我们使用 Result 构建器,那么答案是,当然可以! + +我们可以通过使用 `@resultBuilder` 定义新的结构来定义新的 Result 构建器。你要定义的方法和属性必须是 `static` 的。 + +回到我们将多个 `String` 转换为单个 `String` 的例子。使用下面的 Result 构建器,我们可以顺序链接多个 `String` 元素。代码如下: + +```Swift +@resultBuilder +struct StringBuilder { + static func buildBlock(_ strings: String...) -> String { + strings.joined(separator: "\n") + } +} +``` + +让我们用以下代码来调用它: + +```Swift +let stringBlock = StringBuilder.buildBlock( + "It really inspires the", + "creative individual", + "to break free and start", + "something different." +) + +print(stringBlock) +``` + +在定义值时,我们只应当直接使用 `buildBlock` 方法。因此,在每个 `String` 的末尾,我们都需要添加一个逗号。不过,如果在函数中使用 `StringBuilder` 来完成同样的需求,那么逗号不再被需要。代码如下: + +```Swift +@StringBuilder func makeSentence() -> String { + "It really inspires the" + "creative individual" + "to break free and start" + "something different." +} + +print(makeSentence()) +``` + +目前为止,我们用 Result 构建器所作的工作对你来说可能没有什么意义。但如果我们更有效地使用 Result 构建器,你将更好地理解它们的强大之处。例如,有了这两个将添加到 Result 构建器中的新方法,我们可以使用 Result 构建器来有条件的生成字符串。代码如下: + +```Swift +@resultBuilder +struct ConditionalStringBuilder { + static func buildBlock(_ parts: String...) -> String { + parts.joined(separator: "\n") + } + + static func buildEither(first component: String) -> String { + return component + } + + static func buildEither(second component: String) -> String { + return component + } +} +``` + +如您所见,通过创建一个 `if` 循环,我们可以根据布尔值更改 `String` 元素。结果如下: + +```Swift +@ConditionalStringBuilder func makeSentence() -> String { + "It really inspires the" + "creative individual" + "to break free and start" + + if Bool.random() { + "something different." + } else { + "thinking different." + } +} + +print(makeSentence()) +``` + +当然啦!你还可以自己尝试使用 Result 构建器来完成许许多多有趣的事情,而不仅仅拘泥于上面的例子。 + +--- + +## 拓展的隐式成员语法 + +在修饰符内定义元素时,我们不再需要指定该元素的主要类型。因此,你可以将多个成员属性或函数链接在一起,而无需在开头添加类型,如下所示: + +```Swift +.transition(.scale.move(…)) +``` + +在 Swift 5.4 发布之前,若想得到相同的结果,我们只能这样写: + +```Swift +.transition(AnyTransistion.scale.move(…)) +``` + +## 支持同名函数 + +有时候,你会希望编写同名函数 —— 至少我是这么希望的。在 Swift 5.4 中,我们可以编写同名函数了。 + +比如说,如果我们创建具有相同名称的函数 —— 这些函数具有相同的形参名称 —— 只要我们用不同的对象类型来定义这些形参,那么我们的代码就会生效。 + +你可以试着这样写: + +```Swift +struct iPhone {} +struct iPad {} +struct Mac {} + +func setUpAppleProducts() { + func setUp(product: iPhone) { + print("iPhone is bought") + } + + func setUp(product: iPad) { + print("iPad is bought") + } + + func setUp(product: Mac) { + print("Mac is bought") + } + + setUp(product: iPhone()) + setUp(product: iPad()) + setUp(product: Mac()) +} +``` + +## 结论 + +希望这篇文章能对你有帮助。有报道称 Swift 6.0 可能即将发布。到时候我还会写一篇新文章来说明 Swift 6.0 的新功能。 + +感谢你的阅读。 + +--- + +如果你想和我见面,或者有关于 iOS 开发等方面的问题,你可以在[这里](https://superpeer.com/canbalkya)与我进行一对一的交流。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/which-type-of-loop-is-fastest-in-javascript.md b/article/2021/which-type-of-loop-is-fastest-in-javascript.md new file mode 100644 index 00000000000..183f41b7ece --- /dev/null +++ b/article/2021/which-type-of-loop-is-fastest-in-javascript.md @@ -0,0 +1,121 @@ +> * 原文地址:[Which type of loop is fastest in JavaScript?](https://medium.com/javascript-in-plain-english/which-type-of-loop-is-fastest-in-javascript-ec834a0f21b9) +> * 原文作者:[kushsavani](https://kushsavani.medium.com/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/which-type-of-loop-is-fastest-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/article/2021/which-type-of-loop-is-fastest-in-javascript.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Chorer](https://github.com/Chorer)、[HumanBeing](https://github.com/HumanBeingXenon) + +# JavaScript 中哪一种循环最快呢? + +了解哪一种 `for` 循环或迭代器适合我们的需求,防止我们犯下一些影响应用性能的低级错误。 + +![由 [Artem Sapegin](https://unsplash.com/@sapegin?utm_source=medium&utm_medium=referral) 上传至 [Unsplash](https://unsplash.com/?utm_source=medium&utm_medium=referral)](https://miro.medium.com/max/10944/0*FjGuCxH-seN1PrRF) + +JavaScript 是 Web 开发领域的“常青树”。无论是 JavaScript 框架(如 Node.js、React、Angular、Vue 等),还是原生 JavaScript,都拥有非常庞大的粉丝基础。我们来谈谈现代 JavaScript 吧。循环一直是大多数编程语言的重要组成部分,而现代 JavaScript 为我们提供了许多迭代或循环值的方法。 + +但问题在于,我们是否真的知道哪种循环或迭代最适合我们的需求。`for` 循环有很多变形,例如 `for`、`for`(倒序)、`for…of`、`forEach`、`for…in`、`for…await`。本文将围绕这些展开讨论。 + +## **究竟哪一种循环更快?** + +**答案其实是:** `for`(倒序) + +最让我感到惊讶的事情是,当我在本地计算机上进行测试之后,我不得不接受 `for`(倒序)是所有 `for` 循环中最快的这一事实。下面我会举个对一个包含超过一百万项元素的数组执行一次循环遍历的例子。 + +**声明**:`console.time()` 结果的准确度在很大程度上取决于我们运行测试的系统配置。你可以在[此处](https://johnresig.com/blog/accuracy-of-javascript-time/)对准确度作进一步了解。 + +``` +const million = 1000000; +const arr = Array(million); +console.time('⏳'); +for (let i = arr.length; i > 0; i--) {} // for(倒序) :- 1.5ms +for (let i = 0; i < arr.length; i++) {} // for :- 1.6ms +arr.forEach(v => v) // foreach :- 2.1ms +for (const v of arr) {} // for...of :- 11.7ms +console.timeEnd('⏳'); +``` + +造成这样结果的原因很简单,在代码中,正序和倒序的 `for` 循环几乎花费一样的时间,仅仅相差了 0.1 毫秒。原因是,`for`(倒序)只需要计算一次起始变量 `let i = arr.length`,而在正序的 `for` 循环中,它在每次变量增加后都会检查条件 `i { + console.log(`${item} - ${index}`); +} +things.foreach(callbackFun); +/* 输出 have - 0 + fun - 1 + coding - 2 */ +``` + +需要注意的是,如果我们要使用 `forEach`,我们不能使用 JavaScript 的短路运算符,即不能在每一次循环中跳过或结束循环。 + +### **3. `for…of`** + +`for…of` 是在 ES6(ECMAScript 6)中实现标准化的。它会对一个可迭代的对象(例如 `array`、`map`、`set`、`string` 等)创建一个循环,并且有一个突出的优点,即优秀的可读性。 + +``` +const arr = [3, 5, 7]; +const str = 'hello'; +for (let i of arr) { + console.log(i); // 输出 3, 5, 7 +} +for (let i of str) { + console.log(i); // 输出 'h', 'e', 'l', 'l', 'o' +} +``` + +需要注意的是,请不要在生成器中使用 `for……of`,即便 `for……of` 循环提前终止。在退出循环后,生成器被关闭,并尝试再次迭代,不会产生任何进一步的结果。 + +### **4. `for` `in`** + +`for…in` 会在对象的所有可枚举属性上迭代指定的变量。对于每个不同的属性,`for…in` 语句除返回数字索引外,还将返回用户定义的属性的名称。 +因此,在遍历数组时最好使用带有数字索引的传统 `for` 循环。 因为 `for…in` 语句还会迭代除数组元素之外的用户定义属性,就算我们修改了数组对象(例如添加自定义属性或方法),依然如此。 + +``` +const details = {firstName: 'john', lastName: 'Doe'}; +let fullName = ''; +for (let i in details) { + fullName += details[i] + ' '; // fullName: john doe +} +``` + +### `for…of` 和 `for…in` + +`for…of` 和 `for…in` 之间的主要区别是它们迭代的内容。`for…in` 循环遍历对象的属性,而 `for…of` 循环遍历可迭代对象的值。 + +``` +let arr= [4, 5, 6]; +for (let i in arr) { + console.log(i); // '0', '1', '2' +} +for (let i of arr) { + console.log(i); // '4', '5', '6' +} +``` + +![由 [Tine Ivanič](https://unsplash.com/@tine999?utm_source=medium&utm_medium=referral) 上传至 [Unsplash](https://unsplash.com/?utm_source=medium&utm_medium=referral)](https://miro.medium.com/max/12000/0*E9FPH2LFeFnTGWF5) + +### **结论** + +- `for` 最快,但可读性比较差 +- `foreach` 比较快,能够控制内容 +- `for...of` 比较慢,但香 +- `for...in` 比较慢,没那么方便 + +最后,给你一条明智的建议 —— 优先考虑可读性。尤其是当我们开发复杂的结构程序时,更需要这样做。当然,我们也应该专注于性能。尽量避免增添不必要的、多余的花哨代码,因为这有时可能对你的程序性能造成严重影响。祝你编码愉快。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 +--- +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/why-discord-is-switching-from-go-to-rust.md b/article/2021/why-discord-is-switching-from-go-to-rust.md new file mode 100644 index 00000000000..c94e9f4d711 --- /dev/null +++ b/article/2021/why-discord-is-switching-from-go-to-rust.md @@ -0,0 +1,140 @@ +> * 原文地址:[Why Discord is switching from Go to Rust +](https://blog.discord.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f) +> * 原文作者:[jesse_11222](https://medium.com/@jesse_11222) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/why-discord-is-switching-from-go-to-rust.md](https://github.com/xitu/gold-miner/blob/master/article/2021/why-discord-is-switching-from-go-to-rust.md) +> * 译者: +> * 校对者: +# Why Discord is switching from Go to Rust +![https://miro.medium.com/max/3274/1*BYeVEgTVQia4MD5LSLoUlA.png](https://miro.medium.com/max/3274/1*BYeVEgTVQia4MD5LSLoUlA.png) + +Rust is becoming a first class language in a variety of domains. At Discord, we’ve seen success with Rust on the client side and server side. For example, we use it on the client side for our video encoding pipeline for Go Live and on the server side for [Elixir NIFs](https://blog.discordapp.com/using-rust-to-scale-elixir-for-11-million-concurrent-users-c6f19fc029d3). Most recently, we drastically improved the performance of a service by switching its implementation from Go to Rust. This post explains why it made sense for us to reimplement the service, how it was done, and the resulting performance improvements. + +# **The Read States service** + +Discord is a product focused company, so we’ll start with some product context. The service we switched from Go to Rust is the “Read States” service. Its sole purpose is to keep track of which channels and messages you have read. Read States is accessed every time you connect to Discord, every time a message is sent and every time a message is read. In short, Read States is in the hot path. We want to make sure Discord feels super snappy all the time, so we need to make sure Read States is quick. + +With the Go implementation, the Read States service was not supporting its product requirements. It was fast most of the time, but every few minutes we saw large latency spikes that were bad for user experience. After investigating, we determined the spikes were due to core Go features: its memory model and garbage collector (GC). + +# **Why Go did not meet our performance targets** + +To explain why Go wasn’t meeting our performance targets, we first need to discuss the data structures, scale, access patterns, and architecture of the service. + +The data structure we use to store read state information is conveniently called “Read State”. Discord has billions of Read States. There is one Read State per User per Channel. Each Read State has several counters that need to be updated atomically and often reset to 0. For example, one of the counters is how many @mentions you have in a channel. + +In order to get quick atomic counter updates, each Read States server has a Least Recently Used (LRU) cache of Read States. There are millions of Users in each cache. There are tens of millions of Read States in each cache. There are hundreds of thousands of cache updates per second. + +For persistence, we back the cache with a Cassandra database cluster. On cache key eviction, we commit your Read States to the database. We also schedule a database commit for 30 seconds in the future whenever a Read State is updated. There are tens of thousands of database writes per second. + +In the picture below, you can see the response time and system cpu for a peak sample time frame for the Go service.¹ As you might notice, there are latency and CPU spikes roughly every 2 minutes. + +![https://miro.medium.com/max/2134/1*3v779KSfo2OkxUPfPptq_Q.png](https://miro.medium.com/max/2134/1*3v779KSfo2OkxUPfPptq_Q.png) + +# **So why 2 minute spikes?** + +In Go, on cache key eviction, memory is not immediately freed. Instead, the garbage collector runs every so often to find any memory that has no references and then frees it. In other words, instead of freeing immediately after the memory is out of use, memory hangs out for a bit until the garbage collector can determine if it’s truly out of use. During garbage collection, Go has to do a lot of work to determine what memory is free, which can slow the program down. + +These latency spikes definitely smelled like garbage collection performance impact, but we had written the Go code very efficiently and had very few allocations. We were not creating a lot of garbage. + +After digging through the Go source code, we learned that Go will force a garbage collection run every [2 minutes at minimum](https://github.com/golang/go/blob/895b7c85addfffe19b66d8ca71c31799d6e55990/src/runtime/proc.go#L4481-L4486). In other words, if garbage collection has not run for 2 minutes, regardless of heap growth, go will still force a garbage collection. + +We figured we could tune the garbage collector to happen more often in order to prevent large spikes, so we implemented an endpoint on the service to change the garbage collector [GC Percent](https://golang.org/pkg/runtime/debug/#SetGCPercent) on the fly. Unfortunately, no matter how we configured the GC percent nothing changed. How could that be? It turns out, it was because we were not allocating memory quickly enough for it to force garbage collection to happen more often. + +We kept digging and learned the spikes were huge not because of a massive amount of ready-to-free memory, but because the garbage collector needed to scan the entire LRU cache in order to determine if the memory was truly free from references. Thus, we figured a smaller LRU cache would be faster because the garbage collector would have less to scan. So we added another setting to the service to change the size of the LRU cache and changed the architecture to have many partitioned LRU caches per server. + +We were right. With the LRU cache smaller, garbage collection resulted in smaller spikes. + +Unfortunately, the trade off of making the LRU cache smaller resulted in higher 99th latency times. This is because if the cache is smaller it’s less likely for a user’s Read State to be in the cache. If it’s not in the cache then we have to do a database load. + +After a significant amount of load testing different cache capacities, we found a setting that seemed okay. Not completely satisfied, but satisfied enough and with bigger fish to fry, we left the service running like this for quite some time. + +During that time we were seeing more and more success with Rust in other parts of Discord and we collectively decided we wanted to create the frameworks and libraries needed to build new services fully in Rust. This service was a great candidate to port to Rust since it was small and self-contained, but we also hoped that Rust would fix these latency spikes. So we took on the task of porting Read States to Rust, hoping to prove out Rust as a service language and improve the user experience.² + +# **Memory management in Rust** + +> Rust is blazingly fast and memory-efficient: with no runtime or garbage collector, it can power performance-critical services, run on embedded devices, and easily integrate with other languages.³ + +Rust does not have garbage collection, so we figured it would not have the same latency spikes Go had. + +Rust uses a relatively unique memory management approach that incorporates the idea of memory “ownership”. Basically, Rust keeps track of who can read and write to memory. It knows when the program is using memory and immediately frees the memory once it is no longer needed. It enforces memory rules at compile time, making it virtually impossible to have runtime memory bugs.⁴ You do not need to manually keep track of memory. The compiler takes care of it. + +So in the Rust version of the Read States service, when a user’s Read State is evicted from the LRU cache it is immediately freed from memory. The read state memory does not sit around waiting for the garbage collector to collect it. Rust knows it’s no longer in use and frees it immediately. There is no runtime process to determine if it should be freed. + +# **Async Rust** + +But there was a problem with the Rust ecosystem. At the time this service was reimplemented, Rust stable did not have a very good story for asynchronous Rust. For a networked service, asynchronous programming is a requirement. There were a few community libraries that enabled asynchronous Rust, but they required a significant amount of ceremony and the error messages were extremely obtuse. + +Fortunately, the Rust team was hard at work on making asynchronous programming easy, and it was available in the unstable nightly channel of Rust. + +Discord has never been afraid of embracing new technologies that look promising. For example, we were early adopters of Elixir, React, React Native, and Scylla. If a piece of technology is promising and gives us an advantage, we do not mind dealing with the inherent difficulties and instability of the bleeding edge. This is one of the ways we’ve quickly reached 250+ million users with less than 50 engineers. + +Embracing the new async features in Rust nightly is another example of our willingness to embrace new, promising technology. As an engineering team, we decided it was worth using nightly Rust and we committed to running on nightly until async was fully supported on stable. Together we dealt with any problems that arose and at this point Rust stable supports asynchronous Rust.⁵ The bet paid off. + +# **Implementation, load testing, and launch** + +The actual rewrite was fairly straight forward. It started as a rough translation, then we slimmed it down where it made sense. For instance, Rust has a great type system with extensive support for generics, so we could throw out Go code that existed simply due to lack of generics. Also, Rust’s memory model is able to reason about memory safety across threads, so we were able to throw away some of the manual cross-goroutine memory protection that was required in Go. + +When we started load testing, we were instantly pleased with the results. The latency of the Rust version was just as good as Go’s and **had no latency spikes!** + +Remarkably, we had only put very basic thought into optimization as the Rust version was written. **Even with just basic optimization, Rust was able to outperform the hyper hand-tuned Go version.** This is a huge testament to how easy it is to write efficient programs with Rust compared to the deep dive we had to do with Go. + +But we weren’t satisfied with simply matching Go’s performance. After a bit of profiling and performance optimizations, **we were able to beat Go on every single performance metric**. Latency, CPU, and memory were all better in the Rust version. + +The Rust performance optimizations included: + +1. Changing to a BTreeMap instead of a HashMap in the LRU cache to optimize memory usage. +2. Swapping out the initial metrics library for one that used modern Rust concurrency. +3. Reducing the number of memory copies we were doing. + +Satisfied, we decided to roll out the service. + +The launch was fairly seamless because we load tested. We put it out to a single canary node, found a few edge cases that were missing, and fixed them. Soon after that we rolled it out to the entire fleet. + +Below are the results. + +Go is purple, Rust is blue. + +![https://miro.medium.com/max/2142/1*-q1B4t622mnxoV8kvT9RwA.png](https://miro.medium.com/max/2142/1*-q1B4t622mnxoV8kvT9RwA.png) + +# **Raising the cache capacity** + +After the service ran successfully for a few days, we decided it was time to re-raise the LRU cache capacity. In the Go version, as mentioned above, raising the cap of the LRU cache resulted in longer garbage collections. We no longer had to deal with garbage collection, so we figured we could raise the cap of the cache and get even better performance. We increased the memory capacity for the boxes, optimized the data structure to use even less memory (for fun), and increased the cache capacity to 8 million Read States. + +The results below speak for themselves. **Notice the average time is now measured in microseconds and max @mention is measured in milliseconds.** + +![https://miro.medium.com/max/1076/1*DkLOxc-PzkqgXUj_nnOPpA.png](https://miro.medium.com/max/1076/1*DkLOxc-PzkqgXUj_nnOPpA.png) + +# **Evolving ecosystem** + +Finally, another great thing about Rust is that it has a quickly evolving ecosystem. Recently, tokio (the async runtime we use) released version 0.2. We upgraded and it gave us CPU benefits for free. Below you can see the CPU is consistently lower starting around the 16th. + +![https://miro.medium.com/max/1060/1*eT1PAnwaAcfCUikJ281v2g.png](https://miro.medium.com/max/1060/1*eT1PAnwaAcfCUikJ281v2g.png) + +# **Closing thoughts** + +At this point, Discord is using Rust in many places across its software stack. We use it for the game SDK, video capturing and encoding for Go Live, [Elixir NIFs](https://blog.discordapp.com/using-rust-to-scale-elixir-for-11-million-concurrent-users-c6f19fc029d3), several backend services, and more. + +When starting a new project or software component, we consider using Rust. Of course, we only use it where it makes sense. + +Along with performance, Rust has many advantages for an engineering team. For example, its type safety and borrow checker make it very easy to refactor code as product requirements change or new learnings about the language are discovered. Also, the ecosystem and tooling are excellent and have a significant amount of momentum behind them. + +If you made it this far, you’re probably newly excited about Rust or have been excited for quite some time. If you want to work on interesting problems using Rust professionally, you should consider working here at Discord. + +Also, a fun fact: the Rust team uses Discord to coordinate. There’s even a very helpful Rust community server that you can find us chatting in from time to time. [Click here to check it out.](https://discord.gg/tcbkpyQ) + +[1] Go version 1.9.2. Edit: Graphs are from 1.9.2. We tried versions 1.8, 1.9, and 1.10 without any improvement. The initial port from Go to Rust was completed in May 2019. + +[2] To be clear, we don’t think you should rewrite everything in rust just because. + +[3] Quote from [https://www.rust-lang.org/](https://www.rust-lang.org/) + +[4] Unless, of course, you use **unsafe**. + +[5] [https://areweasyncyet.rs/](https://areweasyncyet.rs/) + + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/why-i-still-lisp-and-you-should-too.md b/article/2021/why-i-still-lisp-and-you-should-too.md new file mode 100644 index 00000000000..6e976fa18ab --- /dev/null +++ b/article/2021/why-i-still-lisp-and-you-should-too.md @@ -0,0 +1,152 @@ +> * 原文地址:[Why I Still Lisp (and You Should Too)](https://medium.com/better-programming/why-i-still-lisp-and-you-should-too-18a2ae36bd8) +> * 原文作者:[Anurag Mendhekar](https://medium.com/@mendhekar) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/why-i-still-lisp-and-you-should-too.md](https://github.com/xitu/gold-miner/blob/master/article/2021/why-i-still-lisp-and-you-should-too.md) +> * 译者:[Elliott Zhao](https://github.com/elliott-zhao) +> * 校对者:[PassionPenguin](https://github.com/PassionPenguin), [Jack Tang](https://github.com/JackEggie) + +# 为什么我还在用 Lisp(而且你也应该用) + +> 这种古老的语言可能没有很多人用了,但它仍然是我代码库中的一部分。 + +![](https://cdn-images-1.medium.com/max/2000/1*BBzSK02LI9pvIGtiT_1IbA.png) + +作为 Scheme / Common Lisp / Racket 的长期用户(和积极支持者),我有时会被人们问到,为什么我还在坚持使用它们。幸运的是,我一直都在自己的程序员组织中工作,从来不需要为使用这些而向领导们解释。但是还有一个更重要的群体 —— 我的程序员同事们 —— 他们从未体会过使用这些语言的乐趣。就算他们不会让我解释,他们也会出于求知欲提问,而有时候也会想知道为什么我不会对 Python 或 Scala 即将加入的很酷的新特性,或者是什么其他风靡一时的东西而神魂颠倒。 + +虽然我真正使用的 Lisp 的变种有很多(Scheme、Common Lisp、Racket、Lisp-for-Erlang),但核心总是保持一致的:一种基于 S 表达式的、动态类型的、主要是函数式的、值传递的基于 λ 演算的语言。 + +我在十几岁的时候在 ZX Spectrum+ 上使用 BASIC 开始了我的编程之旅。虽然我在此之前我就对(手)写 Fortran 程序略有涉猎,但这确实对我来说是一个决定性的起始,因为它真正定义了我的职业路线。很快我就把这些语言用到了它的极限,并且尝试写超出这门语言和实现的有限能力的程序。我转到 Pascal 很短的一段时间(DOS box 上的 Turbo Pascal)里都是非常快乐的,直到我发现了运行在 Unix(Santa Cruz Operation Xenix!)上的 C。它帮助我取得了计算机科学的学士学位,但它总是让我希望能够在程序中拥有更强的表现力。 + +当我在 Miranda(丑陋的 Haskell 的漂亮母亲)中发现函数式编程时(感谢 IISc!),它真的让我大开眼界,想要在程序中追寻**美**!而我对编程语言中的表现力的概念的理解也有了一个巨大的飞跃。至此,我所理解的编程语言应当是简洁的、优雅的、易读的。 + +Miranda 并不是一种特别快的语言,因此执行速度是一个问题。Miranda 还是一种具有 Standard-ML 式类型推断功能的静态类型语言。一开始,我迷上了类型系统。然而,随着时间的推移,我开始鄙视它。虽然它帮助我掌握了一些编译时的东西,但大部分时候都在妨碍我(稍后再介绍)。 + +大约一年后,我终于在印第安纳大学和丹·弗里德曼(因《The Little LISPer》/《The Little Schemer》而著名)一起学习编程语言。这是我于 Scheme 和 Lisp 世界的起点。我终于知道我找到了表达我的程序的完美媒介。在过去的 25 年中,这一点从未改变。 + +在本文中,我试图解释和探索,为什么会这样。是因为我是一个不会改变自己路径的老恐龙吗?是我对新想法太过傲慢和鄙夷吗?或者我只是累了?答案,我认为,不在这上面几点。我觉得它是完美的,而且还**没有**什么可以推翻这一点。 + +让我们分解一下。我在几段之前说过: + +> 一种基于 S 表达式的、动态类型的、主要是函数式的、值传递的基于 λ 演算的语言。 + +我要开始解释这些 —— 倒过来讲。 + +## 基于 λ 演算的语言 + +所有程序中的基本实体都是**函数**,而函数从软件设计过程之初就拥有了它们自己的目的性。你早已考虑了怎样对信息进行操作,考虑了它是怎样转换的,以及它是怎样产生的。我还没有找到一个基本的框架,能够比 λ 演算更好的捕捉到这一固有意向。 + +**目的性**这个词可能会让你迷惑。数学有两种方式来理解函数。首先,作为一组有序对:(**输入,输出**)。尽管这是一种证明函数定理的好方法,但在编程领域是没有意义的。而这,也被称为函数的**扩展**视图。 + +第二种方式是把函数看做一个转换规则。例如,将输入和其本身相乘得到输出(这里就是平方函数了,基本上在各个编程语言中都缩写为 **sqr** 或 **sqrt**)。这是函数的**目的**的观点,而 λ 演算可以很好地捕捉它,并提供简单的规则来帮助我们证明函数定理,而无需求助于扩展性。 + +**等一下**,我确信你正在想。**我从未证明过我的函数的什么垃圾东西**。我敢打赌,事实上,你有过。而且你会**无时无刻**这么做。你总在说服自己,你的函数正在正常工作。你的代码可能不是正式的证明(可能会导致一些 bug),但是对代码进行推理是软件开发人员一直在做的事情。他们通过在脑海中回放代码来查看其行为。 + +基于 λ 演算的语言让在你的脑海中“回放代码”变得**非常**容易。λ 演算的简单规则意味着你只需装更少的东西在你的脑子里,并且代码易于阅读和理解。 + +编程语言当然是实用的工具,因此必须增强其核心简单性以适应更广泛的目的。这就是为什么我喜欢 Scheme(以及我目前最喜欢的 Scheme,Racket — CS,为那些在意此事的人设计)。它最低限度地引入 λ 演算到核心使其可用。即使是增强功能也遵循 λ 演算的基本原则,所以几乎没有意外。 + +这当然就意味着,**递归**成为了一种生活方式。如果你是那种对递归无感的人,或者你依旧相信“递归效率低下”,那么现在是重新审视它的时候了。Scheme(和 Racket)有效地将可能的递归实现为循环。不仅如此,这还是 Scheme 标准的**需求**。 + +这种特性被称为**尾调用优化**(**又称为 TCO**),已经出现了几十年。在评价编程语言现状的时候发现没有现代语言支持它,这是很令人沮丧的。因为新的语言出现并试图把 JVM 作为运行架构,所以这对于 JVM 更是个问题。JVM 不支持这个特性,所以基于 JVM 构建的语言必须越过障碍来提供部分适用 TCO 的假象。因此,我总是非常疑虑地使用任何面向 JVM 的函数式语言。这也是我没有成为 Clojure 的粉丝的原因。 + +这就是原因之一。Scheme / Racket 是基于 λ 演算的编程语言的合理实现。你可能已经注意到,我没有使用“函数式”一词来描述 Scheme。那是因为虽然它主要是函数式的,但并不会一直偏向不可变性。尽管不鼓励使用它,Scheme 意识到在某些真实环境下可能会需要变换(mutation),并且它允许在不需要辅助装置的情况下使用它。在这里,我不会与纯粹主义者争论为什么这是或者不是一个好主意,但这与我稍后将在本文中讨论的内容有关。 + +## 值传递的 + +那些知道 λ 演算细节得人可能已经知道我为什么选择做这种区分。请回顾我的经历,我最初使用函数式编程的 Miranda 是一种**惰性**函数式语言(和 Haskell 一样)。这意味着**只有**在需要表达式的值时才对它们进行求值。这也是 λ 演算最原始的定义。这意味着,函数的参数在使用时进行求值,而非在调用函数时。 + +这种区别是微妙的,并且确实具有一些很好的数学特性,但是对你再脑海中“回放代码”有着深远的影响。在很多情况下,这种情况会让你感到意外(即使是经验丰富的程序员),但在某些情况下,你可能需要比其他人做更多猜想。 + +作为程序员,在你的职业生涯中最难处理的 bug 之一,就是那些在屏幕上打印某些东西会使这个 bug 消失的情况。在惰性函数式语言中,打印某些内容会强制对表达式进行求值,而在发生 bug 的情况下,它可能没有被求值。因此,将值打印为调试工具变得令人疑虑,因为它会严重改变程序的行为方式。我不知道你怎么看,但对我来说,将值打印出来是我必须要使用的调试工具。 + +在语言中随处使用惰性求职也有其他一些微妙之处,这使得它对我来说是个**吸引力不大**的选择。我永远都不想猜测何时对某个表达式求值。要么求值,要么不求值。不要让我猜测何时,尤其是如果它会在某个库的深处发生(或不会发生)。 + +值传递对如何证明有关程序的形式理论有一些意义,但值得庆幸的是,存在一种名为值传递 λ 演算的野兽,我们可以在需要时可以依靠。 + +通过使用**形式转换**和变异,Scheme 允许你**显式**地进行惰性求值,可以方便地将其抽象化,以便你在需要时进行按需调用。这使我们进入了下一个阶段。 + +## 主要是函数式的 + +函数式编程很棒。在你的脑海中回放功能代码很简单:代码易于阅读,并且无需担心变异。除非这还不够。 + +我不赞成随意变异,但我赞成明智地使用变异。像上面的惰性求值的例子一样,我可以完全支持使用变异来**实现**函数特性。变异存在于所有软件周围。对于某些抽象,最富有表现力的做法可能是将变异引入一个小而美的抽象中。例如,消息传递总线是一种充满变异的抽象,但它可以具有非常优雅,纯函数的代码段,而不必携带伪造的状态变量或诸如单子之类的辅助装置。 + +像其他任何工具一样,采取极端的非变异编程可能会有害。一种能够明智地使用变异以更优雅的方式实现大量代码的语言,总比在每种情况下都强制使用一种(多数时候不错的)构造的语言要好。 + +因此,Scheme 内在的倾向于不变异,但是它对变异(或称作**副作用**)的“如果必须用就用”的态度使它成为我更有效的工具。 + +我在上面提到了单子,因此最好先讨论一下单子,因为它们是产生作用的纯函数方式。在写完有关它们的博士学位论文后,我想我对它们有所了解。我喜欢欧金尼奥·莫吉的单子的[原始概念](https://person.dibris.unige.it/moggi-eugenio/ftp/ic91.pdf)的优雅和纯粹的美。将计算过程与其产生的值区别对待,然后将该计算过程视作一种变量类型的想法在各个方面上来说都是**才华横溢的想法**。这是数学上理解编程语言语义的好方法。 + +作为一种编程工具,我对此百感交集。当你可以轻松创建简单的抽象来简化程序的其余部分时,这是一种分离作用然后将其贯穿整个程序的复杂方法。一位(不愿意透露姓名的)杰出的类型理论家曾经说过:“单子仅在隔周星期二有用。” + +单子是一种辅助装置,必须使用函数式语言在副作用外围提供函数围栏。问题在于,围栏是“传染性的”,接触围栏的所有东西现在也必须被围起来,以此类推,直到其影响越来越大。所以你现在无法面对副作用并优雅地进行抽象处理,而是获得了一个不得不带到各处的复杂的抽象。最重要的是,它们的协作也不太好。 + +我并不是说单子完全没有用。它们在某些情况下(“隔周星期二”)运行良好,我在工作时也会用它们。但是,当它们是进行计算的唯一机制时,就会严重削弱编程语言的表达能力。 + +这将我们带入下一个观点,也许是我的观点中最具争议的。 + +## 动态类型的 + +当今世界正围绕着类型化语言不断发展。TypeScript 被认为是 JavaScript 顽固世界的一个救星。Python 和 JavaScript 因缺乏静态类型而备受诟病。在大型编程项目中,类型被认为对于文档和沟通至关重要。工程经理拜倒在类型推断面前以保护他们远离普通软件工程师产生的劣质代码的侵害。 + +静态类型有两种。编译器在 C、C++、Java、Fortran 中使用“老式”静态类型来产生效率更高的代码。这里的类型检查器有严格的限制,但是除了基本的类型检查之外,不要假装提供任何保证。它们至少是**可以理解**的。 + +然后是一种新的静态类型,它起源于 Hindley-Milner 类型系统,它带来了新的野兽: 类型推断。这给你一种并非所有类型的需要声明的错觉。如果你遵守规则,那么你将从老式静态类型和多态性等新奇事物中获益。这种观点也是很容易理解的。 + +但是在最近的几十年中它具有了新的含义:静态类型是编译时错误检查的一种形式,因此它将帮助你产生质量更高的代码。就好像静态类型是神奇的定理证明,能够验证程序的某些深层属性一样。这就是我称之为**垃圾**的地方。我从未见过任何一种静态类型检查器(无论它有多复杂)能帮助我防止发生明显的错误(你还是应该在测试中捕获它)。 + +但是,静态类型检查器的作用是妨碍我的。屡试不爽。作为程序员,我一直在脑海里常存**不变式**(这是我程序中有关事物的属性的奇特名称)。这些不变式的**其中之一**是它的类型。当你初次遇到不变式时,拥有一个可以验证它的工具是很酷的(就像我在 Miranda 上做的)。 + +但这是一个**愚蠢**的工具。它只能做到这些。因此,你现在最终获得了有关如何满足此工具的人为规则。而我所知道的完全可以做(并且可以为我的用例辩护,甚至可以正式证明)的事情突然间就不能了。因此,现在我必须重新设计程序,以满足这种限制极大的工具的需求。大多数人都对这种折衷感到完全满意,并且他们会慢慢改变他们对软件的看法,以适应其局限性。 + +在老印度电影里,电影检查委员会不允许在银幕上接吻。因此,浪漫的场景总是会被剪辑成花朵相撞,或者成对的鸟儿一起飞走,或者其他像这样的傻事。这就是静态类型检查器给我的感觉。我们以一种优美的语言展示自己,它向我们保证了言论自由的权利,但随后语言检查委员会给了我们一记当头棒喝。我们最终不得不使用隐喻和象征,这是唯一的边际效益。 + +一款**优秀**的工具应该做到的是,让我在编译时声明并证明我**所有**的不变式。当然,这终究是无法解决的。所以在笨拙的工具(静态类型检查器)和没有工具之间做出选择,我一直都倾向于没有工具,因为我不想人为地给程序添加约束。所以我用动态类型。 + +所有程序(无论是不是静态类型的程序)都必须处理运行时异常。写得很好的程序会遇到更少的运行时异常,而写得不好的程序会遇到更多。静态类型检查器会让一些人从写的不好的阵营进入到写的很好的阵营。改善(和保证)软件质量的方法是**严格的测试**。想要交付高质量的软件,没有其他解决方案。是否使用静态类型对你的软件的质量影响很小。当你有一个周全的程序员写出的良好设计的程序,这种影响也将消失。 + +换句话说,静态类型是没有意义的。它可能具有某些文档价值,但不能替代其他不变式的文档。例如,你的不变式可能是你想要有一个单调递增的数值数组,它的均值是某个值,它的标准差则是另一个值。任何一种静态类型检查能让你做得最好也也不过是让你定义一个 `array[float]`。其余的不变式必须用文字解释作为函数的文档。那么你为什么还要让自己忍受 `array[float]` 的痛苦呢? + +动态类型允许我在程序中表达自己想要表达的内容而不会妨碍我。我可以根据程序的需要将我的不变式指定为为显式检查或文档。 + +但是,像所有其他东西一样,有时你需要静态地理解类型。例如,我经常处理图像,如果知道他们是 `array[byte]` 会有帮助,而且我预焙了可以魔术般快速处理它们的操作。Scheme / Lisp / Racket 都提供了**在需要时**能够做到这一点的方式。在 Scheme 中,它取决于实现方式,但是 Racket 自带一个 `Typed Racket` 变体,可以与动态类型变体混合使用。Common Lisp 允许在特定的上下文中声明类型,主要是为了让编译器在可能的情况下实现优化。 + +因此,再次的,Scheme / Lisp / Racket **当我需要它们时**给我类型的优点,但不会在所有地方强加约束。两全其美。 + +## 基于 S 表达式的 + +最后,我们来到了我使用 Lisp 的最重要原因之一。对于之前没有听说过 S 表达式的人来说,它代表 Lisp 和它的后代中的一种特殊语法选择。所有句法形式都是**原子**或**列表**。原子是诸如名称(符号),数字,字符串和布尔值之类的东西。而列表看起来像是“(...)”,列表里面的内容也是列表或者原子,而且很棒的是还有一个空列表“()”。就是这样。 + +没有中缀运算,没有运算符优先级,没有关联性,没有伪分隔符,没有独立的 else,什么也没有。所有函数式应用都是前缀式的,因此你不会说“(a + b)”,而是说“(+ a b)”,这更进一步会允许你灵活地说出类似“(+ a b c)”这样的东西。“+”仅仅是一个你可以随意重新定义的函数的名字。 + +有一些“关键字”可以指导给定列表以某种方式进行求值,但是求值规则是分层的且定义明确。换句话来说,S 表达式实际上是用树的形式对你程序的高效表示形式。 + +这种语法的简单性通常会使新手感到困惑。它可能把很多不幸未被这种美丽的编程方式吸引的程序员挡在门外。 + +这种语法形式的最大优点是极简主义 —— 你不需要虚假的语法结构即可传达概念。概念通过函数的名称或者语法关键词传达。这产生了奇特而紧凑的代码。在字符数方面并不一定总是紧凑的,但是在阅读代码时需要记住的概念数量上却很紧凑。 + +它还有更多优点。如果你的程序是树形的,那么你就可以编写程序来操作这些树。Lisper(还有 Schemer 和 Racketeer)称之为**宏**或者**语法扩展**。换句话来说,你可以扩展你的语言的语法来引入新的抽象。 + +几代 Lisper 编写了很多很酷的语法扩展,包括对象系统,语言嵌入,专用语言等等。我用它来开发语法功能,使我可以使用 Scheme 来构建从传感器网络到数字信号处理再到电子商务定价策略的整个领域。世界上甚至没有其他语言可以接近这种对语法扩展的支持。这是我(和其他许多 Lisper)没法放弃的。 + +## 结论 + +综上所述,就是: + +> 一种基于 S 表达式的、动态类型的、主要是函数式的、值传递的基于 λ 演算的语言。 + +这就是为什么我仍然使用 Scheme / Racket / Lisp 并可能在我的余生中继续使用的原因。我会使用其他语言吗?当然 —— 很多。他们中没有一个能和前面几位相比。**尤其是比较新的那几个。**看起来发明新的语言对于新一代的孤陋寡闻的软件工程师是一种锻炼,而老的语言**远远**好于他们做梦能想到的任何东西(我向你介绍名义上也起源于 Lisp 的 Ruby,但也引出了一个问题:**为什么你不直接用 Lisp 本身**)。 + +和每一种偏见一样,我的也有短板。在大约 15 年前,所有的第三方 SDK 都是完全使用 C/C++ 编写的,可以轻松与 Lisp 互操作。Java 的到来泼了一盆冷水,因为 JVM 不能很好地与 Scheme / Lisp / Racket 互操作。这使得在不做大量工作的情况下将第三方库合并到我的程序中变得越来越难。 + +另一个缺点是随着 API 的在互联网上的崛起,大多数厂商都在为互联网的常见语言(Java、Ruby、Python、JavaScript,和最近的 Go 和 Rust)发布库,但是从来不会为 Scheme / Lisp / Racket 发布,除非是社区贡献的,在 C / C++ 中也很少。这通常使我不得不自己构建一个 API 层,这当然不是很实用。Racket (这是我目前的最爱),有一个非常活跃的社区,确实做出了很多巨大的贡献,但是它通常微微落后于时代。而一旦涉及最新和最棒的代码库,我只能自己来收拾这个烂摊子。这可能是我将来采用 Clojure 的主要原因,但这仍有待观察。 + +当然,这还吓不住我。如果非要说有什么的话,就是这使我更加意识到 Lisp 社区必须将其口碑传播得越来越远,并带来新一代的 Lisper,以求在快速演进的环境中强化生态系统。 + +最后,还有性能问题。首先,让我们解决常见的误解:Lisp **不**是解释语言。它**不**慢,并且所有实现都有很多杠杆来调整**大部分**程序的性能。在某些情况下,程序可能需要诸如 **C** 和 **C++** 之类的更快语言的帮助,因为它们更接近硬件,但是有了更快的硬件,即使这种区别也变得无关紧要了。这些语言是生产质量代码的完美选择,并且由于在此之上数十年的工作,它们可能比现有的大多数其他选择更稳定。 + +我确实知道,学习 Scheme / Lisp / Racket 比学习 Python 困难一点点(但是比学习 Java / JavaScript 容易得多)。但是,如果你这样做的话,你将成为一个更好的程序员,并且你将逐渐体会到这些语言的美,以至于再没有其他语言能满足你。 + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/why-react-hooks-are-the-wrong-abstraction.md b/article/2021/why-react-hooks-are-the-wrong-abstraction.md new file mode 100644 index 00000000000..b0444b82d89 --- /dev/null +++ b/article/2021/why-react-hooks-are-the-wrong-abstraction.md @@ -0,0 +1,306 @@ +> * 原文地址:[Why React Hooks Are the Wrong Abstraction](https://medium.com/better-programming/why-react-hooks-are-the-wrong-abstraction-8a44437747c1) +> * 原文作者:[Austin Malerba](https://medium.com/@austinmalerba) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/why-react-hooks-are-the-wrong-abstraction.md](https://github.com/xitu/gold-miner/blob/master/article/2021/why-react-hooks-are-the-wrong-abstraction.md) +> * 译者:[fltenwall](https://github.com/fltenwall) +> * 校对者:[zenblo](https://github.com/zenblo) [PassionPenguin](https://github.com/PassionPenguin) + +# 为什么 React Hooks 是错误的抽象 + +![Photo by the author.](https://cdn-images-1.medium.com/max/5576/1*LVjLXZ8-mBmhJZoJj3w_3w.png) + +在开始之前, 我想表达我对 React 团队多年来所付出的努力的感激。他们创建了一个很棒的框架,从很多方面来说,它是我对现代 Web 开发的引路人。他们为我铺平了道路,让我确信我的想法是正确的,如果没有他们的聪明才智,我不可能得出这些结论。 + +在今天的文章中,我将提出我所观察到的 Hooks 的缺点,并提出一种同样强大但不需要太多注意事项的替代 API 。我要说的是,这个 [替代API](https://malerba118.github.io/elementos-docs/) 有点冗长,但它对计算的浪费较少,概念上更准确,而且与框架无关。 + +## Hooks 的问题 #1: 附加渲染 + +作为设计的一般规则,我认识到我们应该首先禁止用户犯错误。只有当我们无法阻止用户犯错误时,我们才应该在他们犯了错误后通知他们。 + +举个例子,当允许用户在输入字段中输入数量时,我们可以允许他们输入字母数字字符,如果在他们的输入中发现字母字符,就向他们显示错误消息。但是,如果我们只允许用户在字段中输入数字字符,我们就可以提供更好的用户体验,这样就不需要检查是否包含字母字符了。 + +React 的行为与此非常相似。如果我们从概念上考虑 Hooks,它们在组件的整个生命周期内都是静态的。我的意思是说,一旦声明了,我们就不能从组件中移除它们,也不能改变它们相对于其他 Hooks 的位置。 React 使用 lint 规则并抛出错误,试图阻止开发人员违反这个 Hooks 的细节。 + +从这个意义上说,React 允许开发者犯错误,然后试图警告用户他们的错误。为了说明白我的意思,看下这个例子: + +```JSX +const App = () => { + const [countOne, setCountOne] = useState(0); + if (countOne === 0) { + const [countTwo, setCountTwo] = useState(0); + } + + return ( + + ); +}; +``` + +当计数器增加时,会在第二次渲染时产生一个错误,因为组件将删除第二个 `useState` Hooks: + +``` +Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement. +``` + +组件第一次渲染时,Hooks 的位置决定了 React 在后续渲染时必须在哪里找到 Hooks。 + +既然 Hooks 在组件的生命周期内都是静态的,那么我们在组件构造时声明它们不是比在渲染阶段声明它们更有意义吗?如果我们在组件的构造过程中附加了 Hooks,我们就不再需要担心强制执行 Hooks 的规则,因为在组件的生命周期中,Hooks 不会再有机会改变位置或被移除。 + +不幸的是,函数组件没有构造函数的概念,但是让我们假设它们是构造函数。我想它会像下面这样: + +```JSX +const App = createComponent(() => { + // This is a constructor function that only runs once + // per component instance. + + // We would declare our hooks in the constructor. + const [count, setCount] = useState(0) + + // The constructor function returns a render function. + return (props, state) => ( +
+ {/*...*/} +
+ ); +}); +``` + +通过在构造函数中将 Hooks 附加到组件上,我们不必担心它们在重新渲染时发生移位。 + +如果你在想,“你不能仅仅将 Hooks 移动到构造函数。他们**需要**在每次渲染时运行,以获取最新的值”在这一点上,那么你是完全正确的! + +我们不能只是将 Hooks 移出渲染函数,因为我们会破坏它们。所以我们要用别的东西来代替它们。但首先,Hooks 的第二个主要问题是: + +## Hooks 的问题 #2: 假设状态改变 + +我们知道,任何时候组件的状态发生变化,React 都会重新渲染该组件。当我们的组件因大量的状态和逻辑而变得臃肿时,这就会成为一个问题。假设我们有一个组件,它有两个不相关的状态: A 和 B。如果我们更新状态 A,我们的组件会因为状态的改变而重新呈现。即使B没有改变,任何依赖于它的逻辑都会重新运行,除非我们用 `useMemo`/`useCallback` 包装这个逻辑。 + +这是一种浪费,因为 React 本质上是说“好吧,在渲染函数中重新计算所有这些值”,然后当它遇到 `useMemo` 或者 `useCallback` 时,它就会返回那个决定,并在碎片上退出。但是,如果 React 只运行它需要运行的内容,那就更有意义了。 + +## 响应式编程 + +响应式编程已经存在很长一段时间了,但最近在 UI 框架中成为一种流行的编程范式。 + +响应式编程的核心思想是,变量是可观察的,当一个可观察对象的值发生变化时,观察者会通过回调函数来通知这个变化: + +```JavaScript +const count$ = observable(5) + +observe(count$, (count) => { + console.log(count) +}) + +count$.set(6) +count$.set(7) + +// Output: +// 6 +// 7 +``` + +注意,当我们修改可观察的 `count$` 值时,传递给 `observe` 的回调函数是如何执行的。您可能想知道 `count$` 后面的 `$`。这就是所谓的 [Finnish Notation](https://medium.com/@benlesh/observables-and-finnish-notation-df8356ed1c9b),它简单地指出变量包含一个可观察对象。 + +在响应式编程中,还有一个计算或派生的可观察对象的概念,它既可以观察也可以被观察。下面是一个派生的可观察对象的例子,它跟踪另一个可观察对象的值,并对它应用 `transform`: + +```JavaScript +const count$ = observable(5) +const doubledCount$ = derived(count$, (count) => count * 2) + +observe(doubledCount$, (doubledCount) => { + console.log(doubledCount) +}) + +count$.set(6) +count$.set(7) + +// Output: +// 12 +// 14 +``` + +这与我们前面的示例类似,只是现在我们将记录重复的计数。 + +## 用响应式来改造 React + +在介绍了响应式编程的基础知识之后,让我们看一下 React 中的一个示例,并通过使其更具响应性来改进它。 + +考虑一个应用程序有两个计数器和一个依赖于其中一个计数器的派生状态: + +```JSX +const App = () => { + const [countOne, setCountOne] = useState(0); + const [countTwo, setCountTwo] = useState(0); + + const countTwoDoubled = useMemo(() => { + return countTwo * 2; + }, [countTwo]); + + return ( +
+ + +

Count Two Doubled: {countTwoDoubled}

+
+ ); +}; +``` + +在这里,我们有逻辑将 `countTwo` 的值在渲染两次,但如果 `useMemo` 发现 `countTwo` 的值与它在前一个渲染上的值相同,那么再次渲染的值将不会在该渲染上重新派生。 + +结合我们早期的想法,我们可以从 React 中提取状态职责,并在构造函数中将状态设置为可观察对象的图形。当 `observable` 发生变化时,它就会通知组件,这样组件就知道要重新渲染了: + +```JSX +const App = createComponent(({ setState }) => { + // This is a constructor layer that only runs once. + // Create observables to hold our counter state. + const countOne$ = observable(0); + const countTwo$ = observable(0); + const countTwoDoubled$ = derived(countTwo$, (countTwo) => { + return countTwo * 2; + }); + + observe( + [countOne$, countTwo$, countTwoDoubled$], + (countOne, countTwo, countTwoDoubled) => { + setState({ + countOne, + countTwo, + countTwoDoubled + }); + } + ); + + // The constructor returns the render function. + return (props, state) => ( +
+ + +

Count Two Doubled: {state.countTwoDoubled}

+
+ ); +}); +``` + +在上面的例子中,我们在构造函数中创建的可观察对象通过闭包在 render 函数中可用,闭包允许我们设置它们的值以响应单击事件。只有当 `countwo$` 的值改变时,`doubledCountTwo$` 观察 `countwo$` 并将其值加倍。注意,我们不是在渲染过程中而是在渲染之前获得重复计数。最后,当任何可观察对象发生变化时,我们使用 `observe` 函数重新渲染组件。 + +这是一个优雅的解决方案,有以下几个原因: + +1. 状态和效果不再是 React 的责任,而是一个专用的状态管理库的责任,这个库可以跨框架使用,甚至不需要框架。 +2. 我们的可观察对象只在构造时进行初始化,所以我们不必担心违反 Hooks 规则或在呈现期间不必要地重新运行 Hooks 逻辑。 +3. 通过选择仅在依赖项发生变化时重新派生值,我们避免了在不必要的时候重新运行派生逻辑。 + +通过对 React API 进行一些修改,我们可以实现上面的代码。 + +[**在这个沙盒中尝试我们的演示!**](https://codesandbox.io/s/alternate-react-api-kyutz) + +这实际上与 Vue 3 使用其组合API的方式非常相似。尽管命名不同,但是可以看到这个 Vue 代码片段惊人地相似: + +```JavaScript +// 示例来自 https://composition-api.vuejs.org/#usage-in-components +import { reactive, computed, watchEffect } from 'vue' + +function setup() { + const state = reactive({ + count: 0, + double: computed(() => state.count * 2) + }) + + function increment() { + state.count++ + } + + return { + state, + increment + } +} + +const renderContext = setup() + +watchEffect(() => { + renderTemplate( + ``, + renderContext + ) +}) +``` + +如果这还不够令人信服,看看当我们引入一个构造函数层来反应函数组件时,“引用”变得多么简单: + +```JSX +const App = createComponent(() => { + // We can achieve ref functionality via closures + let divEl = null; + + return (props, state) => ( +
divEl = el}> + {/*...*/} +
+ ); +}); +``` + +实际上,我们不需要使用 `useRef`,因为我们可以在构造函数中声明变量,然后在组件的生命周期中从任何地方读写它们。 + +也许更酷的是,我们可以很容易地将 `refs` 变成可观察的: + +```JSX +const App = createComponent(() => { + const divEl$ = observable(null); + + // Do something any time our "ref" changes + observe(divEl$, (divEl) => { + console.log(divEl) + }); + + return (props, state) => ( +
+ {/*...*/} +
+ ); +}); +``` + +当然,我的 `observable`,`derived`,和 `observe` 的实现都有 bug,并没有形成一个完整的状态管理解决方案。更不用说这些精心设计的示例忽略了一些考虑因素,但不用担心:我在这个问题上花了很多心思,我的想法在名为 [Elementos](https://malerba118.github.io/elementos-docs/)的新响应式状态管理库中达到了顶峰! + +![Photo by the author.](https://cdn-images-1.medium.com/max/5020/1*k1YTEm4t8HpWLaUcM7yfmg.png) + +Elementos 是一个与框架无关的响应式状态管理库,强调状态的可组合性和封装性。如果你喜欢这篇文章,我强烈建议你去看看! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/why-the-service-mesh-should-fade-out-of-sight.md b/article/2021/why-the-service-mesh-should-fade-out-of-sight.md new file mode 100644 index 00000000000..1dbc80d9d84 --- /dev/null +++ b/article/2021/why-the-service-mesh-should-fade-out-of-sight.md @@ -0,0 +1,47 @@ +> * 原文地址:[Why the Service Mesh Should Fade Out of Sight](https://medium.com/better-programming/why-the-service-mesh-should-fade-out-of-sight-878bfd30f5a) +> * 原文作者:[David Mooter](https://medium.com/@davidmooter) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/why-the-service-mesh-should-fade-out-of-sight.md](https://github.com/xitu/gold-miner/blob/master/article/2021/why-the-service-mesh-should-fade-out-of-sight.md) +> * 译者: +> * 校对者: + +# Why the Service Mesh Should Fade Out of Sight + +![Photo by [Ricardo Gomez Angel](https://unsplash.com/@ripato?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral).](https://cdn-images-1.medium.com/max/9000/0*aQPqRSOiXhzz9zo6) + +With rising interest in service meshes, many application development and delivery pros’ first encounter with one leaves them wondering how they differ from API gateways. Are service meshes their own product category or are they part of broader API management? These questions miss the point: Service meshes need to fade away into the background of development platforms. + +To understand why, one must first understand the quiet revolution happening with Kubernetes. Simply put, Kubernetes is becoming a distributed operating system to support distributed applications. + +* Legacy operating systems manage the resources of a computer and provide higher levels of abstractions for programmers to interact with the complex underlying hardware. They arose to address the challenges of hand-coding direct interactions with hardware. +* Kubernetes manages the resources of a cluster of computers and provides higher levels of abstractions for programmers to interact with complex underlying hardware and unstable, insecure networks. It arose to address the challenges of hand-coding direct interactions with clustered hardware. Although primitive by OS standards, it will make legacy OSes like Linux and Windows more and more irrelevant as it matures. + +## Service Mesh == Dynamic Linker For Cloud + +A service mesh is the modern-day dynamic linker for distributed computing. With traditional programming, including another module involves importing a library into your integrated development environment (IDE). Upon deployment, the operating system’s dynamic linker connects your program with the library at runtime. It also handles discovering the library, validating security to invoke the library, and establishing a connection to it. With a microservices architecture, your “library” is a network hop to another microservice. Finding that “library” and establishing a secure connection is the job of the service mesh. + +Just as it makes no sense for development and operations teams to have to think about a dynamic linker — much less care and feed for one — modern-day teams should not have to care for and feed a complicated service mesh. The situation we see today of service meshes being first-class infrastructure is an important step forward, but they have a problem: They are too visible. + +Installing a typical service mesh requires several manual steps. Infrastructure teams must coordinate with AppDev teams to ensure that connection configurations are compatible with what was coded. Many service meshes are too complicated to stand up at scale and require solid operational support talent to configure and keep them healthy. You may even need to understand the service mesh’s internal architecture to debug it when things go wrong. + +This must change. + +## It’s All About the Developer Experience + +Imagine a developer experience in which importing a JAR or DLL library required all the installation, configuration, and operational support a service mesh entails. What if it also required understanding the internal architecture of the operating system’s dynamic linker to diagnose runtime problems? I hear you responding, “That’d be insane!” + +Contrast this with the real experience of linking to a library: You reference the library from your IDE, build, and deploy. Done. That should be the gold standard for service mesh. + +Obviously, that is unattainable. A network call is more complicated than an in-memory library link. The point is that a service mesh should become as invisible as possible to the DevOps team. It should **strive** toward that gold standard, even if it can never quite get there 100%. + +Imagine a cloud-native development environment that enables developers to link microservices at build time. It then pushes the configurations of these connections into Kubernetes as part of the build process. Kubernetes then takes care of the rest, with the service mesh just being an implementation detail of your Kubernetes distribution that you rarely have to think about. + +Vendors that believe service mesh is merely about connectivity are missing the point. The fundamental value of microservices (and the cloud in general) is greater agility and scalability from smaller deployable units running on serverless, yet the programming constructs we’ve needed for decades haven’t gone away. Many advancements in cloud technology are filling in the constructs we lost when migrating from monoliths to cloud-native. Vendors that make the microservice developer’s experience more on par with that of traditional software development, without sacrificing the benefits of microservices, will have the winning products. + +The service mesh should be a platform feature — not a product category. It should be as far out of sight and mind from the DevOps team as possible. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/why-you-should-use-picture-tag-instead-of-img-tag.md b/article/2021/why-you-should-use-picture-tag-instead-of-img-tag.md new file mode 100644 index 00000000000..7dfb6aef0e8 --- /dev/null +++ b/article/2021/why-you-should-use-picture-tag-instead-of-img-tag.md @@ -0,0 +1,190 @@ +> * 原文地址:[Why You Should Use Picture Tag Instead of Img Tag](https://blog.bitsrc.io/why-you-should-use-picture-tag-instead-of-img-tag-b9841e86bf8b) +> * 原文作者:[Chameera Dulanga](https://medium.com/@chameeradulanga) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/why-you-should-use-picture-tag-instead-of-img-tag.md](https://github.com/xitu/gold-miner/blob/master/article/2021/why-you-should-use-picture-tag-instead-of-img-tag.md) +> * 译者:[plusmultiply0](https://github.com/plusmultiply0) +> * 校对者:[Usualminds](https://github.com/Usualminds)、苏苏的 [霜羽 Hoarfroster](https://github.com/PassionPenguin) + +# 为什么你应该使用 Picture 标签而不是 Img 标签 + +![](https://cdn-images-1.medium.com/max/5760/1*Sv9aXzgr2N6IiblcW_lFPg.jpeg) + +现代 web 应用程序中,在用户界面中使用大量图片和动画是一件很常见的事情。这些现代设计聚焦于提升应用的用户体验,但是如果没有做好设备对图片的响应式支持,其效果可能适得其反。 + +作为开发者,我们需要完成所有的需求。但是,在大多数情况下,我们可能会错过一些能产生巨大影响的细节,因为我们是以一个更高的视角来解决问题。 + +选择 `picture` 还是 `img` 标签就是这么一个小细节,如果你做出了正确的选择,那么就可以同时提升用户体验和应用性能。 + +本文接下来会讨论 `picture` 与 `img` 标签之间的差异,以及 `picture` 标签优于 `img` 标签之处。 + +## 为什么 Img 标签不能满足现代 web 应用的需求? + +众所周知,`img` 标签在很长的一段的时期内都是 HTML 的核心标签之一,这毫无疑问是因为它的简单和易用。 + +> **然而,屏幕尺寸和分辨率的发展以及复杂的用户需求,让 `img` 标签在响应式和跨设备应用程序的使用中出现了一些问题。** + +所有的问题都可以被归结为两个主要方面: + +1. 分辨率切换(Resolution Switching)—— 如何为窄屏设备提供较小尺寸的图片。 +2. 美术设计(Art Direction)—— 如何为不同尺寸的屏幕显示不同的图片。 + +现在,让我们来看看如何解决上述问题,并了解下 `picture` 标签的额外功能。 + +## 使用 srcset 和 sizes 属性实现分辨率切换 + +正如我先前提到的,现代的 web 设计师经常使用高分辨率的图像来吸引用户的注意力。但是作为开发者,我们必须谨慎地选择合适的 HTML 元素。 + +> **假设你对高分辨率图片使用了 `img` 标签。在这种情况下,相同的图片会在运行了该应用程序的每个设备上应用,并且会影响低分辨率设备(如:移动设备)的性能。** + +这个可能会导致更长的图片加载时间以及自上而下的图片逐部分加载。 + +![Top to bottom image loading issue](https://cdn-images-1.medium.com/max/2000/1*Atpq5fQFaAWBzVRgsMt75w.gif) + +通过使用 `picture` 标签的 `srcset` 和 `sizes` 属性,可以轻松的解决这个问题。 + +```html + + + + + Car + + +``` + +`srcset` 属性接受多个带有宽度像素值的图片,浏览器根据这些像素值来选择要显示的图片。在上面的例子中,为相同的图片提供了 3 个不同大小的版本。 + +`sizes` 属性定义了图片在屏幕上会占据的空间大小。在上面的例子中,如果屏幕的最小尺寸是 1280px ,则图像会占据 1200px 的宽度。 + +> **话虽如此,最好不要只因为分辨率切换就使用 picture 标签,因为现在的 img 标签也能做到同样的事情(并且有更多的浏览器支持)。** + +```html +Car +``` + +然而,在大多数情况下,我们需要同时处理分辨率切换和美术设计,那么 `picture` 标签就是最好的选择。 + +所以,让我们来看看如何使用 `picture` 标签来实现美术设计。 + +## 使用 media 属性实现美术设计 + +美术设计背后的主要思想是,基于设备的屏幕尺寸显示不同的图片。在大多数情况下,一张在大屏设备上看起来很好的图,会在当你切换到移动设备时被裁剪或者看起来很小。 + +> **我们可以通过为不同的屏幕尺寸提供图片的不同版本来解决这个问题。这些不同的版本可以是横向的、纵向的、或者同一图像的任意自定义版本。** + +使用 `picture` 标签,并在其中使用多个 `source` 标签,我们可以轻松的处理分辨率切换。 + +```html + + + + + + + +``` + +接着,我们可以使用 `media` 属性来定义这些 `source` 标签会被使用的情况(媒体条件)。我们也可以用类似于上一节讨论的方式那样来使用 `srcset` 和 `sizes` 属性。 + +下面的代码是将 `picture` 标签用于美术设计和分辨率切换的示例。 + +```html + + + + + + + Car + + +``` + +如果屏幕方向是水平时,浏览器会从第一个图片集(srcset)中显示图片。而当屏幕方面是竖直时,浏览器会使用第二个图片集(srcset)。除此之外,你也可以在 `media` 属性中设置 `max-width` 和 `min-width` 参数: + +```html + + + + +``` + +最后的 `img` 标签是用来向后兼容那些不支持 `picture` 标签的浏览器。 + +## 实现图像格式切换 + +随着科技的快速发展,每天都会产生不同的现代图片格式。其中一些格式,如:`webp`、`svg` 以及 `avif` 可以提供更好的用户体验。 + +另一方面,一些浏览器不支持这些现代图像格式。如果我们不使用兼容的图像格式,有时就会适得其反。 + +> **我们可以轻松的解决这个问题,因为 picture 标签支持我们在其中使用多个 source。** + +```html + + + + + test image + + +``` + +上面的例子包含了 `avif`、`webp` 和 `png` 三种图像格式。首先,浏览器会尝试加载 `avif` 格式。如果失败了,浏览器会接着尝试 `webp` 格式。如果这两种格式都不支持,浏览器就会使用 `png` 格式的图片。 + +> **当 Chrome 声明其浏览器开发者工具(DevTools)将会在渲染选项卡(Rendering)中提供两种新的模拟方式以模拟部分支持的图像类型时,有关 `picture` 标签的事情开始变得有趣起来了。** + +从 Chrome 88 开始,你可以使用其浏览器开发者工具(DevTools)来检查浏览器对于图像格式的兼容情况。 + +![Using Chrome DevTools for Image Compatibility Emulations](https://cdn-images-1.medium.com/max/2562/1*GAFavZjkfi4FUDRkkPMA4Q.png) + +## 总结 + +虽然我们讨论了为什么 `picture` 标签相比 `img` 标签更好。但是,我必须声明的是, `img` 标签并没有消亡,短期内也不会。 + +如果我们能有效的使用 `srcset` 和 `sizes` 等属性,我们就能最大限度的用好 `img` 标签。比如,我们能仅使用 `img` 标签来实现分辨率切换。 + +另一方面,我们可以借助 `picture` 标签使用媒体查询和其他的属性来轻松解决分辨率切换和美术设计。 + +适配图像格式切换与 Chrome DevTools 对其的支持都可以被视为 `picture` 标签的优势。 + +这两个标签各有利弊。所以,我们必须仔细思考并基于我们的需求使用最合适的标签。 + +感谢您的阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/will-scss-be-replaced-by-css3.md b/article/2021/will-scss-be-replaced-by-css3.md new file mode 100644 index 00000000000..bc80b659b6e --- /dev/null +++ b/article/2021/will-scss-be-replaced-by-css3.md @@ -0,0 +1,169 @@ +> * 原文地址:[Will SCSS be replaced by CSS3?](https://blog.bitsrc.io/will-scss-be-replaced-by-css3-754842d6b681) +> * 原文作者:[Viduni Wickramarachchi](https://medium.com/@viduniwickramarachchi) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/will-scss-be-replaced-by-css3.md](https://github.com/xitu/gold-miner/blob/master/article/2021/will-scss-be-replaced-by-css3.md) +> * 译者:[霜羽 Hoarfroster](https://github.com/PassionPenguin) +> * 校对者:[Chorer](https://github.com/Chorer)、[Usualminds](https://github.com/Usualminds) + +# CSS3 会替代 SCSS 吗? + +![](https://cdn-images-1.medium.com/max/5760/1*iiuMRihN7Lj3i1-hTk8PjA.jpeg) + +当谈及设置网页样式的时候,我们可以选择在项目中使用纯 CSS 或是 SCSS(除了其它处理器之外)。SCSS 是 CSS 的超集。大多数的开发者都认为,受益于高级的功能和清晰的语法,SCSS 使用起来比 CSS 更加方便。 + +在这篇文章中我想要带着大家一起探索 SCSS 的功能以及 CSS 这些年来在功能上的提升。此外,我还会评估是否可以在实际项目中用 CSS 替代 SCSS。 + +## CSS 当前的功能 + +CSS 自诞生以来已经取得了很大的进展。近些年来 CSS 的发展也降低了在动画领域使用 JavaScript 的必要性。现代浏览器甚至使用了 GPU 去提升这些 CSS 动画的性能。我们现在甚至只需要稍微学习一下,就可以使用 CSS 构建复杂的响应式网格布局。 + +如今 CSS 有了许多新的功能,但本文只会重点提及一些在现代 Web 应用中常用的新功能。 + +* 在任何 Web 应用的构建中,最主要的一部分就是页面的布局。我们当中的大多数人这些年都依赖于诸如 Bootstrap 这样的 CSS 框架,但 CSS 如今已经提供了 Grid(网格)、Subgrid(子网格)、Flexbox(弹性盒)等新功能去原生地构建布局。虽说 Flexbox 在开发者当中广受欢迎,但 Grid 布局也正迎头赶上。 +* 灵活的文字排版 +* Transition 和 Transform 的强大能力让我们不再需要使用 JavaScript 去制作动画 +* 自定义属性或变量 + +## SCSS 的功能 + +#### SCSS 支持使用变量 —— 避免冗杂的代码 + +我们其实可以在我们的样式表中重用一堆的颜色 `color` 或其他元素定义(例如字体 `font`)。为了做到在统一的一个地方声明这些可重用的东西,SCSS 为我们提供了变量功能,让我们能够用一个变量名表示某个颜色,并在项目的其它地方使用该变量名,而不是重写一遍颜色值。 + +例如下面这个例子: + +```scss +$black: #000000; +$primary-font: 'Ubuntu', 'Helvetica', sans-serif; +$unit: 1rem; + +body { + color: $black; + font-family: $primary-font; + padding: #{$unit * 2}; +} +``` + +CSS 也支持变量和自定义属性,以下就是 CSS 中的自定义属性: + +```css +--black: #000000; +--width: 800px; +--primaryFont: 'Ubuntu', 'Helvetica', sans-serif; + +body { + width: var(--width); + color: var(--black); + font-family: var(--primaryFont); +} +``` + +> # 但是在运行时 CSS 自定义属性比 SCSS 变量更耗时。 + +这是因为浏览器会在运行时去处理这些属性。而 SCSS 则相反,它在预处理阶段会被转化为 CSS,并去处理变量。因此,SCSS 中变量的使用和代码的重用相比 CSS 而言有着更好的性能。 + +#### SCSS 允许嵌套的语法 —— 更简洁的源代码 + +假如有下面这样的 CSS 代码块: + +```css +.header { + padding: 1rem; + border-bottom: 1px solid grey; +} + +.header .nav { + list-style: none; +} + +.header .nav li { + display: inline-flex; +} + +.header .nav li a { + display: flex; + padding: 0.5rem; + color: red; +} +``` + +上述的代码看起来很混乱,为了给子元素添加样式,不得不重复声明同一个父元素。 + +但如果使用 SCSS 的嵌套语法,我们可以编写更简洁的代码。上述的代码如果用 SCSS 编写,是这样的: + +```scss +.header { + padding: 1rem; + border-bottom: 1px solid grey; + + .nav { + list-style: none; + + li { + display: inline-flex; + + a { + display: flex; + padding: 0.5rem; + color: red; + } + } + } +} +``` + +因此,与传统的 CSS 相比,使用 SCSS 设计组件似乎更加优雅而简洁。 + +#### @extend 功能 —— 避免重复同样的样式! + +在 SCSS 中,我们可以使用 `@extend` 在不同的选择器中共享相同的属性。带有占位符的 `@extend` 的使用方法如下所示: + +```scss +%unstyled-list { + list-style: none; + margin: 0; + padding: 0; +} +``` + +`%unstyled-list` 是一个可以避免重复编写代码的语法糖,我们可以在不同的地方使用这个列表样式模版,例如说: + +```scss +.search-results { + @extend %unstyled-list; +} + +.advertisements { + @extend %unstyled-list; +} + +.dashboard { + @extend %unstyled-list; +} +``` + +同样,我们可以在所有引入了这个定义的样式表中重用它。 + +SCSS 中还有很多例如[函数](https://sass-lang.com/documentation/at-rules/function)、[混入](https://sass-lang.com/documentation/at-rules/mixin)、[循环](https://sass-lang.com/documentation/at-rules/control/for) 的功能,能让我们的前端开发更加高效。 + +## 我应该从 SCSS 切换到 CSS 吗? + +在上文中我们探索了 CSS 现有提供的功能以及 SCSS 的功能。但是,如果将 CSS 与 SCSS 进行比较,我们会发现还有一些必要的功能无法在 CSS 中使用。 + +* 随着 Web 应用的不断发展,样式表会变得越发复杂和庞大。CSS 的嵌套功能将大幅度地提高代码的可读性,让我们在开发此类项目的时候得心应手。但是,截止撰写本文的时间,CSS 尚未支持该功能。 +* CSS 无法处理流控制规则。 SCSS 内置提供了诸如 `@if`、`@else`、`@each`、`for` 和 `@while` 的流控制规则。作为程序员,我发现这个功能对于定义样式来说是非常有用的。这也让我们可以编写更少更简洁的代码。 +* 此外,SCSS 还支持数字运算符的标准集,而在 CSS 中我们必须使用 `calc()` 函数才能完成数值运算。SCSS 的数值运算还能在其兼容的单位之间进行自动转换。 + +**但是**, `calc()` 这个 CSS 函数几乎没有限制,例如除法中除数必须是数字,或是对于乘法运算至少有一个参数是数字。 + +* 另一个重要方面是样式重用,这是 SCSS 的”杀手锏“。在这个方面,SCSS 提供了许多功能,例如内置模块、映射、循环和变量。 + +因此我认为,即使 CSS 已经诞生了很多新功能,SCSS 仍然是更好的选择。你可以在下面的评论区中谈谈你的想法。 + +希望你能够喜欢这篇文章。谢谢阅读! + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/article/2021/working-toward-fairer-machine-learning.md b/article/2021/working-toward-fairer-machine-learning.md new file mode 100644 index 00000000000..8224c4e4f26 --- /dev/null +++ b/article/2021/working-toward-fairer-machine-learning.md @@ -0,0 +1,79 @@ +> * 原文地址:[Working toward fairer machine learning](https://www.amazon.science/research-awards/success-stories/algorithmic-bias-and-fairness-in-machine-learning) +> * 原文作者:[Michele Donini](https://www.amazon.science/author/michele-donini), Luca Oneto +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2021/working-toward-fairer-machine-learning.md](https://github.com/xitu/gold-miner/blob/master/article/2021/working-toward-fairer-machine-learning.md) +> * 译者: +> * 校对者: + +# Working toward fairer machine learning + +Editor’s note: [Michele Donini](https://www.linkedin.com/in/michele-donini-2484734a/) is a senior applied scientist with Amazon Web Services (AWS). He and his co-author, [Luca Oneto](https://www.lucaoneto.com/), associate professor of computer engineering at University of Genoa, have written about how different approaches can make data-driven predictions fairer for underrepresented groups. Oneto also won a [2019 Machine Learning Research award](https://www.amazon.science/research-awards/recipients/luca-oneto) for his work on algorithmic fairness. In this article, Donini and Oneto explore the research they and other collaborators have published related to designing machine learning (ML) models from a human-centered perspective, and building responsible AI. + +## What is fairness? + +Fairness can be defined in many different ways, and many different formal notions exist, such as demographic parity, equal opportunity, and equal odds. + +>![https://assets.amazon.science/dims4/default/17fefc0/2147483647/strip/true/crop/1011x482+483+231/resize/1200x572!/quality/90/?url=http%3A%2F%2Famazon-topics-brightspot.s3.amazonaws.com%2Fscience%2Fc6%2F43%2F2f4c0fe14b0ab3a96733fd3ccfe2%2Funfair-fair-test.png](https://assets.amazon.science/dims4/default/17fefc0/2147483647/strip/true/crop/1011x482+483+231/resize/1200x572!/quality/90/?url=http%3A%2F%2Famazon-topics-brightspot.s3.amazonaws.com%2Fscience%2Fc6%2F43%2F2f4c0fe14b0ab3a96733fd3ccfe2%2Funfair-fair-test.png) +> +>Algorithmic fairness is a topic of great importance, with impact on many applications. The issue requires much further research; even the definition of what “being fair” means for an ML model is still an open research question. + +Nevertheless, the basic and common idea behind notions of fairness is that the learned ML model should behave equivalently, or at least similarly, no matter whether it is applied to one subgroup of the population (e.g., males) or to another one (e.g., females). + +For example, demographic parity, which arguably is the most common notion of fairness, implies that the probability of a certain output of an ML model (e.g., deciding to make a loan) should not depend on the value of specific demographic attributes (e.g., gender, race, or age). + +## Moving toward fairer models + +Broadly speaking, we can group current literature on algorithmic fairness into three main approaches: + +- The first approach consists of pre-processing the data to remove historical biases and then feeding this data to classical ML models. +- The second approach consists of post-processing an already learned ML model. This approach is useful when very complex ML models need to be made fairer without touching their inner structure or when re-training them is unfeasible (due to computational cost, or time requirements). +- The third approach, called in-processing, consists of enforcing fairness notions by imposing specific statistical constraints during the learning phase of the model. This is the most natural approach, but so far, it has required ad hoc solutions tailored to specific tasks and data sets. + +>![https://assets.amazon.science/dims4/default/aa34f7f/2147483647/strip/true/crop/200x350+0+0/resize/1200x2100!/quality/90/?url=http%3A%2F%2Famazon-topics-brightspot.s3.amazonaws.com%2Fscience%2Fb4%2F95%2Fd15206d54c978c00acc956a066bb%2Flearn-fair-models-copy.png](https://assets.amazon.science/dims4/default/aa34f7f/2147483647/strip/true/crop/200x350+0+0/resize/1200x2100!/quality/90/?url=http%3A%2F%2Famazon-topics-brightspot.s3.amazonaws.com%2Fscience%2Fb4%2F95%2Fd15206d54c978c00acc956a066bb%2Flearn-fair-models-copy.png) +> +>Broadly speaking, current literature on algorithmic fairness falls into three main approaches: pre-processing data; post-processing an already learned ML model; and in-processing, which consists of enforcing fairness notions by imposing specific statistical constraints during the learning phase of the model. + +We decided to explore and analyze possible techniques to make ML algorithms capable of learning fairer models. + +We started from the base concepts of statistical learning theory — a mathematical framework for describing machine learning — and, in particular, from empirical risk minimization theory. The core concept of empirical risk minimization is that a model’s performance on test data may not accurately predict its performance on real-world data, as the real-world data may have a different probability distribution. + +Empirical-risk-minimization theory provides a way to estimate the “true risk” of a model from its “empirical risk”, which can be computed from the available data. We extended this concept to the true and empirical fairness risk of ML models. + +Below is a summary of three papers we’ve published related to these topics. + +**“[Empirical risk minimization under fairness constraints](https://arxiv.org/pdf/1802.08626.pdf)”** + +This paper presents a new in-processing method, meaning that we incorporate a fairness constraint into the learning problem. We derive theoretical guarantees on both the accuracy and fairness of the resulting models, and we show how to apply our method to a large family of machine learning algorithms, including linear models and [support vector machines for classification](https://scikit-learn.org/stable/modules/svm.html#svm-classification) (a widely used supervised-learning method). + +We observe that, in practice, we can meet our fairness constraint simply by requiring that a scalar product between two vectors remains small (an orthogonality constraint between the vector of the weights describing our model and the vector describing the discrimination between the different subgroups). We further observe that, for linear models, this requirement translates into a simple pre-processing method. Experiments indicate that our approach is empirically effective and performs favorably against state-of-the-art approaches. + +**“[Fair regression with Wasserstein barycenters](https://arxiv.org/pdf/2006.07286.pdf)”** + +In this paper, we consider the case in which the ML model learns a regression function (as opposed to a classification task). We propose a post-processing method for transforming a real-valued regression function — the ML model — into one that satisfies the demographic-parity constraint (i.e., the probability of getting a positive outcome should be virtually the same for different subgroups). In particular, the new regression function is as good an approximation of the original as is possible while still satisfying the constraint, making it an optimal fair predictor. + +>![](https://assets.amazon.science/dims4/default/193689d/2147483647/strip/true/crop/250x310+0+0/resize/1200x1488!/quality/90/?url=http%3A%2F%2Famazon-topics-brightspot.s3.amazonaws.com%2Fscience%2F30%2F64%2F814dbdbf42e8b57c5454be7be982%2Ffair-representation-copy.png) +> +>In “Fair regression with Wasserstein barycenters”, we consider the case in which the ML model learns a regression function and propose a post-processing method for transforming a real-valued regression function — the ML model — into one that satisfies the demographic-parity constraint. + +We assume that the sensitive attribute — the demographic attribute that should not bias outcome — is available to the ML model at inference time and not only during training. We establish a connection between learning a fair model for regression and optimal transport theory, which describes how to measure distances among probability distributions. On that basis, we derive a closed-form expression for the optimal fair predictor. + +Specifically, under the unfair regression function, different populations have different probability distributions; the function skews the probabilities for the population with the sensitive attribute. The difference between subgroups’ distributions can be calculated using the Wasserstein distance. We show that the mean of the distribution of the optimal fair predictor is the mean of the different subgroups’ distributions, as calculated using Wasserstein distance. This mean is known as the Wasserstein barycenter. + +This result offers an intuitive interpretation of optimal fair prediction and suggests a simple post-processing algorithm to achieve fairness. We establish fairness-risk guarantees for this procedure. Numerical experiments indicate that our method is very effective in learning fair models, with a relative increase in error rate that is smaller than the relative gain in fairness. + +**"[Exploiting MMD and Sinkhorn divergences for fair and transferable representation learning](https://www.amazon.science/publications/exploiting-mmd-and-sinkhorn-divergences-for-fair-and-transferable-representation-learning)”** + +Where the first paper described a general learning method, and the second a regression method, this paper concerns deep learning. We show how to improve demographic parity in the multitask-learning setting, in which a deep-learning model learns a single representation of the input data that is useful for multiple tasks. We derive theoretical guarantees on the learned model, establishing that the representation will still reduce bias even when transferred to novel tasks. + +We propose a learning algorithm that imposes constraints based on two different ways of measuring distances between probability distributions, maximum mean discrepancy and Sinkhorn divergence. Keeping this distance small ensures that we represent similar inputs in a similar way when they differ only on the sensitive attribute. We present experiments on three real-world datasets, showing that the proposed method outperforms state-of-the-art approaches by a significant margin. + +Algorithmic fairness is a topic of great importance, with impact on many applications. In our work, we have attempted to take a small step forward, but the issue requires much further research; even the definition of what “being fair” means for an ML model is still an open research question. + +It’s also becoming clearer that we need to keep humans in the loop during the lifecycle of ML models, to evaluate whether the models are acting as we would like them to. In this sense, it is important to note that many other research subjects – such as the explainability, interpretability, and privacy of ML models – are deeply connected to algorithmic fairness. They can work in synergy, with the common goal of increasing the trustworthiness of ML models. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + + +> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 diff --git a/backend.md b/backend.md index f70ca3189eb..9d242a3d0ff 100644 --- a/backend.md +++ b/backend.md @@ -1,272 +1,363 @@ -* [前端 vs 后端:哪一个适合你?](https://juejin.im/post/5d36b5e3f265da1bd3059a21) ([YueYongDev](https://github.com/YueYongDev) 翻译) -* [Go 语言概览](https://juejin.im/post/5d386166e51d454fd8057c6a) ([JackEggie](https://github.com/JackEggie) 翻译) -* [Google 的 Pagespeed 的工作原理:提升你的分数和搜索引擎排名](https://juejin.im/post/5d36903ce51d4510803ce491) ([Jerry-FD](https://github.com/Jerry-FD) 翻译) -* [使用 Node.js 读取超大的文件(第一部分)](https://juejin.im/post/5d3c27ccf265da1b8d1665ba) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [从 Reddit 讨论中看到的 GraphQL 现状](https://juejin.im/post/5d380909e51d4510624f98a0) ([TiaossuP](https://github.com/TiaossuP) 翻译) -* [喷泉码和动态二维码](https://juejin.im/post/5d391ae1f265da1bb0040352) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Kubernetes 儿童插图指南](https://juejin.im/post/5d1b2a656fb9a07edc0b7058) ([JalanJiang](https://github.com/JalanJiang) 翻译) -* [使用 Gomobile 和 Gopherjs 的动态二维码数据传输](https://juejin.im/post/5d2bfccef265da1bb77699e8) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [通过 Rust 学习解析器组合器 — 第三部分](https://juejin.im/post/5d1f29f7f265da1b961324b2) ([suhanyujie](https://github.com/suhanyujie) 翻译) -* [通过 Rust 学习解析器组合器 — 第二部分](https://juejin.im/post/5d04c3abe51d45775d516f7b) ([suhanyujie](https://github.com/suhanyujie) 翻译) -* [通过 Rust 学习解析器组合器 — 第一部分](https://juejin.im/post/5cfddd00f265da1b7e102bee) ([suhanyujie](https://github.com/suhanyujie) 翻译) -* [Python 实现排序算法](https://juejin.im/post/5d1323b6e51d45108b2caeaf) ([fireairforce](https://github.com/fireairforce) 翻译) -* [WebSockets 与长轮询的较量](https://juejin.im/post/5d0b1381e51d455a694f9544) ([JalanJiang](https://github.com/JalanJiang) 翻译) -* [可维护的 ETL: 使管道更容易支持和扩展的技巧](https://juejin.im/post/5d08e178518825166f36bf89) ([fireairforce](https://github.com/fireairforce) 翻译) -* [利用并行流渐进加载图片](https://juejin.im/post/5d044fe3f265da1bd04eddda) ([twang1727](https://github.com/twang1727) 翻译) -* [尝试 DevOps:最适合你的是什么样的工具?](https://juejin.im/post/5cfd4aa3f265da1bb277233e) ([Starriers](https://github.com/Starriers) 翻译) -* [超快速的分析器(二):惰性解析](https://juejin.im/post/5cf33bd751882579e53f0130) ([suhanyujie](https://github.com/suhanyujie) 翻译) -* [如何使用 Node.js 构建一个命令行界面(CLI)](https://juejin.im/post/5cf2111b5188250d2850f884) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Node.js 日志记录指南](https://juejin.im/post/5cf213e4e51d4577407b1cda) ([fireairforce](https://github.com/fireairforce) 翻译) -* [超快速的分析器(一):优化扫描器](https://juejin.im/post/5ce8cbd9e51d4556bb4cd2f9) ([nettee](https://github.com/nettee) 翻译) -* [通过优化 Gunicorn 配置提高性能](https://juejin.im/post/5ce8cab8e51d4577523f22f8) ([shixi-li](https://github.com/shixi-li) 翻译) -* [Go 语言工具概述](https://juejin.im/post/5ce4dc17518825240245be5b) ([iceytea](https://github.com/iceytea) 翻译) -* [如果可以,永远不要在生产中直接运行 Node.js](https://juejin.im/post/5cdeb1306fb9a07efd46dbe5) ([fireairforce](https://github.com/fireairforce) 翻译) -* [化 Markdown 为 HTML:用 Node.js 和 Express 搭建接口](https://juejin.im/post/5cdcc216e51d453a543f9e68) ([Baddyo](https://github.com/Baddyo) 翻译) -* [使用 Nodemailer 轻松构建能通过电子邮件的重置密码 React 应用程序](https://juejin.im/post/5cdea6e3e51d4510b51279b3) ([fireairforce](https://github.com/fireairforce) 翻译) -* [模式 — 使用 Typescript 和 Node.js 的通用仓储](https://juejin.im/post/5cc715e1f265da03b36ef390) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [自动补全规则](https://juejin.im/post/5cd556ef6fb9a03218556cb7) ([fireairforce](https://github.com/fireairforce) 翻译) -* [Spring 的分布式事务实现 — 使用和不使用 XA — 第一部分](https://juejin.im/post/5cce4659f265da038a1487c9) ([JackEggie](https://github.com/JackEggie) 翻译) -* [使用 VS Code 调试 Node.js 的超简单方法](https://juejin.im/post/5cce9b976fb9a0322415aba4) ([iceytea](https://github.com/iceytea) 翻译) -* [分布式系统如何从故障中恢复?— 重试、超时和退避](https://juejin.im/post/5ccf98ace51d456e6d133541) ([nettee](https://github.com/nettee) 翻译) -* [减少 Python 中循环的使用](https://juejin.im/post/5cc8e012e51d453b6d4d13fd) ([qiuyuezhong](https://github.com/qiuyuezhong) 翻译) -* [Node.js 提供百万的活跃 WebSocket 连接](https://juejin.im/post/5cbeb2f45188250ab65f1d0c) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [Node.js 会永远只是慢的 Golang 吗?](https://juejin.im/post/5cc811fc6fb9a0322415a70d) ([steinliber](https://github.com/steinliber) 翻译) -* [用 Rust 打造你的第一个命令行工具](https://juejin.im/post/5cb33b94e51d456e63760453) ([JackEggie](https://github.com/JackEggie) 翻译) -* [Spring 的分布式事务实现 — 使用和不使用XA — 第三部分](https://juejin.im/post/5caee1ee6fb9a068890f1eff) ([radialine](https://github.com/radialine) 翻译) -* [Spring 的分布式事务实现 — 使用和不使用XA — 第二部分](https://juejin.im/post/5cae93ddf265da03a85aaac3) ([xiantang](https://github.com/xiantang) 翻译) -* [Java 和 etcd:因为 jetcd 最终走到了一起](https://juejin.im/post/5cae92f8f265da0360239b89) ([mingxing47](https://github.com/mingxing47) 翻译) -* [多线程简介](https://juejin.im/post/5ca351da6fb9a05e6a08745b) ([steinliber](https://github.com/steinliber) 翻译) -* [用 Apache Shiro 来强化一个 Spring Boot 应用](https://juejin.im/post/5c9f60c7e51d451cf929305d) ([lihanxiang](https://github.com/lihanxiang) 翻译) -* [数据流简介](https://juejin.im/entry/5c8f457cf265da60cf50e5b2) ([steinliber](https://github.com/steinliber) 翻译) -* [连接数据流](https://juejin.im/post/5c8efcbee51d457cb772778f) ([whatbeg](https://github.com/whatbeg) 翻译) -* [Golang 数据结构:树](https://juejin.im/post/5c8e023351882545eb718c9d) ([steinliber](https://github.com/steinliber) 翻译) -* [Node.js 基础知识: 没有依赖关系的 Web 服务器](https://juejin.im/post/5c88a6855188257b0b126564) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [Rust 语言案例研究:社区使得 Rust 成为 npm 的简单选择](https://juejin.im/post/5c88a12ae51d455cd96a14bb) ([WangLeto](https://github.com/WangLeto) 翻译) -* [论数据流的扩展性](https://juejin.im/post/5c8329d25188257ea038a05e) ([Park-ma](https://github.com/Park-ma) 翻译) -* [负载性能](https://juejin.im/post/5c7faa955188251bdd53ebd2) ([WangLeto](https://github.com/WangLeto) 翻译) -* [Java Service 加载器 和 spring Factories 加载器的比较](https://juejin.im/post/5c7fbe52e51d4541e510d282) ([HearFishle](https://github.com/HearFishle) 翻译) -* [在 GO 语言中创建你自己 OAuth2 服务:客户端凭据授权流程](https://juejin.im/post/5c77639a5188251fd46eea45) ([shixi-li](https://github.com/shixi-li) 翻译) -* [谷歌搜索操作符大全(包含 42 个高级操作符)](https://juejin.im/post/5c73744ef265da2dc675c029) ([cdpath](https://github.com/cdpath) 翻译) -* [提供隐私和过滤功能的 DNS 服务器](https://juejin.im/post/5c7365ca5188256282697eaa) ([ScDadaguo](https://github.com/ScDadaguo) 翻译) -* [教程 — 用 C 写一个 Shell](https://juejin.im/post/5c73dd7d6fb9a049aa6fb9aa) ([nettee](https://github.com/nettee) 翻译) -* [用 Rust 写一个微服务](https://juejin.im/post/5c7a3777f265da2dd773fc38) ([nettee](https://github.com/nettee) 翻译) -* [理解数据库分片](https://juejin.im/entry/5c791672f265da2da67c46eb/detail) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [HTTP/3:起源](https://juejin.im/post/5c6cb623f265da2dd37c1505) ([Starriers](https://github.com/Starriers) 翻译) -* [我作为软件工程师与一名数据科学家合作的经历](https://juejin.im/post/5c550038f265da2d8532b2f9) ([CasualJi](https://github.com/CasualJi) 翻译) -* [HTTP 简史](https://juejin.im/post/5c5ecc04e51d457f9c058be6) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [HTTP/2 常见问题解答](https://juejin.im/post/5c5ada2e6fb9a049dd80be75) ([YueYongDev](https://github.com/YueYongDev) 翻译) -* [DNS over TLS:端到端加密的 DNS](https://juejin.im/post/5c4849d06fb9a049c30b967b) ([lsvih](https://github.com/lsvih) 翻译) -* [Courier: Dropbox 的 gRPC 迁移利器](https://juejin.im/post/5c55997ae51d457fd81e3ca0) ([kasheemlew](https://github.com/kasheemlew) 翻译) -* [在 Flask 中使用 Redis Queue 实现异步任务](https://juejin.im/post/5c407497e51d457cba6ca871) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [再看 Flask 视频流](https://juejin.im/post/5c33540451882524ed5b9154) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [提高营销效率的工程(二)— 广告制作和管理的规模化](https://juejin.im/post/5c441193518825258604ecd0) ([Starriers](https://github.com/Starriers) 翻译) -* [数据流的不同应用场景 — Java](https://juejin.im/post/5c2c285fe51d4522ec5a2795) ([Starriers](https://github.com/Starriers) 翻译) -* [无容器下的云计算](https://juejin.im/post/5c24800a518825673b02dcfe) ([TrWestdoor](https://github.com/TrWestdoor) 翻译) -* [如何在六个月或更短的时间内成为 DevOps 工程师,第四部分:打包](https://juejin.im/post/5c19d6255188252ea66b33b3) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [使用 NodeJS 创建一个 GraphQL 服务器](https://juejin.im/post/5c015a5af265da612577d89a) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [Medium 的 GraphQL 服务设计](https://juejin.im/post/5c00dad3f265da617006db4e) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [关于 HTTP/3 的一些心得](https://juejin.im/post/5bfb519ef265da610f636596) ([Starriers](https://github.com/Starriers) 翻译) -* [用 Flask 输出视频流](https://juejin.im/post/5bea86fc518825158c531e9c) ([BriFuture](https://github.com/BriFuture) 翻译) -* [Rust 开发完整的 Web 应用程序](https://juejin.im/post/5bd66dee6fb9a05cdb1081ca) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [Node.js 高性能和可扩展应用程序的最佳实践 [第 2/3 部分]](https://juejin.im/post/5bca9208f265da0ade1ceffb) ([jianboy](https://github.com/jianboy) 翻译) -* [构建高性能和可扩展性 Node.js 应用的最佳实践 [第 3/3 部分]](http://5bcf14cee51d451cb039d13d/) ([steinliber](https://github.com/steinliber) 翻译) -* [开源项目之 Nginx](https://juejin.im/post/5bc55a25f265da0ae8014147) ([razertory](https://github.com/razertory) 翻译) -* [如何在六个月或更短的时间内成为 DevOps 工程师,第一部分](https://juejin.im/post/5bc21c125188255c53364ad5) ([tmpbook](https://github.com/tmpbook) 翻译) -* [Go 语言的整洁架构之道/一个使用 gRPC 的 Go 项目整洁架构例子](https://juejin.im/post/5bb99195e51d450e551a3a2f) ([yuwhuawang](https://github.com/yuwhuawang) 翻译) -* [Node.js 高性能和可扩展应用程序的最佳实践 [第 1/3 部分]](https://juejin.im/post/5bc0f68af265da0abe2720bf) ([jianboy](https://github.com/jianboy) 翻译) -* [使用 Node 和 OAuth 2.0 构建一个简单的 REST API](https://juejin.im/post/5bb1d3f95188255c6a044d9a) ([Starriers](https://github.com/Starriers) 翻译) -* [容器,虚拟机以及 Docker 的初学者入门介绍](https://juejin.im/entry/5bada97f6fb9a05d0e2e7014/detail) ([steinliber](https://github.com/steinliber) 翻译) -* [如何在六个月或更短的时间内成为DevOps 工程师,第2部分:配置](https://juejin.im/post/5baf677df265da0a951ee8f5) ([jianboy](https://github.com/jianboy) 翻译) -* [如何在六个月或更短的时间内成为DevOps 工程师,第三部分:版本控制](https://juejin.im/post/5bb067bfe51d450e905a0aa4) ([jianboy](https://github.com/jianboy) 翻译) -* [2018 年度最佳数据库即服务解决方案](https://juejin.im/post/5ba784e3e51d450e9d64984d) ([cf020031308](https://github.com/cf020031308) 翻译) -* [SmartyStreets 的 Go 测试探索之路](https://juejin.im/post/5ba83f2ff265da0a867c3818) ([kasheemlew](https://github.com/kasheemlew) 翻译) -* [使用 Go 编写微服务及其 GraphQL 网关](https://juejin.im/post/5b94cf476fb9a05d26593f07) ([changkun](https://github.com/changkun) 翻译) -* [GopherCon 2018:揭秘二叉查找树算法](https://juejin.im/post/5b94de9c5188255c5047076c) ([changkun](https://github.com/changkun) 翻译) -* [使用 Nexmo 和微软语音翻译 API 构建 Babel 鱼](https://juejin.im/post/5b8a78a3e51d4538a515cbda) ([Starriers](https://github.com/Starriers) 翻译) -* [如何优化企业级规模的 Node.js 应用程序](https://juejin.im/post/5b83c639f265da436d7e4c5e) ([Starriers](https://github.com/Starriers) 翻译) -* [Databook:通过元数据,Uber 将大数据转化为知识](https://juejin.im/post/5b800032e51d45389d3b4950) ([cf020031308](https://github.com/cf020031308) 翻译) -* [Python 的多线程与多进程](https://juejin.im/post/5b84f3086fb9a01a1a27cedb) ([lsvih](https://github.com/lsvih) 翻译) -* [如何在数据科学中写出生产层面的代码?](https://juejin.im/post/5b7adb7751882542d63b2805) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [Apache Airflow 的关键概念](https://juejin.im/post/5b7ba247e51d4538d42ab6a0) ([Starriers](https://github.com/Starriers) 翻译) -* [我是如何使用 Python 在 Medium 上找到并关注有趣的人](https://juejin.im/post/5b72c61851882561311fccce) ([Park-ma](https://github.com/Park-ma) 翻译) -* [如何使用 Python 和 BeautifulSoup 抓取网站内容](https://juejin.im/post/5b74fcec51882561446fb97f) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [我如何使用 Node.js 来实现工作自动化](https://juejin.im/post/5b4fe75ef265da0f54052138) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [在 UNIX 中,一切皆文件](https://juejin.im/post/5b652d346fb9a04fc03129e6) ([pmwangyang](https://github.com/pmwangyang) 翻译) -* [使用 PhpFastCache 提升网站性能](https://juejin.im/post/5b54d01be51d4517c5649965) ([lsvih](https://github.com/lsvih) 翻译) -* [我们是如何高效实现一致性哈希的](https://juejin.im/post/5b5488a96fb9a04fad3a181a) ([yqian1991](https://github.com/yqian1991) 翻译) -* [正则表达式要跑 5 天,所以我做了个工具将其缩短至 15 分钟。](https://juejin.im/post/5b6d426f6fb9a04fd1604341) ([cf020031308](https://github.com/cf020031308) 翻译) -* [如何使用 Pandas 重写你的 SQL 查询以及其他操作](https://juejin.im/post/5b5e5b2ee51d4517df1510c7) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [Robinhood 为什么使用 Airflow](https://juejin.im/post/5b4808f751882519ec07eaba) ([cf020031308](https://github.com/cf020031308) 翻译) -* [Web 应用架构基础课](https://juejin.im/post/5b69a8eef265da0f926baa56) ([horizon13th](https://github.com/horizon13th) 翻译) -* [Airflow: 一个工作流程管理平台](https://juejin.im/post/5b5bd2b6f265da0f60131d0c) ([yqian1991](https://github.com/yqian1991) 翻译) -* [从 Cron 到 Airflow 的迁移中我们学到了什么](https://juejin.im/post/5b4c3575f265da0f7334bbc9) ([cf020031308](https://github.com/cf020031308) 翻译) -* [[字幕翻译] Andrew Godwin — Django 异步 — PyCon 2018](https://www.bilibili.com/video/av24571596/) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [我是如何从零开始建立一个网络爬虫来实现我的求职自动化的](https://juejin.im/post/5b3b40896fb9a04f9e22e927) ([Starriers](https://github.com/Starriers) 翻译) -* [使用多重赋值与元组解包提升 Python 代码的可读性](https://juejin.im/post/5b3c2cf1e51d451925625b94) ([lsvih](https://github.com/lsvih) 翻译) -* [通过 SSH 远程使用 Python 解释器来运行 Flask](https://juejin.im/post/5b3e25a8e51d45191716d187) ([Starriers](https://github.com/Starriers) 翻译) -* [从 Java EE 8 Security API 开始 — 第二部分](https://juejin.im/post/5b3b49d66fb9a04f8a2160a9) ([Starriers](https://github.com/Starriers) 翻译) -* [基于 Node.js 的 Alexa Skills Kit 发布了!](https://juejin.im/post/5b4790b6f265da0f5d4cbec5) ([Yuhanlolo](https://github.com/Yuhanlolo) 翻译) -* [使用 Python 实现接缝裁剪算法](https://juejin.im/post/5b46ee8e6fb9a04fc436ad60) ([caoyi0905](https://github.com/caoyi0905) 翻译) -* [Erlang 之禅第二部分](https://juejin.im/post/5b3ea3ed6fb9a04fb8772a2c) ([7Ethan](https://github.com/7Ethan) 翻译) -* [从 Java EE 8 Security API 开始 — 第一部分](https://juejin.im/post/5b35a8d4f265da599423598b) ([Starriers](https://github.com/Starriers) 翻译) -* [通过插图学习 Go 的并发](https://juejin.im/post/5b2cd078e51d4558b70ca399) ([elliott-zhao](https://github.com/elliott-zhao) 翻译) -* [Kubernetes 分布式应用部署和人脸识别 app 实例](https://juejin.im/post/5b2db0576fb9a00e50313904) ([maoqyhz](https://github.com/maoqyhz) 翻译) -* [[字幕翻译] Graham Dumpleton — Secrets of a WSGI master. — PyCon 2018](https://github.com/xitu/gold-miner/blob/master/TODO1/secrets-of-a-wsgi-master-pycon-2018.md) ([vuuihc](https://github.com/vuuihc) 翻译) -* [Erlang 之禅第一部分](https://juejin.im/post/5b2a16cce51d4558d726e8c9) ([steinliber](https://github.com/steinliber) 翻译) -* [[字幕翻译] James Bennett — 理解 Python 字节码 — PyCon 2018](https://github.com/xitu/gold-miner/issues/3990) ([cdpath](https://github.com/cdpath) 翻译) -* [如何通过树莓派的深度学习轻松检测对象](https://juejin.im/post/5b1ba938518825137661af46) ([Starriers](https://github.com/Starriers) 翻译) -* [[字幕翻译] 玛利亚塔·维加亚 — 什么是 Python 核心开发者?— PyCon 2018](https://juejin.im/post/5b152c825188257d8a48d4a8) ([elliott-zhao](https://github.com/elliott-zhao) 翻译) -* [一种更简单的途径在 Java 中进行函数式编程](https://juejin.im/post/5b24aa5f6fb9a00e4d53e0c9) ([maoqyhz](https://github.com/maoqyhz) 翻译) -* [在 Laravel 应用程序之间共享数据库](https://juejin.im/post/5b17407fe51d4506a14db524) ([elliott-zhao](https://github.com/elliott-zhao) 翻译) -* [支撑现代存储系统的算法](https://juejin.im/post/5b10f80b5188257d92206851) ([LeopPro](https://github.com/LeopPro) 翻译) -* [使用 Go 语言的流模式来解析 DrugBank 的 XML(或者任何大的 XML 文件)](https://juejin.im/entry/5b06322a6fb9a07aab2a3d44) ([steinliber](https://github.com/steinliber) 翻译) -* [那些我们不需要的 HTTP 头信息](https://juejin.im/post/5b06c89df265da0db35022d8) ([SergeyChang](https://github.com/SergeyChang) 翻译) -* [由 Node.js 发送 Web 推送通知](https://juejin.im/post/5afc32146fb9a07acf5657e7) ([lsvih](https://github.com/lsvih) 翻译) -* [30 分钟 Python 爬虫教程](https://juejin.im/post/5afab181f265da0b7452514a) ([kezhenxu94](https://github.com/kezhenxu94) 翻译) -* [Python 中的键值(具名)参数:如何使用它们](https://juejin.im/post/5ae97546f265da0b8d41bcc7) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [使用 python 和 keras 实现卷积神经网络](https://juejin.im/post/5aefb0f351882567336aa3c7) ([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) -* [使用 Go 和 AWS Lambda 构建无服务 API](https://juejin.im/post/5af4082f518825672a02f262) ([sisibeloved](https://github.com/sisibeloved) 翻译) -* [Java 桥接方法详解](https://juejin.im/post/5af28ca0518825672565da74) ([kezhenxu94](https://github.com/kezhenxu94) 翻译) -* [我是如何修复 Python 3.7 中一个非常古老的 GIL 竞态条件 bug 的](https://juejin.im/post/5aeba1075188256712786039) ([kezhenxu94](https://github.com/kezhenxu94) 翻译) -* [GAN 的 Keras 实现:构建图像去模糊应用](https://juejin.im/post/5ad6e358f265da237b229bb2) ([luochen1992](https://github.com/luochen1992) 翻译) -* [用 Redis 和 Python 构建一个共享单车的 app](https://juejin.im/post/5adc861a51882567161a2799) ([Starriers](https://github.com/Starriers) 翻译) -* [Node.js 能进行 HTTP/2 推送啦!](https://juejin.im/post/5ad61595f265da23a04a129c) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [用 Skater 解读预测模型:打开模型的黑箱](https://juejin.im/post/5ae1494bf265da0b7c06f835) ([radialine](https://github.com/radialine) 翻译) -* [使用 NumPy 和 Pandas 进行 Python 式数据清理](https://juejin.im/post/5ad57db3f265da239c7bd9fb) ([bambooom](https://github.com/bambooom) 翻译) -* [不用 Class,如何写一个类](https://juejin.im/post/5acadb6d6fb9a028cb2deb8f) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [JanusGraph 为 PHP 助力](https://juejin.im/post/5ac31768f265da23766b7970) ([GanymedeNil](https://github.com/GanymedeNil) 翻译) -* [Pandas 数据类型概览](https://juejin.im/post/5acc36e66fb9a028d043c2a5) ([stormluke](https://github.com/stormluke) 翻译) -* [使用 python 分析 14 亿条数据](https://juejin.im/post/5aceae206fb9a028d2084fea) ([rydensun](https://github.com/rydensun) 翻译) -* [用户领域 API 监控和代码注入检测](https://juejin.im/post/5ac485175188255c93237f5d) ([Xekin-FE](https://github.com/Xekin-FE) 翻译) -* [VINE:一种开源的神经进化(Neuroevolution)交互式数据可视化工具](https://juejin.im/post/5ac466d6f265da238059db99) ([Starriers](https://github.com/Starriers) 翻译) -* [用 Python 编程进行糖尿病相关的机器学习](https://juejin.im/post/5ace62e96fb9a028b92d8267) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [如何用 Python 写一个 Discord 机器人](https://juejin.im/post/5ac1b9796fb9a028c42e5a61) ([Starriers](https://github.com/Starriers) 翻译) -* [Web 爬虫下的 Python 数据分析:中情局全球概况图解](https://juejin.im/post/5ab9fcebf265da238e0dc349) ([Starriers](https://github.com/Starriers) 翻译) -* [Elasticsearch 滚动升级](https://juejin.im/post/5ab5f53f518825556b6cbdea) ([rpgmakervx](https://github.com/rpgmakervx) 翻译) -* [这可能是 2018 年最好的一篇 PHP 性能测评(包含 5.6 到 7.2,以及HHVM)](https://juejin.im/post/5ab4bac9518825557b4caec6) ([Albertao](https://github.com/Albertao) 翻译) -* [斐波那契数列中的偶数(Python vs. JavaScript)](https://juejin.im/post/5aaa61f8f265da237b21d258) ([zephyrJS](https://github.com/zephyrJS) 翻译) -* [将项目迁移到 Python 3](https://juejin.im/post/5a9e3ff06fb9a028d2077434) ([Starriers](https://github.com/Starriers) 翻译) -* [GraphQL API 设计最佳实践](https://juejin.im/entry/5aab36936fb9a028d7005a3f/detail) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [Python 是解决任何问题的完美工具](https://juejin.im/post/5aa74bf95188255568686ae0) ([rydensun](https://github.com/rydensun) 翻译) -* [为 Python Web 应用编写 Dockerfiles](https://juejin.im/post/5aaf8038518825557e783285) ([lsvih](https://github.com/lsvih) 翻译) -* [用 Python 做一个 H5 游戏机器人](https://juejin.im/post/5aa9e7645188257bf550c745) ([lsvih](https://github.com/lsvih) 翻译) -* [Express.js 与 AWS Lambda  —  一场关于 serverless 的爱情故事](https://juejin.im/post/5aa128cdf265da239b410225) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [用户账户、授权和密码管理的 12 个最佳方法](https://juejin.im/post/5a9e4db151882555677e0dc1) ([Wangalan30](https://github.com/Wangalan30) 翻译) -* [Elasticsearch Reference Getting Start](https://juejin.im/post/5aa0b13af265da238b7d92f7) ([foxxnuaa](https://github.com/foxxnuaa) 翻译) -* [使用 Rust 开发一个简单的 Web 应用,第 2a 部分](https://juejin.im/post/5a81961cf265da4e7f359e86) ([LeopPro](https://github.com/LeopPro) 翻译) -* [使用 Rust 开发一个简单的 Web 应用,第 2b 部分](https://juejin.im/post/5a8196716fb9a0635c0478d7) ([LeopPro](https://github.com/LeopPro) 翻译) -* [使用 Rust 开发一个简单的 Web 应用,第 3 部分 —— 整合](https://juejin.im/post/5a8d6a436fb9a0635172803f) ([LeopPro](https://github.com/LeopPro) 翻译) -* [使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析](https://juejin.im/post/5a8d6aad6fb9a0634514c6c6) ([LeopPro](https://github.com/LeopPro) 翻译) -* [标准化的包布局](https://juejin.im/post/5a8cf9dc6fb9a063475f8c15) ([steinliber](https://github.com/steinliber) 翻译) -* [为 Flask Web 应用配置 Nginx](https://juejin.im/post/5a795febf265da4e94499949) ([lsvih](https://github.com/lsvih) 翻译) -* [为 Django Framework 贡献你的力量并没有想象中的那么难](https://juejin.im/post/5a77cd6e5188257a79247fe1) ([JayZhaoBoy](https://github.com/JayZhaoBoy) 翻译) -* [8 个技巧让你在 2018 年构建更好的 Node.js 应用程序](https://juejin.im/post/5a617c436fb9a01c9e46074f) ([PLDaily](https://github.com/PLDaily) 翻译) -* [状态管理的未来: 在 Apollo Client 中使用 apollo-link-state管理本地数据](https://juejin.im/post/5a728da26fb9a01cb74eb328) ([yct21](https://github.com/yct21) 翻译) -* [使用 Rust 开发一个简单的 Web 应用之总结篇:还是先把 Rust 放一边吧](https://juejin.im/post/5a71cf15f265da3e4f0a7d0a) ([mysterytony](https://github.com/mysterytony) 翻译) -* [使用 Rust 开发一个简单的 Web 应用,第 1 部分](https://juejin.im/post/5a673ba16fb9a01ca5609f35) ([LeopPro](https://github.com/LeopPro) 翻译) -* [通过后台数据预获取技术实现性能提升](https://juejin.im/post/5a71a9c3f265da3e2f01459b) ([NeoyeElf](https://github.com/NeoyeElf) 翻译) -* [利用双环 TDD 进行由外向内的开发](https://juejin.im/post/5a5dea0d6fb9a01cab28443c) ([NeilLi1992](https://github.com/NeilLi1992) 翻译) -* [Node.js 最佳实践 —— 如何在 2018 年成为更好的 Node.js 开发者](https://juejin.im/post/5a52242e6fb9a01c914037f3) ([NeilLi1992](https://github.com/NeilLi1992) 翻译) -* [如何用 TypeScript 玩转后端?](https://juejin.im/post/5a36837d6fb9a045167d4644) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [使用 Rust 来写原生 Node.js 模块](https://juejin.im/post/5a2b51bff265da4332277ee0) ([LeopPro](https://github.com/LeopPro) 翻译) -* [使用 helmet 库来保护你的 Express 网站](https://juejin.im/post/5a24fd8f51882509e5438247) ([lsvih](https://github.com/lsvih) 翻译) -* [Python 3.7 的新特性](https://juejin.im/post/5a127e60f265da430f31b45b) ([winjeysong](https://github.com/winjeysong) 翻译) -* [HTTP/2 下网站资源打包的正确方法](https://juejin.im/post/59f74d20f265da431523326b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yct21](https://github.com/yct21) 翻译) -* [Go并发编程中的那些事](https://juejin.im/post/59ecb058f265da43346f10e5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([kobehaha](https://github.com/kobehaha) 翻译) -* [CSV 注入:被人低估的风险](https://juejin.im/post/59eca3fef265da430b7a63c8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mnikn](https://github.com/mnikn) 翻译) -* [你不知道的 Node](https://juejin.im/post/59cf06caf265da0665640008?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lampui](https://github.com/lampui) 翻译) -* [SQL 指引:如何写出更好的查询](https://juejin.im/post/59c1d402518825396f4f6321?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zyziyun](https://github.com/zyziyun) 翻译) -* [2017年日志生态系统概述](https://juejin.im/post/59b8e345f265da0660296161?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([TanNingMeng](https://github.com/TanNingMeng) 翻译) -* [Coursera 的 GraphQL 之路](https://juejin.im/post/59b8d1d36fb9a00a3f24c439?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom) 翻译) -* [SQL 事务隔离实用指南](https://juejin.im/post/59b7ce03f265da0672281fcc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sigoden](https://github.com/sigoden) 翻译) -* [低成本将你的网站切换为 HTTPS](https://juejin.im/post/59b129365188253da63829ad?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [为什么 context.Value 重要,如何改进](https://juejin.im/post/59b20d6ff265da249517c14a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([tmpbook](https://github.com/tmpbook) 翻译) -* [搭建账户系统](https://juejin.im/post/59b2708b5188257e8a30842f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shawnchenxmu](https://github.com/shawnchenxmu) 翻译) -* [扩展 Node.js 应用](https://juejin.im/post/599eb2dbf265da246d6afb33?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mnikn](https://github.com/mnikn) 翻译) -* [在 Go 语言中增强 Cookie 的安全性](https://juejin.im/post/59aa7a4d6fb9a0249c007e16?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [关于 Node.js 的认证方面的教程(很可能)是有误的](https://juejin.im/post/599f955d51882511264e7f69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MuYunyun](https://github.com/MuYunyun) 翻译) -* [使用 Node.js 搭建一个 API 网关](https://juejin.im/post/5992769151882548b17f76a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MuYunyun](https://github.com/MuYunyun) 翻译) -* [REST API 已死,GraphQL 长存](https://juejin.im/post/5991667b518825485d28dfb1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sigoden](https://github.com/sigoden) 翻译) -* [将现有的 API 从 REST 迁移到 GraphQL](https://juejin.im/post/598eb22af265da3e26097835?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zaraguo](https://github.com/zaraguo) 翻译) -* [所有你需要知道的关于完全理解 Node.js 事件循环及其度量](https://juejin.im/post/5984816a518825265674c8f6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MuYunyun](https://github.com/MuYunyun) 翻译) -* [GraphQL vs. REST](https://juejin.im/post/59793f625188253ded721c70?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wilsonandusa](https://github.com/wilsonandusa) 翻译) -* [理解 Python 中的异步编程](https://juejin.im/entry/59704efc6fb9a06bbd6fabeb/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber) 翻译) -* [WAR 还是 JAR,你应该用哪种格式打包?](https://juejin.im/post/5966fb99f265da6c2211ac4d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([windmxf](https://github.com/windmxf) 翻译) -* [Node.js 子进程:你应该知道的一切](https://juejin.im/entry/595dc35b51882568d00a97ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([FrankXiong](https://github.com/FrankXiong) 翻译) -* [如何在无损的情况下让图片变的更小](https://juejin.im/post/5959fbe0f265da6c2518d740?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XatMassacrE](https://github.com/XatMassacrE) 翻译) -* [在 Reddit 中代码部署的演进](https://juejin.im/entry/594b7fd21b69e60062a4cb01/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber) 翻译) -* [REST 2.0 在此,它的名字叫 GraphQL](https://juejin.im/post/5947b45c128fe1006a505189?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mnikn](https://github.com/mnikn) 翻译) -* [用 Go 语言理解 Tensorflow](https://juejin.im/post/59420951128fe1006a1960f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [Node.js 流: 你需要知道的一切](https://juejin.im/post/5940a9c3128fe1006a0ab176?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([loveky](https://github.com/loveky) 翻译) -* [时间复杂度 O(log n) 意味着什么?](https://juejin.im/entry/593f56528d6d810058a355f4/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [使用 Gradle 做构建检查](https://juejin.im/entry/5937f0a48fd9c513c627114a/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jacksonke](https://github.com/jacksonke/) 翻译) -* [Django 基于 Postgres 的全文搜索](https://juejin.im/entry/593a069b61ff4b006c70ba82/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber/) 翻译) -* [理解 NodeJS 中基于事件驱动的架构](https://juejin.im/entry/5937f2cdac502e0068d1aeec/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD/) 翻译) -* [如何从一个业余爱好者成长成为专业开发者](https://juejin.im/entry/59361e1e570c35005b65464e/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zaraguo](https://github.com/zaraguo/) 翻译) -* [建立更好的代码审查制度](https://juejin.im/entry/5934bafb2f301e006b055f57/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bobmayuze](https://github.com/bobmayuze/) 翻译) -* [使用速率限制扩展你的 API](https://github.com/xitu/gold-miner/blob/master/TODO/rate-limiters.md?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([tanglie1993](https://github.com/tanglie1993/) 翻译) -* [真相就在代码中](https://juejin.im/post/59152d17da2f60005dd0ae77?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)[loveky](https://github.com/loveky) 翻译) -* [nginScript 入门](https://github.com/xitu/gold-miner/blob/master/TODO/introduction-nginscript.md?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([1992chenlu](https://github.com/1992chenlu) 翻译) -* [我是如何找回 Reddit 密码的](https://juejin.im/entry/590aee94da2f60005328fb2d/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [Node.js 之战: 如何在生产环境中调试错误](https://juejin.im/post/59035d3644d904006919086b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mnikn](https://github.com/mnikn)翻译) -* [我经常听到的 GraphQL 到底是什么?](https://juejin.im/post/58fd6d121b69e600589ec740/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih)翻译) -* [系统设计入门](https://github.com/xitu/system-design-primer/blob/master/README-zh-Hans.md) ([XatMassacrE](https://github.com/XatMassacrE) [L9m](https://github.com/L9m) [Airmacho](https://github.com/Airmacho) [xiaoyusilen](https://github.com/xiaoyusilen) [jifaxu](https://github.com/jifaxu)翻译) -* [如何使用 HTTP Headers 来保护你的 Web 应用](https://juejin.im/post/58f5d3718d6d810057c18f75/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom)翻译) -* [解析 Go 中的函数调用](https://juejin.im/post/58f579b58d6d81006491c7c0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen)翻译) -* [Go 函数调用 Redux](https://juejin.im/post/58f57be144d904006c09019c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen)翻译) -* [关于在 Node.js 中引用模块,知道这些就够了](https://juejin.im/post/58eb3812da2f60005f0bae9b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) -* [模块化 vs. 微服务](https://juejin.im/post/58eb2627da2f60005f0b2d60/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen) 翻译) -* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf) 翻译) -* [Pull request review 的十大错误](https://juejin.im/post/58ce3b3e61ff4b006c988f63/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [震惊!RxJava 5 个不为人知的小秘密](https://juejin.im/post/58cb833b8ac247218c2632e5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([skyar2009](https://github.com/skyar2009) 翻译) -* [跨站请求伪造已死!](https://juejin.im/post/58c669b6a22b9d0058b3c630?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XatMassacrE](https://github.com/XatMassacrE) 翻译) -* [Google 是如何构建 web 框架的](https://gold.xitu.io/entry/58bcdda4128fe1007e5b44db/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf)翻译) -* [这项浏览器调整使 Facebook 收到的网络请求减少了 60%](https://gold.xitu.io/entry/58b82f602f301e006c545b05/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([vuuihc](https://github.com/vuuihc)翻译) -* [用 Python 实现每秒百万级请求](https://gold.xitu.io/entry/58b5b141570c350062f6cc01/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath)翻译) -* [Node.js 支持 ES6 模块的进展](http://gold.xitu.io/entry/58b393f08d6d8100586955fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([hikerpig](https://github.com/hikerpig) 翻译) -* [在线进行大规模的数据迁移](https://gold.xitu.io/entry/58b2b7268ac24728d5484e1b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber)翻译) -* [用神经网络进行文本分类](https://gold.xitu.io/entry/58aa65ec2f301e006c32ee0c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/Kulbear) 翻译) -* [防守式编程的艺术](https://gold.xitu.io/entry/58980dbc1b69e6005997f069/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([GiggleAll](https://github.com/GiggleAll) 翻译) -* [为何我抵制使用缓存?](https://gold.xitu.io/entry/5884184f1b69e60058dc7fc6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [为什么我关闭了你的 PR (开源软件维护者笔记)](https://gold.xitu.io/entry/5870ed78da2f603a93d7e0f0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [在 Node.js 和 C++ 之间使用 Buffer 共享数据](https://gold.xitu.io/entry/586fbcefda2f600053df7787?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) -* [容器时代的分布式日志架构](https://gold.xitu.io/entry/5870f966a22b9d00588bafce?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [为 Async-Await 唱一曲赞歌](https://gold.xitu.io/entry/586eff068d6d810058794c94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xekri](https://github.com/xekri) 翻译) -* [GitHub 是如何阻止网络暴力的](https://gold.xitu.io/entry/58652f6661ff4b00583ba924?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wild-flame](https://github.com/wild-flame) 翻译) -* [在算法横行的时代,我们更需要人类来把关](https://gold.xitu.io/entry/5860fd7761ff4b0058248319?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) -* [高效的工程师一步一步来 —— 开发者影响力中的模式](https://gold.xitu.io/entry/5860f5dcb123db0065be0c45?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [简明 TensorFlow 教程 —第二部分:混合学习](https://gold.xitu.io/entry/5858ed4e1b69e6006cb12a7c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardhua](https://github.com/edvardHua) 翻译) -* [来写一个 Python 说明文档生成器吧](https://github.com/xitu/gold-miner/blob/master/TODO/python-introspection-with-the-inspect-module.md) ([王子建](https://github.com/Romeo0906) 翻译) -* [TensorFlow —  第三部分: 所有的模型](https://gold.xitu.io/entry/58574d0c8d6d810065b4a0b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardhua](https://github.com/edvardHua) 翻译) -* [用 Python 建立一个简单的对象模型](https://gold.xitu.io/entry/5852965661ff4b0063a72977?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [用不可变的基础设施提高攻击者的攻击成本 ](https://gold.xitu.io/entry/5850e60f1b69e6006c773e07?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [用 Python 和 Numpy 实现音频数字指纹特征识别](https://gold.xitu.io/entry/5850e6ebac502e0067ce86a8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [简明 TensorFlow 教程 —— 第一部分:基础知识](https://gold.xitu.io/entry/5850c11cac502e0067cd7ea5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [代码复用的风险性](https://gold.xitu.io/entry/58491d3b8e450a006aae7b4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015](https://github.com/Gocy015) 翻译) -* [通过 Python 和 Pandas 调用 SQLite Databases](https://gold.xitu.io/entry/584790a70ce46300578c5977/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [Node & Express 入门指南](https://gold.xitu.io/entry/58468843a22b9d007aa70d38/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [从 Node.js 到 Golang 的迁徙之路](https://gold.xitu.io/entry/584780928e450a006c1b801c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [Python 数据可视化概览(涵盖 ggplot 和 Altair)](https://gold.xitu.io/entry/5842eded128fe10058a3cd7a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [Webhook 该做和不该做的: 我们在整合超过 100 个 API 中所学到的](http://gold.xitu.io/entry/5840df86a22b9d007a882f5d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber) 翻译) -* [研读 NodeJS 文档,我知道了这 19 件事](http://gold.xitu.io/entry/583ad71d128fe1006be5ddd6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jacksonke](https://github.com/jacksonke) 翻译) -* [带你声明 Python 中的动态属性](http://gold.xitu.io/entry/5832a16d2e958a0069e2c560?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [承载了巨大访问量的热门游戏 Pokémon GO 的后端架构是什么?](http://gold.xitu.io/entry/580aef59bf22ec005820a1dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [人人都应该用的 Python 开源库](http://gold.xitu.io/entry/57ca8aab165abd0068e5097a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Graning](https://github.com/Graning) 翻译) -* [详解 Python 模板引擎工作机制](http://gold.xitu.io/entry/57b4609f6be3ff006a0c8ad3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [这样做才能设计出更好的数据表](http://gold.xitu.io/entry/57af3cbc5bbb500062cb38a5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [利用 Shoryuken and SQS 快速处理 API 请求](http://gold.xitu.io/entry/57a14ac879bc44005497b433?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [为什么我们要用网页端组件去构建服务器?该怎么做?](http://gold.xitu.io/entry/579ad925c4c971005abfc7a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [字体加载策略全面指南](https://gold.xitu.io/entry/5790d1aa5bbb500063b8a747?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [基于多种服务的地理位置查询系统](https://gold.xitu.io/entry/578f80196be3ff006c0657a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([emmiter](https://github.com/emmiter/) 翻译) -* [探索 Python 3 加密技术](http://gold.xitu.io/entry/575fae92df0eea0062c5a1dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yushneng](https://github.com/rainyear) 翻译) -* [Java 不可变类的整洁之道](https://gold.xitu.io/entry/5774fe212e958a22d884a49c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([buccoji](https://github.com/buccoji) 翻译) -* [如何应用最新版的谷歌表格 API](https://gold.xitu.io/entry/5773acce0a2b58006a3fd7fe?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Goshin](https://github.com/Goshin) 翻译) -* [教程:使用 Passport.js 来做后台用户验证](http://gold.xitu.io/entry/57638f286be3ff006a171870?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [探索 Python 3 加密技术](http://gold.xitu.io/entry/575fae92df0eea0062c5a1dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yushneng](https://github.com/rainyear) 翻译) -* [在生产环境中使用 Node.js 一年记](http://gold.xitu.io/entry/573d229ead5b950057645190?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [SSH 简化配置](http://gold.xitu.io/entry/5704cf8e71cfe4005dc76f18?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [Python3.5 协程原理](http://gold.xitu.io/entry/56ea295ed342d300546e1e22?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yushneng](https://github.com/rainyear) 翻译) -* [使用 Lua 完成 OAuth2 身份验证](http://gold.xitu.io/entry/56cd222199a6ce005a25b9ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([BOBO](https://github.com/CoderBOBO) 翻译) -* [Web 开发者的 HTTP/2 性能优化指南](http://gold.xitu.io/entry/56ce7d1a1532bc005372a7fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhongyi Tong](https://github.com/geeeeeeeeek) 翻译) +* [代码可视化 - 使用图技术为 Python 项目绘制结构图](https://juejin.cn/post/6935232492299354120)([Ashira97](https://github.com/Ashira97) 翻译) +* [Bash 中的 if else 语句](https://juejin.cn/post/6934324540692496392)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [每个人都可以理解的授权访问和身份认证](https://juejin.cn/post/6935230984619032589)([Ashira97](https://github.com/Ashira97) 翻译) +* [简述 HTTP 请求与跨域资源共享 CORS](https://juejin.cn/post/6927191095470194695)([zenblo](https://github.com/zenblo) 翻译) +* [如何基于已有的 REST API 实现 GraphQL API](https://juejin.cn/post/6931145990599049223)([samyu2000](https://github.com/samyu2000) 翻译) +* [上手 Python 数据类前需要知道的 6 件事](https://juejin.cn/post/6926815217859559438)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [Python 定义函数的 5 种参数](https://juejin.cn/post/6927094483200770062)([Zhengjian-L](https://github.com/Zhengjian-L) 翻译) +* [微服务是你的最佳解决方案么?](https://juejin.cn/post/6881415957303001102)([wangqinggang](https://github.com/wangqinggang) 翻译) +* [Python 中的列表和元组](https://juejin.cn/post/6923195053754023949)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [Node.js 缓冲区的完整指南](https://juejin.cn/post/6917192648424390669)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [Node.js 安全编程的最佳实践](https://juejin.cn/post/6918757099782537224)([Ashira97](https://github.com/Ashira97) 翻译) +* [如何使用 Node.js 执行多线程](https://juejin.cn/post/6915255619926622222)([zenblo](https://github.com/zenblo) 翻译) +* [理解 LSM 树:一种适用于频繁写入的数据库的结构](https://juejin.cn/post/6918940339676020743)([samyu2000](https://github.com/samyu2000) 翻译) +* [爱 GraphQL 胜过 REST](https://juejin.cn/post/6914306976294338567)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [WebTransport 会在不久的将来取代 WebRTC 吗?](https://juejin.cn/post/6910186017190313991)([Usualminds](https://github.com/Usualminds) 翻译) +* [2021 年 Web 开发者应该掌握的 15 个 VSCode 扩展](https://juejin.cn/post/6910570256645914637)([regon-cao](https://github.com/regon-cao) 翻译) +* [Elasticsearch 新手指南](https://juejin.cn/post/6913725535717851144)([yqian1991](https://github.com/yqian1991) 翻译) +* [使用 SpringBoot 和 MySQL 构建 GraphQL 服务端应用程序](https://juejin.cn/post/6899241103682502670)([samyu2000](https://github.com/samyu2000) 翻译) +* [为什么如今 Deno 正全面取代 Node.js](https://juejin.cn/post/6897420951592534030)([samyu2000](https://github.com/samyu2000) 翻译) +* [Blitz.js 简介:一个新兴的 React 全栈框架](https://juejin.cn/post/6887201657801670669)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [5 分钟内从单体架构迁移到微服务架构](https://juejin.cn/post/6900884077226917901)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [在几秒钟内为你的开发环境创建一个私有 PostgreSQL 数据库](https://juejin.cn/post/6899674625325105159)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [使用 Svelte 开发前端应用的五个理由](https://juejin.cn/post/6897010393609142279)([zenblo](https://github.com/zenblo) 翻译) +* [给初学者的示例:什么是 WSGI?](https://juejin.cn/post/6896716356054417416)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [Github Actions 工作流的创建与跟踪](https://juejin.cn/post/6892248874669309965)([zenblo](https://github.com/zenblo) 翻译) +* [Deno 已经死了吗?](https://juejin.cn/post/6899332861414146055)([Inchill](https://github.com/Inchill) 翻译) +* [Python List 使用注意事项](https://juejin.cn/post/6886633614717485070)([samyu2000](https://github.com/samyu2000) 翻译) +* [Golang 切片综合指南](https://juejin.cn/post/6883398632071462919)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [通过“四不要”掌握 Python 中的 Lambda 函数](https://juejin.cn/post/6883389756269395975)([loststar](https://github.com/loststar) 翻译) +* [Python logging 使用指南](https://juejin.im/post/6881981250203353095)([samyu2000](https://github.com/samyu2000) 翻译) +* [使用 Shpinx 为 Python 项目自动生成文档](https://juejin.cn/post/6882904677373968397)([actini](https://github.com/actini) 翻译) +* [Python 的优化 — 驻留机制](https://juejin.im/post/6875879902902485005)([samyu2000](https://github.com/samyu2000) 翻译) +* [利用映射提高 MongoDB 性能](https://juejin.im/post/6881503834737213454)([onlinelei](https://github.com/onlinelei) 翻译) +* [Python:使用 locals() 和 globals() 巧妙编程](https://github.com/xitu/gold-miner/blob/master/article/2020/python-smart-coding-with-locals-and-global.md)([actini](https://github.com/actini) 翻译) +* [如何创建一个可复用的网页爬虫](https://juejin.im/post/6860354555759869966)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [写给工程师的《系统性能兵法》](https://juejin.im/post/6858061688386617358)([lhd951220](https://github.com/lhd951220) 翻译) +* [记一次 —— 构建 API 网关服务的经历](https://juejin.im/post/5ef078666fb9a0589364a46b)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [Schema.org:你未曾耳闻的流行网页标准 🤫](https://juejin.im/post/5ee4ce2df265da770c0f08b6)([lhd951220](https://github.com/lhd951220) 翻译) +* [如何使用 Python 生成随机文本验证码](https://juejin.im/post/5f1567a3f265da22db2c351d)([lhd951220](https://github.com/lhd951220) 翻译) +* [鲜为人知的 GraphQL 特性](https://juejin.im/post/5edbaf2751882543281f73fc)([hansonfang](https://github.com/hansonfang) 翻译) +* [你理解数据库死锁发生的原因吗?](https://juejin.im/post/5ed9ac93e51d45783f10fd25)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [使用 Deno 和 Oak 构建 CRUD API](https://juejin.im/post/5ed711086fb9a0479a801362)([lhd951220](https://github.com/lhd951220) 翻译) +* [如何编写可节省您时间的日志文件](https://juejin.im/post/5edf8d636fb9a047cd65d136)([PingHGao](https://github.com/PingHGao) 翻译) +* [Python 内存管理之垃圾回收](https://juejin.im/post/5ecdcea6f265da77160035c7)([chaingangway](https://github.com/chaingangway) 翻译) +* [异步编程和多线程,我该选择哪个方案?](https://juejin.im/post/6844904168159707150)([chaingangway](https://github.com/chaingangway) 翻译) +* [使用 GraphQL 的 6 个月](https://juejin.im/post/5eb63dfae51d454dea6fdd78)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [如何在自己的计算机上模拟 UDP Flood DoS 攻击](https://juejin.im/post/5eb8fb09e51d4540bb6172e1)([chaingangway](https://github.com/chaingangway) 翻译) +* [使用 Django 构建一个简单的邮件服务](https://juejin.im/post/5eb6171c5188256d7a3cac97)([shixi-li](https://github.com/shixi-li) 翻译) +* [在 Node.js 中用 Puppeteer 实现网络爬虫](https://juejin.im/post/5eb25a806fb9a04356087809)([Baddyo](https://github.com/Baddyo) 翻译) +* [Kafka vs. RabbitMQ:为什么使用 Kafka?](https://juejin.im/post/5e9e29c8f265da47a831421a)([QinRoc](https://github.com/QinRoc) 翻译) +* [MySQL 最佳实践 — 高效插入数据](https://juejin.im/post/5e8dc755e51d4546d32bcdd1)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [Go 发布新版 Protobuf API](https://juejin.im/post/5e83e1176fb9a03c80278e6d)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [用依赖注入来解耦你的代码](https://juejin.im/post/5e80a1d46fb9a03c8c03fe51)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [给 NodeJS 的 Logs 点颜色看看!](https://juejin.im/post/5e6f01b151882549422ef315)([cyz980908](https://github.com/cyz980908) 翻译) +* [停止在任何地方使用 ===](https://juejin.im/post/5e5fb5e951882549522ac8a2)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [NestJS 实现基本用户认证和会话](https://juejin.im/post/5e8c829f6fb9a03c4857710d)([cyz980908](https://github.com/cyz980908) 翻译) +* [TypeScript 中带生成器的惰性管道](https://juejin.im/post/5eaa43616fb9a0432c4c8fc8)([febrainqu](https://github.com/febrainqu) 翻译) +* [用 6 分钟学习如何用 Redis 缓存您的 NodeJS 应用!](https://juejin.im/post/5e4df6d7518825496452ac98)([cyz980908](https://github.com/cyz980908) 翻译) +* [SQL 将死于 No-SQL 之手?](https://juejin.im/post/5e5517bff265da576b566551)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [如何选择合适的数据库](https://juejin.im/post/5e3c10e6518825494f7de8ff)([cyz980908](https://github.com/cyz980908) 翻译) +* [如何用 Nest.js、MongoDB 和 Vue.js 搭建一个博客](https://juejin.im/post/5e1820a951882526334a1d1f)([cyz980908](https://github.com/cyz980908) 翻译) +* [C++ 中清晰明了的状态机代码](https://juejin.im/post/5e0ad822e51d45414f5c7fc1)([zh1an](https://github.com/zh1an) 翻译) +* [PHP 7.4 有什么新功能?你必须掌握的 10 大特性](https://juejin.im/post/5dfa04316fb9a0160770a501)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [将 GraphQL 概念可视化](https://juejin.im/post/5de480d7f265da05ce3b7368)([cyz980908](https://github.com/cyz980908) 翻译) +* [你不需要 passport.js — node.js 认证指南](https://juejin.im/post/5e060589f265da33b0718f55)([HytonightYX](https://github.com/HytonightYX) 翻译) +* [动态规划算法的实际应用:接缝裁剪](https://juejin.im/post/5de8b483f265da33d039c618)([nettee](https://github.com/nettee) 翻译) +* [Node.js 新特性将颠覆 AI、物联网等更多惊人领域](https://juejin.im/post/5dbb8d70f265da4d12067a3e)([Baddyo](https://github.com/Baddyo) 翻译) +* [如何使用 Mountebank 和 Node.js 来 Mock 服务](https://juejin.im/post/5dad5a6951882509674032cd)([Pingren](https://github.com/Pingren) 翻译) +* [Syslog:系统管理员完整指南](https://juejin.im/post/6858168312388386824)([githubmnume](https://github.com/githubmnume) 翻译) +* [为什么你要学习 Go?](https://juejin.im/post/5d6ce211f265da03cd0a99be)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [使用因果分析优化 Go HTTP/2 服务器](https://juejin.im/post/5dc3e5faf265da4d144e86c2)([JackEggie](https://github.com/JackEggie) 翻译) +* [如何杀死一个进程和它的所有子进程](https://juejin.im/post/5d68a1a951882525830c7093)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [Python 的打包现状(写于 2019 年)](https://juejin.im/post/5d72104851882572ed0004d2)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Docker 的学习和应用](https://juejin.im/post/5d650a36f265da03c34c0bb4)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [深入理解 Python 类型提示](https://juejin.im/post/5d64905fe51d4561fd6cb50f)([hu7may](https://github.com/hu7may) 翻译) +* [通过 Rust 学习解析器组合器 — 第四部分](https://juejin.im/post/5d629f75e51d456210163bc0)([40m41h42t](https://github.com/40m41h42t) 翻译) +* [胜者是 Stream:NodeJS 读取大数据集合几种方法的性能比较](https://juejin.im/post/5d67c71e51882537930bc593)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [可靠地运维一个大型分布式系统:我的学习实践](https://juejin.im/post/5d567cd4e51d4561e224a324)([Pingren](https://github.com/Pingren) 翻译) +* [数据分片是如何在分布式 SQL 数据库中起作用的](https://juejin.im/post/5d42867a6fb9a06ac76d915d)([Ultrasteve](https://github.com/Ultrasteve) 翻译) +* [为什么我们要切换到 gRPC](https://juejin.im/post/5cff855c518825612f412526)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [用 React 和 Node.js 实现受保护的路由和权限验证](https://juejin.im/post/5c1cdaaa6fb9a049aa6f0f8b)([ElizurHz](https://github.com/ElizurHz) 翻译) +* [Python 与大数据:Airflow & Jupyter Notebook with Hadoop 3, Spark & Presto](https://juejin.im/post/5b5a7fdfe51d453526175687)([cf020031308](https://github.com/cf020031308) 翻译) +* [给初学者的 Jupyter Notebook 教程](https://juejin.im/post/5af8d3776fb9a07ab7744dd0)([7Ethan](https://github.com/7Ethan) 翻译) +* [利用 Keras 深度学习库进行词性标注教程](https://juejin.im/post/5ae4613a5188256727742d7d)([luochen1992](https://github.com/luochen1992) 翻译) +* [为你的网站带上帽子 — 使用 helmet 保护 Express 应用](https://juejin.im/post/5a24fd8f51882509e5438247)([lsvih](https://github.com/lsvih) 翻译) +* [如何使用 Golang 中的 Go-Routines 写出高性能的代码](https://juejin.im/post/5a17c0f9f265da431a42e060)([tmpbook](https://github.com/tmpbook) 翻译) +* [并发编程](https://juejin.im/post/59ecb058f265da43346f10e5)([kobehaha](https://github.com/kobehaha) 翻译) +* [混乱世界中的稳定:Postgres 如何使事务原子化](https://juejin.im/post/59db0f94518825788a44470e)([TanNingMeng](https://github.com/TanNingMeng) 翻译) +* [把 UUID 或者 GUID 作为主键?你得小心啦!](https://juejin.im/post/59561e5b6fb9a06bbf6fdf16)([zaraguo](https://github.com/zaraguo) 翻译) +* [理解 NPM 5 中的 lock 文件](https://juejin.im/post/5943849aac502e006b84ce07)([changkun](https://github.com/changkun) 翻译) +* [Web 开发者安全清单](https://juejin.im/post/592651c944d904006400cd88)([gangsterhyj](https://github.com/GangsterHyj) 翻译) +* [前端 vs 后端:哪一个适合你?](https://juejin.im/post/5d36b5e3f265da1bd3059a21)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [Go 语言概览](https://juejin.im/post/5d386166e51d454fd8057c6a)([JackEggie](https://github.com/JackEggie) 翻译) +* [Google 的 Pagespeed 的工作原理:提升你的分数和搜索引擎排名](https://juejin.im/post/5d36903ce51d4510803ce491)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [使用 Node.js 读取超大的文件(第一部分)](https://juejin.im/post/5d3c27ccf265da1b8d1665ba)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [从 Reddit 讨论中看到的 GraphQL 现状](https://juejin.im/post/5d380909e51d4510624f98a0)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [喷泉码和动态二维码](https://juejin.im/post/5d391ae1f265da1bb0040352)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Kubernetes 儿童插图指南](https://juejin.im/post/5d1b2a656fb9a07edc0b7058)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [使用 Gomobile 和 Gopherjs 的动态二维码数据传输](https://juejin.im/post/5d2bfccef265da1bb77699e8)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [通过 Rust 学习解析器组合器 — 第三部分](https://juejin.im/post/5d1f29f7f265da1b961324b2)([suhanyujie](https://github.com/suhanyujie) 翻译) +* [通过 Rust 学习解析器组合器 — 第二部分](https://juejin.im/post/5d04c3abe51d45775d516f7b)([suhanyujie](https://github.com/suhanyujie) 翻译) +* [通过 Rust 学习解析器组合器 — 第一部分](https://juejin.im/post/5cfddd00f265da1b7e102bee)([suhanyujie](https://github.com/suhanyujie) 翻译) +* [Python 实现排序算法](https://juejin.im/post/5d1323b6e51d45108b2caeaf)([fireairforce](https://github.com/fireairforce) 翻译) +* [WebSockets 与长轮询的较量](https://juejin.im/post/5d0b1381e51d455a694f9544)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [可维护的 ETL: 使管道更容易支持和扩展的技巧](https://juejin.im/post/5d08e178518825166f36bf89)([fireairforce](https://github.com/fireairforce) 翻译) +* [利用并行流渐进加载图片](https://juejin.im/post/5d044fe3f265da1bd04eddda)([twang1727](https://github.com/twang1727) 翻译) +* [尝试 DevOps:最适合你的是什么样的工具?](https://juejin.im/post/5cfd4aa3f265da1bb277233e)([Starriers](https://github.com/Starriers) 翻译) +* [超快速的分析器(二):惰性解析](https://juejin.im/post/5cf33bd751882579e53f0130)([suhanyujie](https://github.com/suhanyujie) 翻译) +* [如何使用 Node.js 构建一个命令行界面(CLI)](https://juejin.im/post/5cf2111b5188250d2850f884)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Node.js 日志记录指南](https://juejin.im/post/5cf213e4e51d4577407b1cda)([fireairforce](https://github.com/fireairforce) 翻译) +* [超快速的分析器(一):优化扫描器](https://juejin.im/post/5ce8cbd9e51d4556bb4cd2f9)([nettee](https://github.com/nettee) 翻译) +* [通过优化 Gunicorn 配置提高性能](https://juejin.im/post/5ce8cab8e51d4577523f22f8)([shixi-li](https://github.com/shixi-li) 翻译) +* [Go 语言工具概述](https://juejin.im/post/5ce4dc17518825240245be5b)([iceytea](https://github.com/iceytea) 翻译) +* [如果可以,永远不要在生产中直接运行 Node.js](https://juejin.im/post/5cdeb1306fb9a07efd46dbe5)([fireairforce](https://github.com/fireairforce) 翻译) +* [化 Markdown 为 HTML:用 Node.js 和 Express 搭建接口](https://juejin.im/post/5cdcc216e51d453a543f9e68)([Baddyo](https://github.com/Baddyo) 翻译) +* [使用 Nodemailer 轻松构建能通过电子邮件的重置密码 React 应用程序](https://juejin.im/post/5cdea6e3e51d4510b51279b3)([fireairforce](https://github.com/fireairforce) 翻译) +* [模式 — 使用 Typescript 和 Node.js 的通用仓储](https://juejin.im/post/5cc715e1f265da03b36ef390)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [自动补全规则](https://juejin.im/post/5cd556ef6fb9a03218556cb7)([fireairforce](https://github.com/fireairforce) 翻译) +* [Spring 的分布式事务实现 — 使用和不使用 XA — 第一部分](https://juejin.im/post/5cce4659f265da038a1487c9)([JackEggie](https://github.com/JackEggie) 翻译) +* [使用 VS Code 调试 Node.js 的超简单方法](https://juejin.im/post/5cce9b976fb9a0322415aba4)([iceytea](https://github.com/iceytea) 翻译) +* [分布式系统如何从故障中恢复?— 重试、超时和退避](https://juejin.im/post/5ccf98ace51d456e6d133541)([nettee](https://github.com/nettee) 翻译) +* [减少 Python 中循环的使用](https://juejin.im/post/5cc8e012e51d453b6d4d13fd)([qiuyuezhong](https://github.com/qiuyuezhong) 翻译) +* [Node.js 提供百万的活跃 WebSocket 连接](https://juejin.im/post/5cbeb2f45188250ab65f1d0c)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [Node.js 会永远只是慢的 Golang 吗?](https://juejin.im/post/5cc811fc6fb9a0322415a70d)([steinliber](https://github.com/steinliber) 翻译) +* [用 Rust 打造你的第一个命令行工具](https://juejin.im/post/5cb33b94e51d456e63760453)([JackEggie](https://github.com/JackEggie) 翻译) +* [Spring 的分布式事务实现 — 使用和不使用XA — 第三部分](https://juejin.im/post/5caee1ee6fb9a068890f1eff)([radialine](https://github.com/radialine) 翻译) +* [Spring 的分布式事务实现 — 使用和不使用XA — 第二部分](https://juejin.im/post/5cae93ddf265da03a85aaac3)([xiantang](https://github.com/xiantang) 翻译) +* [Java 和 etcd:因为 jetcd 最终走到了一起](https://juejin.im/post/5cae92f8f265da0360239b89)([mingxing47](https://github.com/mingxing47) 翻译) +* [多线程简介](https://juejin.im/post/5ca351da6fb9a05e6a08745b)([steinliber](https://github.com/steinliber) 翻译) +* [用 Apache Shiro 来强化一个 Spring Boot 应用](https://juejin.im/post/5c9f60c7e51d451cf929305d)([lihanxiang](https://github.com/lihanxiang) 翻译) +* [数据流简介](https://juejin.im/entry/5c8f457cf265da60cf50e5b2)([steinliber](https://github.com/steinliber) 翻译) +* [连接数据流](https://juejin.im/post/5c8efcbee51d457cb772778f)([whatbeg](https://github.com/whatbeg) 翻译) +* [Golang 数据结构:树](https://juejin.im/post/5c8e023351882545eb718c9d)([steinliber](https://github.com/steinliber) 翻译) +* [Node.js 基础知识: 没有依赖关系的 Web 服务器](https://juejin.im/post/5c88a6855188257b0b126564)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [Rust 语言案例研究:社区使得 Rust 成为 npm 的简单选择](https://juejin.im/post/5c88a12ae51d455cd96a14bb)([WangLeto](https://github.com/WangLeto) 翻译) +* [论数据流的扩展性](https://juejin.im/post/5c8329d25188257ea038a05e)([Park-ma](https://github.com/Park-ma) 翻译) +* [负载性能](https://juejin.im/post/5c7faa955188251bdd53ebd2)([WangLeto](https://github.com/WangLeto) 翻译) +* [Java Service 加载器 和 spring Factories 加载器的比较](https://juejin.im/post/5c7fbe52e51d4541e510d282)([HearFishle](https://github.com/HearFishle) 翻译) +* [在 GO 语言中创建你自己 OAuth2 服务:客户端凭据授权流程](https://juejin.im/post/5c77639a5188251fd46eea45)([shixi-li](https://github.com/shixi-li) 翻译) +* [谷歌搜索操作符大全(包含 42 个高级操作符)](https://juejin.im/post/5c73744ef265da2dc675c029)([cdpath](https://github.com/cdpath) 翻译) +* [提供隐私和过滤功能的 DNS 服务器](https://juejin.im/post/5c7365ca5188256282697eaa)([ScDadaguo](https://github.com/ScDadaguo) 翻译) +* [教程 — 用 C 写一个 Shell](https://juejin.im/post/5c73dd7d6fb9a049aa6fb9aa)([nettee](https://github.com/nettee) 翻译) +* [用 Rust 写一个微服务](https://juejin.im/post/5c7a3777f265da2dd773fc38)([nettee](https://github.com/nettee) 翻译) +* [理解数据库分片](https://juejin.im/entry/5c791672f265da2da67c46eb/detail)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [HTTP/3:起源](https://juejin.im/post/5c6cb623f265da2dd37c1505)([Starriers](https://github.com/Starriers) 翻译) +* [我作为软件工程师与一名数据科学家合作的经历](https://juejin.im/post/5c550038f265da2d8532b2f9)([CasualJi](https://github.com/CasualJi) 翻译) +* [HTTP 简史](https://juejin.im/post/5c5ecc04e51d457f9c058be6)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [HTTP/2 常见问题解答](https://juejin.im/post/5c5ada2e6fb9a049dd80be75)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [DNS over TLS:端到端加密的 DNS](https://juejin.im/post/5c4849d06fb9a049c30b967b)([lsvih](https://github.com/lsvih) 翻译) +* [Courier: Dropbox 的 gRPC 迁移利器](https://juejin.im/post/5c55997ae51d457fd81e3ca0)([kasheemlew](https://github.com/kasheemlew) 翻译) +* [在 Flask 中使用 Redis Queue 实现异步任务](https://juejin.im/post/5c407497e51d457cba6ca871)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [再看 Flask 视频流](https://juejin.im/post/5c33540451882524ed5b9154)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [提高营销效率的工程(二)— 广告制作和管理的规模化](https://juejin.im/post/5c441193518825258604ecd0)([Starriers](https://github.com/Starriers) 翻译) +* [数据流的不同应用场景 — Java](https://juejin.im/post/5c2c285fe51d4522ec5a2795)([Starriers](https://github.com/Starriers) 翻译) +* [无容器下的云计算](https://juejin.im/post/5c24800a518825673b02dcfe)([TrWestdoor](https://github.com/TrWestdoor) 翻译) +* [如何在六个月或更短的时间内成为 DevOps 工程师,第四部分:打包](https://juejin.im/post/5c19d6255188252ea66b33b3)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [使用 NodeJS 创建一个 GraphQL 服务器](https://juejin.im/post/5c015a5af265da612577d89a)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [Medium 的 GraphQL 服务设计](https://juejin.im/post/5c00dad3f265da617006db4e)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [关于 HTTP/3 的一些心得](https://juejin.im/post/5bfb519ef265da610f636596)([Starriers](https://github.com/Starriers) 翻译) +* [用 Flask 输出视频流](https://juejin.im/post/5bea86fc518825158c531e9c)([BriFuture](https://github.com/BriFuture) 翻译) +* [Rust 开发完整的 Web 应用程序](https://juejin.im/post/5bd66dee6fb9a05cdb1081ca)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [Node.js 高性能和可扩展应用程序的最佳实践 [第 2/3 部分]](https://juejin.im/post/5bca9208f265da0ade1ceffb)([jianboy](https://github.com/jianboy) 翻译) +* [构建高性能和可扩展性 Node.js 应用的最佳实践 [第 3/3 部分]](http://5bcf14cee51d451cb039d13d/)([steinliber](https://github.com/steinliber) 翻译) +* [开源项目之 Nginx](https://juejin.im/post/5bc55a25f265da0ae8014147)([razertory](https://github.com/razertory) 翻译) +* [如何在六个月或更短的时间内成为 DevOps 工程师,第一部分](https://juejin.im/post/5bc21c125188255c53364ad5)([tmpbook](https://github.com/tmpbook) 翻译) +* [Go 语言的整洁架构之道/一个使用 gRPC 的 Go 项目整洁架构例子](https://juejin.im/post/5bb99195e51d450e551a3a2f)([yuwhuawang](https://github.com/yuwhuawang) 翻译) +* [Node.js 高性能和可扩展应用程序的最佳实践 [第 1/3 部分]](https://juejin.im/post/5bc0f68af265da0abe2720bf)([jianboy](https://github.com/jianboy) 翻译) +* [使用 Node 和 OAuth 2.0 构建一个简单的 REST API](https://juejin.im/post/5bb1d3f95188255c6a044d9a)([Starriers](https://github.com/Starriers) 翻译) +* [容器,虚拟机以及 Docker 的初学者入门介绍](https://juejin.im/entry/5bada97f6fb9a05d0e2e7014/detail)([steinliber](https://github.com/steinliber) 翻译) +* [如何在六个月或更短的时间内成为DevOps 工程师,第2部分:配置](https://juejin.im/post/5baf677df265da0a951ee8f5)([jianboy](https://github.com/jianboy) 翻译) +* [如何在六个月或更短的时间内成为DevOps 工程师,第三部分:版本控制](https://juejin.im/post/5bb067bfe51d450e905a0aa4)([jianboy](https://github.com/jianboy) 翻译) +* [2018 年度最佳数据库即服务解决方案](https://juejin.im/post/5ba784e3e51d450e9d64984d)([cf020031308](https://github.com/cf020031308) 翻译) +* [SmartyStreets 的 Go 测试探索之路](https://juejin.im/post/5ba83f2ff265da0a867c3818)([kasheemlew](https://github.com/kasheemlew) 翻译) +* [使用 Go 编写微服务及其 GraphQL 网关](https://juejin.im/post/5b94cf476fb9a05d26593f07)([changkun](https://github.com/changkun) 翻译) +* [GopherCon 2018:揭秘二叉查找树算法](https://juejin.im/post/5b94de9c5188255c5047076c)([changkun](https://github.com/changkun) 翻译) +* [使用 Nexmo 和微软语音翻译 API 构建 Babel 鱼](https://juejin.im/post/5b8a78a3e51d4538a515cbda)([Starriers](https://github.com/Starriers) 翻译) +* [如何优化企业级规模的 Node.js 应用程序](https://juejin.im/post/5b83c639f265da436d7e4c5e)([Starriers](https://github.com/Starriers) 翻译) +* [Databook:通过元数据,Uber 将大数据转化为知识](https://juejin.im/post/5b800032e51d45389d3b4950)([cf020031308](https://github.com/cf020031308) 翻译) +* [Python 的多线程与多进程](https://juejin.im/post/5b84f3086fb9a01a1a27cedb)([lsvih](https://github.com/lsvih) 翻译) +* [如何在数据科学中写出生产层面的代码?](https://juejin.im/post/5b7adb7751882542d63b2805)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [Apache Airflow 的关键概念](https://juejin.im/post/5b7ba247e51d4538d42ab6a0)([Starriers](https://github.com/Starriers) 翻译) +* [我是如何使用 Python 在 Medium 上找到并关注有趣的人](https://juejin.im/post/5b72c61851882561311fccce)([Park-ma](https://github.com/Park-ma) 翻译) +* [如何使用 Python 和 BeautifulSoup 抓取网站内容](https://juejin.im/post/5b74fcec51882561446fb97f)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [我如何使用 Node.js 来实现工作自动化](https://juejin.im/post/5b4fe75ef265da0f54052138)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [在 UNIX 中,一切皆文件](https://juejin.im/post/5b652d346fb9a04fc03129e6)([pmwangyang](https://github.com/pmwangyang) 翻译) +* [使用 PhpFastCache 提升网站性能](https://juejin.im/post/5b54d01be51d4517c5649965)([lsvih](https://github.com/lsvih) 翻译) +* [我们是如何高效实现一致性哈希的](https://juejin.im/post/5b5488a96fb9a04fad3a181a)([yqian1991](https://github.com/yqian1991) 翻译) +* [正则表达式要跑 5 天,所以我做了个工具将其缩短至 15 分钟。](https://juejin.im/post/5b6d426f6fb9a04fd1604341)([cf020031308](https://github.com/cf020031308) 翻译) +* [如何使用 Pandas 重写你的 SQL 查询以及其他操作](https://juejin.im/post/5b5e5b2ee51d4517df1510c7)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [Robinhood 为什么使用 Airflow](https://juejin.im/post/5b4808f751882519ec07eaba)([cf020031308](https://github.com/cf020031308) 翻译) +* [Web 应用架构基础课](https://juejin.im/post/5b69a8eef265da0f926baa56)([horizon13th](https://github.com/horizon13th) 翻译) +* [Airflow: 一个工作流程管理平台](https://juejin.im/post/5b5bd2b6f265da0f60131d0c)([yqian1991](https://github.com/yqian1991) 翻译) +* [从 Cron 到 Airflow 的迁移中我们学到了什么](https://juejin.im/post/5b4c3575f265da0f7334bbc9)([cf020031308](https://github.com/cf020031308) 翻译) +* [[字幕翻译] Andrew Godwin — Django 异步 — PyCon 2018](https://www.bilibili.com/video/av24571596/)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [我是如何从零开始建立一个网络爬虫来实现我的求职自动化的](https://juejin.im/post/5b3b40896fb9a04f9e22e927)([Starriers](https://github.com/Starriers) 翻译) +* [使用多重赋值与元组解包提升 Python 代码的可读性](https://juejin.im/post/5b3c2cf1e51d451925625b94)([lsvih](https://github.com/lsvih) 翻译) +* [通过 SSH 远程使用 Python 解释器来运行 Flask](https://juejin.im/post/5b3e25a8e51d45191716d187)([Starriers](https://github.com/Starriers) 翻译) +* [从 Java EE 8 Security API 开始 — 第二部分](https://juejin.im/post/5b3b49d66fb9a04f8a2160a9)([Starriers](https://github.com/Starriers) 翻译) +* [基于 Node.js 的 Alexa Skills Kit 发布了!](https://juejin.im/post/5b4790b6f265da0f5d4cbec5)([Yuhanlolo](https://github.com/Yuhanlolo) 翻译) +* [使用 Python 实现接缝裁剪算法](https://juejin.im/post/5b46ee8e6fb9a04fc436ad60)([caoyi0905](https://github.com/caoyi0905) 翻译) +* [Erlang 之禅第二部分](https://juejin.im/post/5b3ea3ed6fb9a04fb8772a2c)([7Ethan](https://github.com/7Ethan) 翻译) +* [从 Java EE 8 Security API 开始 — 第一部分](https://juejin.im/post/5b35a8d4f265da599423598b)([Starriers](https://github.com/Starriers) 翻译) +* [通过插图学习 Go 的并发](https://juejin.im/post/5b2cd078e51d4558b70ca399)([elliott-zhao](https://github.com/elliott-zhao) 翻译) +* [Kubernetes 分布式应用部署和人脸识别 app 实例](https://juejin.im/post/5b2db0576fb9a00e50313904)([maoqyhz](https://github.com/maoqyhz) 翻译) +* [[字幕翻译] Graham Dumpleton — Secrets of a WSGI master. — PyCon 2018](https://github.com/xitu/gold-miner/blob/master/TODO1/secrets-of-a-wsgi-master-pycon-2018.md)([vuuihc](https://github.com/vuuihc) 翻译) +* [Erlang 之禅第一部分](https://juejin.im/post/5b2a16cce51d4558d726e8c9)([steinliber](https://github.com/steinliber) 翻译) +* [[字幕翻译] James Bennett — 理解 Python 字节码 — PyCon 2018](https://github.com/xitu/gold-miner/issues/3990)([cdpath](https://github.com/cdpath) 翻译) +* [如何通过树莓派的深度学习轻松检测对象](https://juejin.im/post/5b1ba938518825137661af46)([Starriers](https://github.com/Starriers) 翻译) +* [[字幕翻译] 玛利亚塔·维加亚 — 什么是 Python 核心开发者?— PyCon 2018](https://juejin.im/post/5b152c825188257d8a48d4a8)([elliott-zhao](https://github.com/elliott-zhao) 翻译) +* [一种更简单的途径在 Java 中进行函数式编程](https://juejin.im/post/5b24aa5f6fb9a00e4d53e0c9)([maoqyhz](https://github.com/maoqyhz) 翻译) +* [在 Laravel 应用程序之间共享数据库](https://juejin.im/post/5b17407fe51d4506a14db524)([elliott-zhao](https://github.com/elliott-zhao) 翻译) +* [支撑现代存储系统的算法](https://juejin.im/post/5b10f80b5188257d92206851)([LeopPro](https://github.com/LeopPro) 翻译) +* [使用 Go 语言的流模式来解析 DrugBank 的 XML(或者任何大的 XML 文件)](https://juejin.im/entry/5b06322a6fb9a07aab2a3d44)([steinliber](https://github.com/steinliber) 翻译) +* [那些我们不需要的 HTTP 头信息](https://juejin.im/post/5b06c89df265da0db35022d8)([SergeyChang](https://github.com/SergeyChang) 翻译) +* [由 Node.js 发送 Web 推送通知](https://juejin.im/post/5afc32146fb9a07acf5657e7)([lsvih](https://github.com/lsvih) 翻译) +* [30 分钟 Python 爬虫教程](https://juejin.im/post/5afab181f265da0b7452514a)([kezhenxu94](https://github.com/kezhenxu94) 翻译) +* [Python 中的键值(具名)参数:如何使用它们](https://juejin.im/post/5ae97546f265da0b8d41bcc7)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [使用 python 和 keras 实现卷积神经网络](https://juejin.im/post/5aefb0f351882567336aa3c7)([JohnJiangLA](https://github.com/JohnJiangLA) 翻译) +* [使用 Go 和 AWS Lambda 构建无服务 API](https://juejin.im/post/5af4082f518825672a02f262)([sisibeloved](https://github.com/sisibeloved) 翻译) +* [Java 桥接方法详解](https://juejin.im/post/5af28ca0518825672565da74)([kezhenxu94](https://github.com/kezhenxu94) 翻译) +* [我是如何修复 Python 3.7 中一个非常古老的 GIL 竞态条件 bug 的](https://juejin.im/post/5aeba1075188256712786039)([kezhenxu94](https://github.com/kezhenxu94) 翻译) +* [GAN 的 Keras 实现:构建图像去模糊应用](https://juejin.im/post/5ad6e358f265da237b229bb2)([luochen1992](https://github.com/luochen1992) 翻译) +* [用 Redis 和 Python 构建一个共享单车的 app](https://juejin.im/post/5adc861a51882567161a2799)([Starriers](https://github.com/Starriers) 翻译) +* [Node.js 能进行 HTTP/2 推送啦!](https://juejin.im/post/5ad61595f265da23a04a129c)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [用 Skater 解读预测模型:打开模型的黑箱](https://juejin.im/post/5ae1494bf265da0b7c06f835)([radialine](https://github.com/radialine) 翻译) +* [使用 NumPy 和 Pandas 进行 Python 式数据清理](https://juejin.im/post/5ad57db3f265da239c7bd9fb)([bambooom](https://github.com/bambooom) 翻译) +* [不用 Class,如何写一个类](https://juejin.im/post/5acadb6d6fb9a028cb2deb8f)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [JanusGraph 为 PHP 助力](https://juejin.im/post/5ac31768f265da23766b7970)([GanymedeNil](https://github.com/GanymedeNil) 翻译) +* [Pandas 数据类型概览](https://juejin.im/post/5acc36e66fb9a028d043c2a5)([stormluke](https://github.com/stormluke) 翻译) +* [使用 python 分析 14 亿条数据](https://juejin.im/post/5aceae206fb9a028d2084fea)([rydensun](https://github.com/rydensun) 翻译) +* [用户领域 API 监控和代码注入检测](https://juejin.im/post/5ac485175188255c93237f5d)([Xekin-FE](https://github.com/Xekin-FE) 翻译) +* [VINE:一种开源的神经进化(Neuroevolution)交互式数据可视化工具](https://juejin.im/post/5ac466d6f265da238059db99)([Starriers](https://github.com/Starriers) 翻译) +* [用 Python 编程进行糖尿病相关的机器学习](https://juejin.im/post/5ace62e96fb9a028b92d8267)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [如何用 Python 写一个 Discord 机器人](https://juejin.im/post/5ac1b9796fb9a028c42e5a61)([Starriers](https://github.com/Starriers) 翻译) +* [Web 爬虫下的 Python 数据分析:中情局全球概况图解](https://juejin.im/post/5ab9fcebf265da238e0dc349)([Starriers](https://github.com/Starriers) 翻译) +* [Elasticsearch 滚动升级](https://juejin.im/post/5ab5f53f518825556b6cbdea)([rpgmakervx](https://github.com/rpgmakervx) 翻译) +* [这可能是 2018 年最好的一篇 PHP 性能测评(包含 5.6 到 7.2,以及HHVM)](https://juejin.im/post/5ab4bac9518825557b4caec6)([Albertao](https://github.com/Albertao) 翻译) +* [斐波那契数列中的偶数(Python vs. JavaScript)](https://juejin.im/post/5aaa61f8f265da237b21d258)([zephyrJS](https://github.com/zephyrJS) 翻译) +* [将项目迁移到 Python 3](https://juejin.im/post/5a9e3ff06fb9a028d2077434)([Starriers](https://github.com/Starriers) 翻译) +* [GraphQL API 设计最佳实践](https://juejin.im/entry/5aab36936fb9a028d7005a3f/detail)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [Python 是解决任何问题的完美工具](https://juejin.im/post/5aa74bf95188255568686ae0)([rydensun](https://github.com/rydensun) 翻译) +* [为 Python Web 应用编写 Dockerfiles](https://juejin.im/post/5aaf8038518825557e783285)([lsvih](https://github.com/lsvih) 翻译) +* [用 Python 做一个 H5 游戏机器人](https://juejin.im/post/5aa9e7645188257bf550c745)([lsvih](https://github.com/lsvih) 翻译) +* [Express.js 与 AWS Lambda  —  一场关于 serverless 的爱情故事](https://juejin.im/post/5aa128cdf265da239b410225)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [用户账户、授权和密码管理的 12 个最佳方法](https://juejin.im/post/5a9e4db151882555677e0dc1)([Wangalan30](https://github.com/Wangalan30) 翻译) +* [Elasticsearch Reference Getting Start](https://juejin.im/post/5aa0b13af265da238b7d92f7)([foxxnuaa](https://github.com/foxxnuaa) 翻译) +* [使用 Rust 开发一个简单的 Web 应用,第 2a 部分](https://juejin.im/post/5a81961cf265da4e7f359e86)([LeopPro](https://github.com/LeopPro) 翻译) +* [使用 Rust 开发一个简单的 Web 应用,第 2b 部分](https://juejin.im/post/5a8196716fb9a0635c0478d7)([LeopPro](https://github.com/LeopPro) 翻译) +* [使用 Rust 开发一个简单的 Web 应用,第 3 部分 —— 整合](https://juejin.im/post/5a8d6a436fb9a0635172803f)([LeopPro](https://github.com/LeopPro) 翻译) +* [使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析](https://juejin.im/post/5a8d6aad6fb9a0634514c6c6)([LeopPro](https://github.com/LeopPro) 翻译) +* [标准化的包布局](https://juejin.im/post/5a8cf9dc6fb9a063475f8c15)([steinliber](https://github.com/steinliber) 翻译) +* [为 Flask Web 应用配置 Nginx](https://juejin.im/post/5a795febf265da4e94499949)([lsvih](https://github.com/lsvih) 翻译) +* [为 Django Framework 贡献你的力量并没有想象中的那么难](https://juejin.im/post/5a77cd6e5188257a79247fe1)([JayZhaoBoy](https://github.com/JayZhaoBoy) 翻译) +* [8 个技巧让你在 2018 年构建更好的 Node.js 应用程序](https://juejin.im/post/5a617c436fb9a01c9e46074f)([PLDaily](https://github.com/PLDaily) 翻译) +* [状态管理的未来: 在 Apollo Client 中使用 apollo-link-state管理本地数据](https://juejin.im/post/5a728da26fb9a01cb74eb328)([yct21](https://github.com/yct21) 翻译) +* [使用 Rust 开发一个简单的 Web 应用之总结篇:还是先把 Rust 放一边吧](https://juejin.im/post/5a71cf15f265da3e4f0a7d0a)([mysterytony](https://github.com/mysterytony) 翻译) +* [使用 Rust 开发一个简单的 Web 应用,第 1 部分](https://juejin.im/post/5a673ba16fb9a01ca5609f35)([LeopPro](https://github.com/LeopPro) 翻译) +* [通过后台数据预获取技术实现性能提升](https://juejin.im/post/5a71a9c3f265da3e2f01459b)([NeoyeElf](https://github.com/NeoyeElf) 翻译) +* [利用双环 TDD 进行由外向内的开发](https://juejin.im/post/5a5dea0d6fb9a01cab28443c)([NeilLi1992](https://github.com/NeilLi1992) 翻译) +* [Node.js 最佳实践 —— 如何在 2018 年成为更好的 Node.js 开发者](https://juejin.im/post/5a52242e6fb9a01c914037f3)([NeilLi1992](https://github.com/NeilLi1992) 翻译) +* [如何用 TypeScript 玩转后端?](https://juejin.im/post/5a36837d6fb9a045167d4644)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [使用 Rust 来写原生 Node.js 模块](https://juejin.im/post/5a2b51bff265da4332277ee0)([LeopPro](https://github.com/LeopPro) 翻译) +* [使用 helmet 库来保护你的 Express 网站](https://juejin.im/post/5a24fd8f51882509e5438247)([lsvih](https://github.com/lsvih) 翻译) +* [Python 3.7 的新特性](https://juejin.im/post/5a127e60f265da430f31b45b)([winjeysong](https://github.com/winjeysong) 翻译) +* [HTTP/2 下网站资源打包的正确方法](https://juejin.im/post/59f74d20f265da431523326b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yct21](https://github.com/yct21) 翻译) +* [Go并发编程中的那些事](https://juejin.im/post/59ecb058f265da43346f10e5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([kobehaha](https://github.com/kobehaha) 翻译) +* [CSV 注入:被人低估的风险](https://juejin.im/post/59eca3fef265da430b7a63c8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mnikn](https://github.com/mnikn) 翻译) +* [你不知道的 Node](https://juejin.im/post/59cf06caf265da0665640008?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lampui](https://github.com/lampui) 翻译) +* [SQL 指引:如何写出更好的查询](https://juejin.im/post/59c1d402518825396f4f6321?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zyziyun](https://github.com/zyziyun) 翻译) +* [2017年日志生态系统概述](https://juejin.im/post/59b8e345f265da0660296161?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([TanNingMeng](https://github.com/TanNingMeng) 翻译) +* [Coursera 的 GraphQL 之路](https://juejin.im/post/59b8d1d36fb9a00a3f24c439?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [SQL 事务隔离实用指南](https://juejin.im/post/59b7ce03f265da0672281fcc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sigoden](https://github.com/sigoden) 翻译) +* [低成本将你的网站切换为 HTTPS](https://juejin.im/post/59b129365188253da63829ad?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [为什么 context.Value 重要,如何改进](https://juejin.im/post/59b20d6ff265da249517c14a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([tmpbook](https://github.com/tmpbook) 翻译) +* [搭建账户系统](https://juejin.im/post/59b2708b5188257e8a30842f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shawnchenxmu](https://github.com/shawnchenxmu) 翻译) +* [扩展 Node.js 应用](https://juejin.im/post/599eb2dbf265da246d6afb33?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mnikn](https://github.com/mnikn) 翻译) +* [在 Go 语言中增强 Cookie 的安全性](https://juejin.im/post/59aa7a4d6fb9a0249c007e16?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [关于 Node.js 的认证方面的教程(很可能)是有误的](https://juejin.im/post/599f955d51882511264e7f69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MuYunyun](https://github.com/MuYunyun) 翻译) +* [使用 Node.js 搭建一个 API 网关](https://juejin.im/post/5992769151882548b17f76a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MuYunyun](https://github.com/MuYunyun) 翻译) +* [REST API 已死,GraphQL 长存](https://juejin.im/post/5991667b518825485d28dfb1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sigoden](https://github.com/sigoden) 翻译) +* [将现有的 API 从 REST 迁移到 GraphQL](https://juejin.im/post/598eb22af265da3e26097835?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zaraguo](https://github.com/zaraguo) 翻译) +* [所有你需要知道的关于完全理解 Node.js 事件循环及其度量](https://juejin.im/post/5984816a518825265674c8f6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MuYunyun](https://github.com/MuYunyun) 翻译) +* [GraphQL vs. REST](https://juejin.im/post/59793f625188253ded721c70?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wilsonandusa](https://github.com/wilsonandusa) 翻译) +* [理解 Python 中的异步编程](https://juejin.im/entry/59704efc6fb9a06bbd6fabeb/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber) 翻译) +* [WAR 还是 JAR,你应该用哪种格式打包?](https://juejin.im/post/5966fb99f265da6c2211ac4d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([windmxf](https://github.com/windmxf) 翻译) +* [Node.js 子进程:你应该知道的一切](https://juejin.im/entry/595dc35b51882568d00a97ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([FrankXiong](https://github.com/FrankXiong) 翻译) +* [如何在无损的情况下让图片变的更小](https://juejin.im/post/5959fbe0f265da6c2518d740?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XatMassacrE](https://github.com/XatMassacrE) 翻译) +* [在 Reddit 中代码部署的演进](https://juejin.im/entry/594b7fd21b69e60062a4cb01/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber) 翻译) +* [REST 2.0 在此,它的名字叫 GraphQL](https://juejin.im/post/5947b45c128fe1006a505189?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mnikn](https://github.com/mnikn) 翻译) +* [用 Go 语言理解 Tensorflow](https://juejin.im/post/59420951128fe1006a1960f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [Node.js 流: 你需要知道的一切](https://juejin.im/post/5940a9c3128fe1006a0ab176?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([loveky](https://github.com/loveky) 翻译) +* [时间复杂度 O(log n) 意味着什么?](https://juejin.im/entry/593f56528d6d810058a355f4/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [使用 Gradle 做构建检查](https://juejin.im/entry/5937f0a48fd9c513c627114a/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jacksonke](https://github.com/jacksonke/) 翻译) +* [Django 基于 Postgres 的全文搜索](https://juejin.im/entry/593a069b61ff4b006c70ba82/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber/) 翻译) +* [理解 NodeJS 中基于事件驱动的架构](https://juejin.im/entry/5937f2cdac502e0068d1aeec/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD/) 翻译) +* [如何从一个业余爱好者成长成为专业开发者](https://juejin.im/entry/59361e1e570c35005b65464e/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zaraguo](https://github.com/zaraguo/) 翻译) +* [建立更好的代码审查制度](https://juejin.im/entry/5934bafb2f301e006b055f57/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bobmayuze](https://github.com/bobmayuze/) 翻译) +* [使用速率限制扩展你的 API](https://github.com/xitu/gold-miner/blob/master/TODO/rate-limiters.md?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([tanglie1993](https://github.com/tanglie1993/) 翻译) +* [真相就在代码中](https://juejin.im/post/59152d17da2f60005dd0ae77?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([loveky](https://github.com/loveky) 翻译) +* [nginScript 入门](https://github.com/xitu/gold-miner/blob/master/TODO/introduction-nginscript.md?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([1992chenlu](https://github.com/1992chenlu) 翻译) +* [我是如何找回 Reddit 密码的](https://juejin.im/entry/590aee94da2f60005328fb2d/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [Node.js 之战: 如何在生产环境中调试错误](https://juejin.im/post/59035d3644d904006919086b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mnikn](https://github.com/mnikn) 翻译) +* [我经常听到的 GraphQL 到底是什么?](https://juejin.im/post/58fd6d121b69e600589ec740/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [系统设计入门](https://github.com/xitu/system-design-primer/blob/master/README-zh-Hans.md) ([XatMassacrE](https://github.com/XatMassacrE) [L9m](https://github.com/L9m) [Airmacho](https://github.com/Airmacho) [xiaoyusilen](https://github.com/xiaoyusilen)([jifaxu](https://github.com/jifaxu) 翻译) +* [如何使用 HTTP Headers 来保护你的 Web 应用](https://juejin.im/post/58f5d3718d6d810057c18f75/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [解析 Go 中的函数调用](https://juejin.im/post/58f579b58d6d81006491c7c0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xiaoyusilen](https://github.com/xiaoyusilen) 翻译) +* [Go 函数调用 Redux](https://juejin.im/post/58f57be144d904006c09019c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xiaoyusilen](https://github.com/xiaoyusilen) 翻译) +* [关于在 Node.js 中引用模块,知道这些就够了](https://juejin.im/post/58eb3812da2f60005f0bae9b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) +* [模块化 vs. 微服务](https://juejin.im/post/58eb2627da2f60005f0b2d60/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xiaoyusilen](https://github.com/xiaoyusilen) 翻译) +* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([fghpdf](https://github.com/fghpdf) 翻译) +* [Pull request review 的十大错误](https://juejin.im/post/58ce3b3e61ff4b006c988f63/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [震惊!RxJava 5 个不为人知的小秘密](https://juejin.im/post/58cb833b8ac247218c2632e5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([skyar2009](https://github.com/skyar2009) 翻译) +* [跨站请求伪造已死!](https://juejin.im/post/58c669b6a22b9d0058b3c630?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XatMassacrE](https://github.com/XatMassacrE) 翻译) +* [Google 是如何构建 web 框架的](https://gold.xitu.io/entry/58bcdda4128fe1007e5b44db/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([fghpdf](https://github.com/fghpdf) 翻译) +* [这项浏览器调整使 Facebook 收到的网络请求减少了 60%](https://gold.xitu.io/entry/58b82f602f301e006c545b05/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([vuuihc](https://github.com/vuuihc) 翻译) +* [用 Python 实现每秒百万级请求](https://gold.xitu.io/entry/58b5b141570c350062f6cc01/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [Node.js 支持 ES6 模块的进展](http://gold.xitu.io/entry/58b393f08d6d8100586955fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([hikerpig](https://github.com/hikerpig) 翻译) +* [在线进行大规模的数据迁移](https://gold.xitu.io/entry/58b2b7268ac24728d5484e1b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber) 翻译) +* [用神经网络进行文本分类](https://gold.xitu.io/entry/58aa65ec2f301e006c32ee0c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/Kulbear) 翻译) +* [防守式编程的艺术](https://gold.xitu.io/entry/58980dbc1b69e6005997f069/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([GiggleAll](https://github.com/GiggleAll) 翻译) +* [为何我抵制使用缓存?](https://gold.xitu.io/entry/5884184f1b69e60058dc7fc6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [为什么我关闭了你的 PR (开源软件维护者笔记)](https://gold.xitu.io/entry/5870ed78da2f603a93d7e0f0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [在 Node.js 和 C++ 之间使用 Buffer 共享数据](https://gold.xitu.io/entry/586fbcefda2f600053df7787?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) +* [容器时代的分布式日志架构](https://gold.xitu.io/entry/5870f966a22b9d00588bafce?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [为 Async-Await 唱一曲赞歌](https://gold.xitu.io/entry/586eff068d6d810058794c94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xekri](https://github.com/xekri) 翻译) +* [GitHub 是如何阻止网络暴力的](https://gold.xitu.io/entry/58652f6661ff4b00583ba924?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wild-flame](https://github.com/wild-flame) 翻译) +* [在算法横行的时代,我们更需要人类来把关](https://gold.xitu.io/entry/5860fd7761ff4b0058248319?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) +* [高效的工程师一步一步来 —— 开发者影响力中的模式](https://gold.xitu.io/entry/5860f5dcb123db0065be0c45?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [简明 TensorFlow 教程 —第二部分:混合学习](https://gold.xitu.io/entry/5858ed4e1b69e6006cb12a7c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardhua](https://github.com/edvardHua) 翻译) +* [来写一个 Python 说明文档生成器吧](https://github.com/xitu/gold-miner/blob/master/TODO/python-introspection-with-the-inspect-module.md)([王子建](https://github.com/Romeo0906) 翻译) +* [TensorFlow —  第三部分: 所有的模型](https://gold.xitu.io/entry/58574d0c8d6d810065b4a0b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardhua](https://github.com/edvardHua) 翻译) +* [用 Python 建立一个简单的对象模型](https://gold.xitu.io/entry/5852965661ff4b0063a72977?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [用不可变的基础设施提高攻击者的攻击成本 ](https://gold.xitu.io/entry/5850e60f1b69e6006c773e07?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [用 Python 和 Numpy 实现音频数字指纹特征识别](https://gold.xitu.io/entry/5850e6ebac502e0067ce86a8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [简明 TensorFlow 教程 —— 第一部分:基础知识](https://gold.xitu.io/entry/5850c11cac502e0067cd7ea5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [代码复用的风险性](https://gold.xitu.io/entry/58491d3b8e450a006aae7b4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015](https://github.com/Gocy015) 翻译) +* [通过 Python 和 Pandas 调用 SQLite Databases](https://gold.xitu.io/entry/584790a70ce46300578c5977/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [Node & Express 入门指南](https://gold.xitu.io/entry/58468843a22b9d007aa70d38/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [从 Node.js 到 Golang 的迁徙之路](https://gold.xitu.io/entry/584780928e450a006c1b801c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [Python 数据可视化概览(涵盖 ggplot 和 Altair)](https://gold.xitu.io/entry/5842eded128fe10058a3cd7a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [Webhook 该做和不该做的: 我们在整合超过 100 个 API 中所学到的](http://gold.xitu.io/entry/5840df86a22b9d007a882f5d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber) 翻译) +* [研读 NodeJS 文档,我知道了这 19 件事](http://gold.xitu.io/entry/583ad71d128fe1006be5ddd6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jacksonke](https://github.com/jacksonke) 翻译) +* [带你声明 Python 中的动态属性](http://gold.xitu.io/entry/5832a16d2e958a0069e2c560?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [承载了巨大访问量的热门游戏 Pokémon GO 的后端架构是什么?](http://gold.xitu.io/entry/580aef59bf22ec005820a1dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [人人都应该用的 Python 开源库](http://gold.xitu.io/entry/57ca8aab165abd0068e5097a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Graning](https://github.com/Graning) 翻译) +* [详解 Python 模板引擎工作机制](http://gold.xitu.io/entry/57b4609f6be3ff006a0c8ad3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [这样做才能设计出更好的数据表](http://gold.xitu.io/entry/57af3cbc5bbb500062cb38a5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [利用 Shoryuken and SQS 快速处理 API 请求](http://gold.xitu.io/entry/57a14ac879bc44005497b433?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [为什么我们要用网页端组件去构建服务器?该怎么做?](http://gold.xitu.io/entry/579ad925c4c971005abfc7a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [字体加载策略全面指南](https://gold.xitu.io/entry/5790d1aa5bbb500063b8a747?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [基于多种服务的地理位置查询系统](https://gold.xitu.io/entry/578f80196be3ff006c0657a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([emmiter](https://github.com/emmiter/) 翻译) +* [探索 Python 3 加密技术](http://gold.xitu.io/entry/575fae92df0eea0062c5a1dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yushneng](https://github.com/rainyear) 翻译) +* [Java 不可变类的整洁之道](https://gold.xitu.io/entry/5774fe212e958a22d884a49c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([buccoji](https://github.com/buccoji) 翻译) +* [如何应用最新版的谷歌表格 API](https://gold.xitu.io/entry/5773acce0a2b58006a3fd7fe?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Goshin](https://github.com/Goshin) 翻译) +* [教程:使用 Passport.js 来做后台用户验证](http://gold.xitu.io/entry/57638f286be3ff006a171870?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [在生产环境中使用 Node.js 一年记](http://gold.xitu.io/entry/573d229ead5b950057645190?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [SSH 简化配置](http://gold.xitu.io/entry/5704cf8e71cfe4005dc76f18?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [Python3.5 协程原理](http://gold.xitu.io/entry/56ea295ed342d300546e1e22?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yushneng](https://github.com/rainyear) 翻译) +* [使用 Lua 完成 OAuth2 身份验证](http://gold.xitu.io/entry/56cd222199a6ce005a25b9ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([BOBO](https://github.com/CoderBOBO) 翻译) +* [Web 开发者的 HTTP/2 性能优化指南](http://gold.xitu.io/entry/56ce7d1a1532bc005372a7fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhongyi Tong](https://github.com/geeeeeeeeek) 翻译) diff --git a/design.md b/design.md index ef6f8c476a9..9f5083ee8fb 100644 --- a/design.md +++ b/design.md @@ -1,137 +1,164 @@ -* [响应式设计的基本原则](https://juejin.im/post/5d2ed18af265da1ba56b5374) ([Pingren](https://github.com/Pingren) 翻译) -* [设计任何图表的六项原则](https://juejin.im/post/5d27fca7f265da1b5e731f92) ([MarchYuanx](https://github.com/MarchYuanx) 翻译) -* [感受 4px 基线网格带来的便利](https://juejin.im/post/5d09e5ecf265da1b60290798) ([Mcskiller](https://github.com/Mcskiller) 翻译) -* [设计师如何成长为 Leader?](https://juejin.im/post/5d172fca6fb9a07eda032c6f) ([TiaossuP](https://github.com/TiaossuP) 翻译) -* [微设计系统 — 打破藩篱](https://juejin.im/post/5d0335395188255ee806a5da) ([Charlo-O](https://github.com/Charlo-O) 翻译) -* [项目世界 — 在数字设计中实现上帝模式](https://juejin.im/post/5ce63193518825332978ef65) ([Charlo-O](https://github.com/Charlo-O) 翻译) -* [声音设计与无声设计](https://juejin.im/post/5ce354bee51d4510727c7fd1) ([CLOXnu](https://github.com/CLOXnu) 翻译) -* [移动界面设计的 10 项启发式原则](https://juejin.im/post/5cbe6d3d5188250a80187a57) ([HydeSong](https://github.com/HydeSong) 翻译) -* [怎么简化你的设计](https://juejin.im/post/5cbd7ef55188250ab10aaf23) ([shixi-li](https://github.com/shixi-li) 翻译) -* [伟大设计与好设计之间区别是什么?这里告诉你真相](https://juejin.im/post/5cc15d1c5188252d6a6b1886) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [曝光!UX 行话大全](https://juejin.im/post/5c9f5c49e51d451b8a2af27b) ([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) -* [线框图变得不那么重要了 — 好事啊!](https://juejin.im/post/5c9269edf265da6116245ee9) ([hanxiansen](https://github.com/hanxiansen) 翻译) -* [四个理由让你使用灰度色调进行设计](https://juejin.im/post/5c961b1fe51d456a6743109e) ([xionglong58](https://github.com/xionglong58) 翻译) -* [设计不会拯救世界](https://juejin.im/post/5c966aed5188252d9b3768df) ([QiaoN](https://github.com/QiaoN) 翻译) -* [数字产品为人们授权的时代已来](https://juejin.im/post/5c7e50236fb9a04a0e2deffa) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [从著名数据数据可视化中我们可以学到什么](https://juejin.im/user/567e246a34f81a1d879e7a14) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [为什么 UX 和 UI 仍需要分离开](https://juejin.im/post/5c769c44f265da2d8c7ddb71) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [2019 年的 9 大设计趋势](https://juejin.im/post/5c7355e0f265da2d993d8ceb) ([shixi-li](https://github.com/shixi-li) 翻译) -* [UX 设计实践:如何设计可扫描的 Web 界面](https://juejin.im/post/5c34af846fb9a049a42f39d8) ([Ivocin](https://github.com/Ivocin) 翻译) -* [一份关于色彩无障碍性产品设计的指南](https://juejin.im/post/5c2c233d6fb9a049bd4266b7) ([Hopsken](https://github.com/Hopsken) 翻译) -* [快速原型设计的新手指南](https://juejin.im/user/585b9407da2f6000657a5c0c) ([rydensun](https://github.com/rydensun) 翻译) -* [我是如何在谷歌找到 UX 设计的工作的](https://juejin.im/post/5bea544ff265da6112048e3c) ([rydensun](https://github.com/rydensun) 翻译) -* [设计师的决策树](https://juejin.im/post/5befd61ee51d4557fe34e944) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [动效设计可以很简单](https://juejin.im/post/5bd11a176fb9a05d101423c0) ([rydensun](https://github.com/rydensun) 翻译) -* [白雪公主如何帮助 Airbnb 证明在设计中最重要的技能是讲故事](https://juejin.im/post/5bb22bc1f265da0a9e53200b) ([CoolRice](https://github.com/CoolRice) 翻译) -* [如何创建一个设计体系来赋能团队 —— 关注人,而非像素](https://juejin.im/post/5bac2a2fe51d450e942f4853) ([pmwangyang](https://github.com/pmwangyang) 翻译) -* [另外 5 种关于视觉和认知间差异的绘画练习](https://juejin.im/post/5baa5b45f265da0ab915cb7f) ([Ruixi](https://github.com/Ruixi) 翻译) -* [构建未来的设计生态系统](https://juejin.im/post/5b992be8f265da0aa3591346) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [设计 QA 在应用程序设计中的重要性](https://juejin.im/post/5b89421651882542da339868) ([lihanxiang](https://github.com/lihanxiang) 翻译) -* [为什么设计师讨厌政治](https://juejin.im/post/5b89599f51882542b03e6d5b) ([Starriers](https://github.com/Starriers) 翻译) -* [常见网页设计错误一览](https://juejin.im/post/5b7984265188254312414c1f) ([StellaBauhinia](https://github.com/StellaBauhinia) 翻译) -* [如何设计移动应用的搜索功能?](https://juejin.im/post/5b692ca251882562b924a6c7) ([xunge0613](https://github.com/xunge0613) 翻译) -* [在 Sketch 中使用一个设计体系创作:第一部分 [教程]](https://juejin.im/post/5b591a655188257bca290b24) ([pmwangyang](https://github.com/pmwangyang) 翻译) -* [在 Sketch 中使用一个设计体系创作: 第二部分 [教程]](https://juejin.im/post/5b5d2a456fb9a04fc80b8f4b) ([Zheng7426](https://github.com/Zheng7426) 翻译) -* [绘图技巧的快速入门之:6 个绘图练习,让你立即上手!](https://juejin.im/post/5b39823fe51d4558ca674cff) ([wzasd](https://github.com/wzasd) 翻译) -* [为什么 UX,UI,CX,IA,IxD 和其他类型的设计都是愚蠢的](https://juejin.im/post/5b3588f2e51d4558dd69a44c) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [创造华丽 UI 的 7 个规则(Part 2)](https://juejin.im/post/5b2a1554e51d4558cc35b3be) ([xujunjiejack](https://github.com/xujunjiejack) 翻译) -* [创造华丽 UI 的 7 个规则(Part 1)](https://juejin.im/post/5b1dcc7d5188257d7d71946a) ([wzasd](https://github.com/wzasd) 翻译) -* [用户体验中的稀缺性:成为常态的心理偏见](https://juejin.im/post/5aef0943518825672a02d2ca) ([Starriers](https://github.com/Starriers) 翻译) -* [细数那些我离不开的 Sketch 插件](https://juejin.im/post/5ae0623ef265da0b8d419aca) ([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) -* [设计师与工程师协作的 5 项准则](https://juejin.im/post/5ac9e56af265da23945fc201) ([Starriers](https://github.com/Starriers) 翻译) -* [产品设计的环状循环](https://juejin.im/post/5aa74b32f265da23a4047aef) ([rydensun](https://github.com/rydensun) 翻译) -* [设计研究的 9 条规则](https://juejin.im/post/5aa6958a5188255587233477) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [开始设计动画的九个步骤](https://juejin.im/post/5aa1f965f265da23994e1e1f) ([reid3290](https://github.com/reid3290) 翻译) -* [想帮助用户做决定?你的 APP 可以这样设计!](https://juejin.im/post/5a7194986fb9a01c9f5bbbb2) ([pthtc](https://github.com/pthtc) 翻译) -* [新兴技术领域中以用户为中心的设计的应用](https://juejin.im/post/5a682282f265da3e283a2cca) ([dongpeiguo](https://github.com/dongpeiguo) 翻译) -* [2018 设计趋势](https://juejin.im/post/5a695d88f265da3e58598968) ([pot-code](https://github.com/pot-code) 翻译) -* [如何紧跟未来的设计趋势:15 个让你永远不过时的资料](https://juejin.im/post/5a52d2226fb9a01c9525ebbe) ([kangkai124](https://github.com/kangkai124) 翻译) -* [网站设计综合指南](https://juejin.im/post/5a5abb97518825733f6df3d9) ([horizon13th](https://github.com/horizon13th) 翻译) -* [Face ID 对易用性意味着什么](https://juejin.im/post/5a41d01cf265da432c241943) ([winry01](https://github.com/winry01) 翻译) -* [iPhone X 网页设计](https://juejin.im/post/59e445816fb9a0450670ab82?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([HydeSong](https://github.com/HydeSong) 翻译) -* [如何为通知设计更好的用户体验](https://juejin.im/post/59f9b14f518825295f5d411f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([dongpeiguo](https://github.com/dongpeiguo) 翻译) -* [扁平化的 UI 元素既朴实又玄乎](https://juejin.im/post/59c0d3305188256bce40e884?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [「小键盘」难题:用户在手机上填写表单吗?](https://juejin.im/post/59c0e3835188256bcf2e1d22?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [Web 设计准则](https://juejin.im/post/59c9c6f66fb9a00a4d53eec7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xunge0613](https://github.com/xunge0613) 翻译) -* [优化 Facebook 新鲜事,使其为您提供更好的服务](https://juejin.im/post/59a52a276fb9a024927a43ce?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laiyun90](https://github.com/laiyun90) 翻译) -* [UI vs UX: 到底有什么差别](https://juejin.im/entry/59a62190f265da24843e713d/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [怎么写出完美的错误消息](https://juejin.im/post/599cf1596fb9a02481205803?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [通知是一种「暗模式」吗?](https://juejin.im/post/59ae63026fb9a024985f31b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [你的站点如你所想的移动友好吗?](https://juejin.im/post/59ae68c0f265da2489159ab4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laiyun90](https://github.com/laiyun90) 翻译) -* [别再使用图片轮播了](https://juejin.im/post/599cf1596fb9a02481205803?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shawnchenxmu](https://github.com/shawnchenxmu) 翻译) -* [虚拟现实是如何改变用户体验的:从原型到设备的设计](https://juejin.im/post/599683e0f265da24996015cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laiyun90](https://github.com/laiyun90) 翻译) -* [AI 能解决你的 UX 设计问题吗?](https://juejin.im/post/5992aa306fb9a03c445df727?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [设计作品集网站的真正角色是什么?](https://juejin.im/post/598959b65188253d2968eaab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([noturnot](https://github.com/noturnot) 翻译) -* [原子设计:如何设计组件系统](https://juejin.im/post/59780066f265da6c3433872f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([H2O-2](https://github.com/H2O-2) 翻译) -* [为企业应用设计更好的表格](https://juejin.im/post/5976ecb65188250c855facc2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laiyun90](https://github.com/laiyun90) 翻译) -* [UX 基于背后的合理化,而非设计](https://juejin.im/post/5971ce0d51882574623352ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([horizon13th](https://github.com/horizon13th) 翻译) -* [以排印为本,从内容出发](https://juejin.im/entry/5965c5b26fb9a06ba025074c/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [更好的表单设计: 每一页,一件事(实例研究)](https://juejin.im/post/5964c340f265da6c3f70c617?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([horizon13th](https://github.com/horizon13th) 翻译) -* [用动效创建的可用性:动效中的用户体验宣言](https://juejin.im/post/595c77a66fb9a06bcb7f92ff?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ruixi](https://github.com/ruixi) 翻译) -* [使登录页面变得正确](https://juejin.im/post/5951e7905188250d98489c6a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([LisaPeng](https://github.com/LisaPeng) 翻译) -* [可口可乐自由风格售卖亭界面用户体验的回顾和重新设计](https://juejin.im/post/594bd720f265da6c4c4fb134?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译) -* [为复杂产品制定设计规范](https://juejin.im/post/5944b8e55c497d006bdc261a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [是的,重新设计](https://juejin.im/post/5940e74fa0bb9f006b76a841?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([dongpeiguo](https://github.com/dongpeiguo) 翻译) -* [如何理智地构建复杂用户界面](https://juejin.im/post/5937a61f2f301e006b2879a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [设计准则:如何说服用户去使用新的功能](https://juejin.im/post/59279b650ce463006b029cbc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) -* [最激动人心的视觉系统其实是最枯燥乏味的](https://juejin.im/entry/59228e15a0bb9f005f60915a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [人人都是设计师,我们可以的。](https://juejin.im/post/59157cdf0ce4630069d79857?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译) -* [设计师装腔指南](https://juejin.im/post/5915880b570c35006932fac9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Changkun Ou](https://github.com/changkun) 翻译) -* [从形式到功能,设计思维的改变](https://juejin.im/post/58fedca744d9040069f720e4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [搜索结果页的最佳实践](https://juejin.im/post/58da37c761ff4b00607287a6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [某些2017年的 UX 趋势啊,扎心了](https://juejin.im/post/58cf5dc22f301e007e52fb2b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [像开发人员一样做设计](https://gold.xitu.io/entry/58b7ba6f8fd9c56d16be6bb0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [设计预期的用户体验](https://gold.xitu.io/entry/58b2d8e9570c3500696f53a5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jifaxu](https://github.com/jifaxu) 翻译) -* [优秀产品背后的设计原则](https://gold.xitu.io/entry/58b04c49570c35006960d764/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jifaxu](https://github.com/jifaxu) 翻译) -* [漂亮的字体组合的秘密](https://gold.xitu.io/entry/58a3b99aac502e0068b0e8fa/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [色彩如何影响 UX 和用户行为](https://gold.xitu.io/entry/58a1a44886b599006b47ccda/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [视觉系统中的按钮](https://gold.xitu.io/entry/58845fa2b123db7389d23bc1/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([funtrip](https://github.com/funtrip) 翻译) -* [每一个表单都渴望验证](https://gold.xitu.io/entry/58845fa2b123db7389d23bc1/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZiXYu](https://github.com/ZiXYu) 翻译) -* [创建一个移动应用的终极指导](https://gold.xitu.io/entry/587f05a48d6d810058e20795/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([PhxNirvana](https://github.com/phxnirvana) 翻译) -* [如何让用户发掘移动应用中的 “隐藏” 手势](https://gold.xitu.io/entry/587d72af2f301e00579ed0e3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015](https://github.com/Gocy015) 翻译) -* [如何为复杂应用设计表单](https://gold.xitu.io/entry/5877633b1b69e6006bd1efc3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([funtrip](https://github.com/funtrip) 翻译) -* [设计思考,不只是流行词而已](https://gold.xitu.io/entry/5873faf4da2f6035a7f4a025?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bobmayuze](https://github.com/bobmayuze) 翻译) -* [科学写作,为产品经理推荐的利器!](https://gold.xitu.io/entry/586b37e7ac502e12d62a3b5d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [使用强大的调查技巧了解用户的动机](https://gold.xitu.io/entry/585a3f9b1b69e6006cb93529/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [iOS: 自定义 Modal 视图](https://gold.xitu.io/entry/58576ca7128fe1006b7b35a3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) -* [如何用 Sketch 打造「前端框架」](https://gold.xitu.io/entry/5836ad4367f3560065f439dc/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [全新的 Uber App 与全新的设计](http://gold.xitu.io/entry/584770f80ce46300578b9b48?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([PhxNirvana](https://github.com/phxnirvana) 翻译) -* [移动端设计最佳实践](http://gold.xitu.io/entry/583bd69bac502e006ea8caaa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy](https://github.com/Gocy015) 翻译) -* [为用户体验设计绘制草图,你所需要知道的一切](http://gold.xitu.io/entry/580cd2c5a22b9d006382cba8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([funtrip](https://github.com/funtrip) 翻译) -* [奋起的 IBM 凭什么成为世界上最大最精致的设计公司?](http://gold.xitu.io/entry/57e8c99b8ac247005bd929a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [顾虑越少,设计越好](http://gold.xitu.io/entry/57df4d04a0bb9f0058a4429d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Siegen](https://github.com/siegeout) 翻译) -* [好的设计准则是如何塑造更强大的产品形态的](http://gold.xitu.io/entry/57db572ed203090069d2e201?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([rottenpen](https://github.com/rottenpen) 翻译) -* [用心设计的艺术](http://gold.xitu.io/entry/57d6bd1bd20309006a08e25e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [设计一个你自己不会去用的产品](http://gold.xitu.io/entry/57ce923c816dfa00541bf9a2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [视觉设计本地化的重要性](http://gold.xitu.io/entry/57ce9d4c7db2a200680f6fc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cbangchen](https://github.com/cbangchen) 翻译) -* [你的设计应该「所见即所得」](http://gold.xitu.io/entry/57c5978f128fe1005fdf4858?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [根据 OS 设计你的应用](http://gold.xitu.io/entry/57bebe962e958a006958e73b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/Kulbear) 翻译) -* [嘿,Logo,你应该是这个尺寸的!](http://gold.xitu.io/entry/57bb183279bc440063a6f290?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) -* [别再设计你的应用界面了,在用户体验上下点功夫吧](http://gold.xitu.io/entry/57b1e47ac4c97100548c964e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/Kulbear) 翻译) -* [移动开发中的极简设计](http://gold.xitu.io/entry/57abf8735bbb500062b1becb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardhua](https://github.com/edvardhua) 翻译) -* [设计,其实是一种产生共鸣的过程](http://gold.xitu.io/entry/57a41ffca341310063262054?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Rottenpen](https://github.com/Rottenpen) 翻译) -* [如何在应用内设计一份调查?](https://gold.xitu.io/entry/579ae2a85bbb500064c9233e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gran](https://github.com/graning) 翻译) -* [移动应用设计新趋势](http://gold.xitu.io/entry/5796ee065bbb500063ef3535?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shixinzhang](https://github.com/shixinzhang) 翻译) -* [移动开发中用 1x 视觉稿设计的好处](http://gold.xitu.io/entry/578840f9d342d30058a29968?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wildflame](https://github.com/wild-flame/) 翻译) -* [用户界面中的字体](http://gold.xitu.io/entry/57859bb9d342d300578b1ebf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [从产品设计到虚拟现实](https://gold.xitu.io/entry/5783aa752e958a0054dad3bc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [UI 的黑暗面!暗色背景的优势](https://gold.xitu.io/entry/577c9385a633bd005be7fe7a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yangzj1992](http://www.qcyoung.com/) 翻译) -* [如何在移动 APP 中设计输入框](http://gold.xitu.io/entry/5745af0a2e958a002db75980?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第三部分](https://gold.xitu.io/entry/576cc25f2e958a00571dfb5f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Hugo](https://github.com/xcc3641) 翻译) -* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第二部分](http://gold.xitu.io/entry/574eb491d342d300434cec1c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangzhaoqi](https://github.com/joddiy) 翻译) -* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第一部分](http://gold.xitu.io/entry/574d062b2e958a0069335d8e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Sausure](https://github.com/Sausure) 翻译) -* [我是如何为 Mac 应用 Flinto 设计 UI 图标的](http://gold.xitu.io/entry/57315d571ea4930064f6bd45?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([edvardHua](https://github.com/edvardHua) 翻译) -* [下拉菜单为何是一种不好的用户体验?](http://gold.xitu.io/entry/573154c249830c0061bdc180?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([邵辉Vista](https://github.com/shaohui10086) 翻译) -* [Sketch的过去现在和未来](http://gold.xitu.io/entry/5721e59771cfe40057521079?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lfkdsk](https://github.com/lfkdsk) 翻译) -* [为什么我们喜欢丑的、一团糟的界面以及你为什么也要这样](http://gold.xitu.io/entry/57172a4f2e958a0054a8ffcf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [写给设计师的字偶距调整指南](http://gold.xitu.io/entry/570e5530c4c971005496adc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [设计一款移动应用前你应该知道这些事情](http://gold.xitu.io/entry/57034d617db2a200592a5213?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Adam Shen](https://github.com/shenxn) 翻译) -* [11 个顶级设计师分享他们的职业建议](http://gold.xitu.io/entry/56ea5b03731956005d025af3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Adam Shen](https://github.com/shenxn) 翻译) -* [为什么有些设计初衷很好,结果却很糟糕](http://gold.xitu.io/entry/56e000421532bc005161b4af?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [Mastering Sketch 3](http://gold.xitu.io/entry/5659daf9ddb299ad38f9e446?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jabez128](https://github.com/jabez128) 翻译) -* [[译] 通过设计让学习变轻松 - Google 的 Primer 团队是如何做用户体验设计的](http://gold.xitu.io/entry/56cbbf9671cfe40054e91c02?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([s2dongman](https://github.com/s2dongman) 翻译) -* [关于 Sprite 动画简介](http://gold.xitu.io/entry/56d7e5207db2a2005122f2a2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aaaaaashu](https://github.com/Aaaaaashu?tab=repositories) 翻译) -* [Animated SVG vs GIF](http://gold.xitu.io/entry/56cb0c95efa631005c3a50f2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([rainyear](https://github.com/rainyear) 翻译) -* [探索 Stripe Dashboard 产品设计之道](http://gold.xitu.io/entry/56c7cad1d342d30054334db5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([CaesarPan](https://github.com/CaesarPan) 翻译) -* [苹果正在带坏整个设计圈](https://github.com/xitu/gold-miner/blob/master/TODO/how-apple.md)([crackhy](https://github.com/crackhy) 翻译) -* [Slack如此成功的秘诀](http://gold.xitu.io/entry/56cbd5427db2a20051a7dbb2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Boyce Chang](https://github.com/boycechang) 翻译) +* [你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [构建设计系统和组件库](https://juejin.cn/post/6924152501805678606)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [解构标志性的 Apple Watch Bubble UI](https://juejin.cn/post/6919630087843217416)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [黑暗主题 — 现代 UI 设计](https://juejin.cn/post/6901856999235911688)([zenblo](https://github.com/zenblo) 翻译) +* [颜色为何成为数据可视化的关键,怎样使用它?](https://juejin.im/post/6872238362233831432)([Amy-Designer](https://github.com/Amy-Designer) 翻译) +* [用户体验案例学习:重新设计 KoinStreet 主页](https://juejin.im/post/6869757477928304654)([Zhengjian-L](https://github.com/Zhengjian-L) 翻译) +* [寻找 2020 年最有意义的十大网页设计流行趋势](https://juejin.im/post/5ed74ee0e51d45788a6d686e)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [什么是无障碍?为什它对于用户体验很重要?](https://juejin.im/post/5ebf96a5f265da7b9754dd7d)([QinRoc](https://github.com/QinRoc) 翻译) +* [用户体验案例学习:Mood Talk ——  一个心理健康应用](https://juejin.im/post/5ebbb38ae51d454dca711099)([nia3y](https://github.com/nia3y) 翻译) +* [创建一个 Settings icon 的五种方法](https://juejin.im/post/5e9e845be51d454709221d1f)([cyz980908](https://github.com/cyz980908) 翻译) +* [眼动跟踪和移动世界的最佳用户体验实践](https://zhuanlan.zhihu.com/p/120424545)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [关于 icon 设计的 7 大准则](https://juejin.im/post/5e5dbd3e6fb9a07cd323dd2b)([cyz980908](https://github.com/cyz980908) 翻译) +* [图标万花筒](https://juejin.im/post/5e0ac4756fb9a048526aa26b)([Baddyo](https://github.com/Baddyo) 翻译) +* [设计的变革 —— 从用户体验到个人体验](https://juejin.im/post/5e00d1b4f265da33b636145a)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [简单的谬误](https://juejin.im/post/5eca7e8ee51d45784a354d1c)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [如何设计一款讨人喜欢的暗色主题](https://juejin.im/post/5dad4ef1f265da5bb86ad294)([cyz980908](https://github.com/cyz980908) 翻译) +* [当每个产品设计都是一种意见](https://juejin.im/post/5d5a77676fb9a06b1417e4b3)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [元设计师的崛起](https://juejin.im/post/5d4919e5f265da03a1484008)([Baddyo](https://github.com/Baddyo) 翻译) +* [在数据可视化中,我们曾经“画”下的那些错误](https://juejin.im/post/5cd39e1de51d453a3a0acb7b)([ccJia](https://github.com/ccJia) 翻译) +* [设计一个页面原则上应该指的是编写 HTML 和 CSS](https://juejin.im/post/5c6425d6e51d454ba22ba414)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [如何提升设计到开发的协作效率](https://juejin.im/post/5b83609de51d4538c210a957)([meterscao](https://github.com/meterscao) 翻译) +* [如何打造以人为本的移动游戏](https://juejin.im/post/5a61663b518825732f7ecd2a)([hanliuxin5](https://github.com/hanliuxin5) 翻译) +* [开发者须知:女性用户和手机游戏](https://juejin.im/post/5a4d96fd5188253865099818)([corresponding](https://github.com/corresponding) 翻译) +* [我是如何在谷歌做开发者的用户体验的](https://juejin.im/post/59a785d46fb9a02493222d77)([laiyun90](https://github.com/laiyun90) 翻译) +* [如果你的产品停止成长,你该怎么做?](https://juejin.im/post/5985935c518825261a2d222f)([funtrip](https://github.com/funtrip) 翻译) +* [针对失败者的体验设计](https://juejin.im/post/59013f6eda2f60005de40516)([ylq167](https://github.com/ylq167) 翻译) +* [细节是产品设计的重中之重](https://juejin.im/post/58ed96aaa22b9d00634732e9)([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) +* [响应式设计的基本原则](https://juejin.im/post/5d2ed18af265da1ba56b5374)([Pingren](https://github.com/Pingren) 翻译) +* [设计任何图表的六项原则](https://juejin.im/post/5d27fca7f265da1b5e731f92)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [感受 4px 基线网格带来的便利](https://juejin.im/post/5d09e5ecf265da1b60290798)([Mcskiller](https://github.com/Mcskiller) 翻译) +* [设计师如何成长为 Leader?](https://juejin.im/post/5d172fca6fb9a07eda032c6f)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [微设计系统 — 打破藩篱](https://juejin.im/post/5d0335395188255ee806a5da)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [项目世界 — 在数字设计中实现上帝模式](https://juejin.im/post/5ce63193518825332978ef65)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [声音设计与无声设计](https://juejin.im/post/5ce354bee51d4510727c7fd1)([CLOXnu](https://github.com/CLOXnu) 翻译) +* [移动界面设计的 10 项启发式原则](https://juejin.im/post/5cbe6d3d5188250a80187a57)([HydeSong](https://github.com/HydeSong) 翻译) +* [怎么简化你的设计](https://juejin.im/post/5cbd7ef55188250ab10aaf23)([shixi-li](https://github.com/shixi-li) 翻译) +* [伟大设计与好设计之间区别是什么?这里告诉你真相](https://juejin.im/post/5cc15d1c5188252d6a6b1886)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [曝光!UX 行话大全](https://juejin.im/post/5c9f5c49e51d451b8a2af27b)([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) +* [线框图变得不那么重要了 — 好事啊!](https://juejin.im/post/5c9269edf265da6116245ee9)([hanxiansen](https://github.com/hanxiansen) 翻译) +* [四个理由让你使用灰度色调进行设计](https://juejin.im/post/5c961b1fe51d456a6743109e)([xionglong58](https://github.com/xionglong58) 翻译) +* [设计不会拯救世界](https://juejin.im/post/5c966aed5188252d9b3768df)([QiaoN](https://github.com/QiaoN) 翻译) +* [数字产品为人们授权的时代已来](https://juejin.im/post/5c7e50236fb9a04a0e2deffa)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [从著名数据数据可视化中我们可以学到什么](https://juejin.im/user/567e246a34f81a1d879e7a14)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [为什么 UX 和 UI 仍需要分离开](https://juejin.im/post/5c769c44f265da2d8c7ddb71)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [2019 年的 9 大设计趋势](https://juejin.im/post/5c7355e0f265da2d993d8ceb)([shixi-li](https://github.com/shixi-li) 翻译) +* [UX 设计实践:如何设计可扫描的 Web 界面](https://juejin.im/post/5c34af846fb9a049a42f39d8)([Ivocin](https://github.com/Ivocin) 翻译) +* [一份关于色彩无障碍性产品设计的指南](https://juejin.im/post/5c2c233d6fb9a049bd4266b7)([Hopsken](https://github.com/Hopsken) 翻译) +* [快速原型设计的新手指南](https://juejin.im/user/585b9407da2f6000657a5c0c)([rydensun](https://github.com/rydensun) 翻译) +* [我是如何在谷歌找到 UX 设计的工作的](https://juejin.im/post/5bea544ff265da6112048e3c)([rydensun](https://github.com/rydensun) 翻译) +* [设计师的决策树](https://juejin.im/post/5befd61ee51d4557fe34e944)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [动效设计可以很简单](https://juejin.im/post/5bd11a176fb9a05d101423c0)([rydensun](https://github.com/rydensun) 翻译) +* [白雪公主如何帮助 Airbnb 证明在设计中最重要的技能是讲故事](https://juejin.im/post/5bb22bc1f265da0a9e53200b)([CoolRice](https://github.com/CoolRice) 翻译) +* [如何创建一个设计体系来赋能团队 —— 关注人,而非像素](https://juejin.im/post/5bac2a2fe51d450e942f4853)([pmwangyang](https://github.com/pmwangyang) 翻译) +* [另外 5 种关于视觉和认知间差异的绘画练习](https://juejin.im/post/5baa5b45f265da0ab915cb7f)([Ruixi](https://github.com/Ruixi) 翻译) +* [构建未来的设计生态系统](https://juejin.im/post/5b992be8f265da0aa3591346)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [设计 QA 在应用程序设计中的重要性](https://juejin.im/post/5b89421651882542da339868)([lihanxiang](https://github.com/lihanxiang) 翻译) +* [为什么设计师讨厌政治](https://juejin.im/post/5b89599f51882542b03e6d5b)([Starriers](https://github.com/Starriers) 翻译) +* [常见网页设计错误一览](https://juejin.im/post/5b7984265188254312414c1f)([StellaBauhinia](https://github.com/StellaBauhinia) 翻译) +* [如何设计移动应用的搜索功能?](https://juejin.im/post/5b692ca251882562b924a6c7)([xunge0613](https://github.com/xunge0613) 翻译) +* [在 Sketch 中使用一个设计体系创作:第一部分 [教程]](https://juejin.im/post/5b591a655188257bca290b24)([pmwangyang](https://github.com/pmwangyang) 翻译) +* [在 Sketch 中使用一个设计体系创作: 第二部分 [教程]](https://juejin.im/post/5b5d2a456fb9a04fc80b8f4b)([Zheng7426](https://github.com/Zheng7426) 翻译) +* [绘图技巧的快速入门之:6 个绘图练习,让你立即上手!](https://juejin.im/post/5b39823fe51d4558ca674cff)([wzasd](https://github.com/wzasd) 翻译) +* [为什么 UX,UI,CX,IA,IxD 和其他类型的设计都是愚蠢的](https://juejin.im/post/5b3588f2e51d4558dd69a44c)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [创造华丽 UI 的 7 个规则(Part 2)](https://juejin.im/post/5b2a1554e51d4558cc35b3be)([xujunjiejack](https://github.com/xujunjiejack) 翻译) +* [创造华丽 UI 的 7 个规则(Part 1)](https://juejin.im/post/5b1dcc7d5188257d7d71946a)([wzasd](https://github.com/wzasd) 翻译) +* [用户体验中的稀缺性:成为常态的心理偏见](https://juejin.im/post/5aef0943518825672a02d2ca)([Starriers](https://github.com/Starriers) 翻译) +* [细数那些我离不开的 Sketch 插件](https://juejin.im/post/5ae0623ef265da0b8d419aca)([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) +* [设计师与工程师协作的 5 项准则](https://juejin.im/post/5ac9e56af265da23945fc201)([Starriers](https://github.com/Starriers) 翻译) +* [产品设计的环状循环](https://juejin.im/post/5aa74b32f265da23a4047aef)([rydensun](https://github.com/rydensun) 翻译) +* [设计研究的 9 条规则](https://juejin.im/post/5aa6958a5188255587233477)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [开始设计动画的九个步骤](https://juejin.im/post/5aa1f965f265da23994e1e1f)([reid3290](https://github.com/reid3290) 翻译) +* [想帮助用户做决定?你的 APP 可以这样设计!](https://juejin.im/post/5a7194986fb9a01c9f5bbbb2)([pthtc](https://github.com/pthtc) 翻译) +* [新兴技术领域中以用户为中心的设计的应用](https://juejin.im/post/5a682282f265da3e283a2cca)([dongpeiguo](https://github.com/dongpeiguo) 翻译) +* [2018 设计趋势](https://juejin.im/post/5a695d88f265da3e58598968)([pot-code](https://github.com/pot-code) 翻译) +* [如何紧跟未来的设计趋势:15 个让你永远不过时的资料](https://juejin.im/post/5a52d2226fb9a01c9525ebbe)([kangkai124](https://github.com/kangkai124) 翻译) +* [网站设计综合指南](https://juejin.im/post/5a5abb97518825733f6df3d9)([horizon13th](https://github.com/horizon13th) 翻译) +* [Face ID 对易用性意味着什么](https://juejin.im/post/5a41d01cf265da432c241943)([winry01](https://github.com/winry01) 翻译) +* [iPhone X 网页设计](https://juejin.im/post/59e445816fb9a0450670ab82?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([HydeSong](https://github.com/HydeSong) 翻译) +* [如何为通知设计更好的用户体验](https://juejin.im/post/59f9b14f518825295f5d411f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([dongpeiguo](https://github.com/dongpeiguo) 翻译) +* [扁平化的 UI 元素既朴实又玄乎](https://juejin.im/post/59c0d3305188256bce40e884?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [「小键盘」难题:用户在手机上填写表单吗?](https://juejin.im/post/59c0e3835188256bcf2e1d22?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [Web 设计准则](https://juejin.im/post/59c9c6f66fb9a00a4d53eec7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xunge0613](https://github.com/xunge0613) 翻译) +* [优化 Facebook 新鲜事,使其为您提供更好的服务](https://juejin.im/post/59a52a276fb9a024927a43ce?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laiyun90](https://github.com/laiyun90) 翻译) +* [UI vs UX: 到底有什么差别](https://juejin.im/entry/59a62190f265da24843e713d/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [怎么写出完美的错误消息](https://juejin.im/post/599cf1596fb9a02481205803?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [通知是一种「暗模式」吗?](https://juejin.im/post/59ae63026fb9a024985f31b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [你的站点如你所想的移动友好吗?](https://juejin.im/post/59ae68c0f265da2489159ab4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laiyun90](https://github.com/laiyun90) 翻译) +* [别再使用图片轮播了](https://juejin.im/post/599cf1596fb9a02481205803?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shawnchenxmu](https://github.com/shawnchenxmu) 翻译) +* [虚拟现实是如何改变用户体验的:从原型到设备的设计](https://juejin.im/post/599683e0f265da24996015cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laiyun90](https://github.com/laiyun90) 翻译) +* [AI 能解决你的 UX 设计问题吗?](https://juejin.im/post/5992aa306fb9a03c445df727?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [设计作品集网站的真正角色是什么?](https://juejin.im/post/598959b65188253d2968eaab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([noturnot](https://github.com/noturnot) 翻译) +* [原子设计:如何设计组件系统](https://juejin.im/post/59780066f265da6c3433872f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([H2O-2](https://github.com/H2O-2) 翻译) +* [为企业应用设计更好的表格](https://juejin.im/post/5976ecb65188250c855facc2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laiyun90](https://github.com/laiyun90) 翻译) +* [UX 基于背后的合理化,而非设计](https://juejin.im/post/5971ce0d51882574623352ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([horizon13th](https://github.com/horizon13th) 翻译) +* [以排印为本,从内容出发](https://juejin.im/entry/5965c5b26fb9a06ba025074c/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [更好的表单设计: 每一页,一件事(实例研究)](https://juejin.im/post/5964c340f265da6c3f70c617?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([horizon13th](https://github.com/horizon13th) 翻译) +* [用动效创建的可用性:动效中的用户体验宣言](https://juejin.im/post/595c77a66fb9a06bcb7f92ff?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ruixi](https://github.com/ruixi) 翻译) +* [使登录页面变得正确](https://juejin.im/post/5951e7905188250d98489c6a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([LisaPeng](https://github.com/LisaPeng) 翻译) +* [可口可乐自由风格售卖亭界面用户体验的回顾和重新设计](https://juejin.im/post/594bd720f265da6c4c4fb134?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ylq167](https://github.com/ylq167) 翻译) +* [为复杂产品制定设计规范](https://juejin.im/post/5944b8e55c497d006bdc261a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [是的,重新设计](https://juejin.im/post/5940e74fa0bb9f006b76a841?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([dongpeiguo](https://github.com/dongpeiguo) 翻译) +* [如何理智地构建复杂用户界面](https://juejin.im/post/5937a61f2f301e006b2879a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [设计准则:如何说服用户去使用新的功能](https://juejin.im/post/59279b650ce463006b029cbc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) +* [最激动人心的视觉系统其实是最枯燥乏味的](https://juejin.im/entry/59228e15a0bb9f005f60915a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [人人都是设计师,我们可以的。](https://juejin.im/post/59157cdf0ce4630069d79857?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ylq167](https://github.com/ylq167) 翻译) +* [设计师装腔指南](https://juejin.im/post/5915880b570c35006932fac9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Changkun Ou](https://github.com/changkun) 翻译) +* [从形式到功能,设计思维的改变](https://juejin.im/post/58fedca744d9040069f720e4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [搜索结果页的最佳实践](https://juejin.im/post/58da37c761ff4b00607287a6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [某些2017年的 UX 趋势啊,扎心了](https://juejin.im/post/58cf5dc22f301e007e52fb2b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [像开发人员一样做设计](https://gold.xitu.io/entry/58b7ba6f8fd9c56d16be6bb0/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [设计预期的用户体验](https://gold.xitu.io/entry/58b2d8e9570c3500696f53a5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jifaxu](https://github.com/jifaxu) 翻译) +* [优秀产品背后的设计原则](https://gold.xitu.io/entry/58b04c49570c35006960d764/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jifaxu](https://github.com/jifaxu) 翻译) +* [漂亮的字体组合的秘密](https://gold.xitu.io/entry/58a3b99aac502e0068b0e8fa/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [色彩如何影响 UX 和用户行为](https://gold.xitu.io/entry/58a1a44886b599006b47ccda/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [视觉系统中的按钮](https://gold.xitu.io/entry/58845fa2b123db7389d23bc1/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([funtrip](https://github.com/funtrip) 翻译) +* [每一个表单都渴望验证](https://gold.xitu.io/entry/58845fa2b123db7389d23bc1/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZiXYu](https://github.com/ZiXYu) 翻译) +* [创建一个移动应用的终极指导](https://gold.xitu.io/entry/587f05a48d6d810058e20795/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([PhxNirvana](https://github.com/phxnirvana) 翻译) +* [如何让用户发掘移动应用中的 “隐藏” 手势](https://gold.xitu.io/entry/587d72af2f301e00579ed0e3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015](https://github.com/Gocy015) 翻译) +* [如何为复杂应用设计表单](https://gold.xitu.io/entry/5877633b1b69e6006bd1efc3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([funtrip](https://github.com/funtrip) 翻译) +* [设计思考,不只是流行词而已](https://gold.xitu.io/entry/5873faf4da2f6035a7f4a025?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bobmayuze](https://github.com/bobmayuze) 翻译) +* [科学写作,为产品经理推荐的利器!](https://gold.xitu.io/entry/586b37e7ac502e12d62a3b5d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [使用强大的调查技巧了解用户的动机](https://gold.xitu.io/entry/585a3f9b1b69e6006cb93529/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [iOS: 自定义 Modal 视图](https://gold.xitu.io/entry/58576ca7128fe1006b7b35a3/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) +* [如何用 Sketch 打造「前端框架」](https://gold.xitu.io/entry/5836ad4367f3560065f439dc/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [全新的 Uber App 与全新的设计](http://gold.xitu.io/entry/584770f80ce46300578b9b48?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([PhxNirvana](https://github.com/phxnirvana) 翻译) +* [移动端设计最佳实践](http://gold.xitu.io/entry/583bd69bac502e006ea8caaa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy](https://github.com/Gocy015) 翻译) +* [为用户体验设计绘制草图,你所需要知道的一切](http://gold.xitu.io/entry/580cd2c5a22b9d006382cba8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([funtrip](https://github.com/funtrip) 翻译) +* [奋起的 IBM 凭什么成为世界上最大最精致的设计公司?](http://gold.xitu.io/entry/57e8c99b8ac247005bd929a6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [顾虑越少,设计越好](http://gold.xitu.io/entry/57df4d04a0bb9f0058a4429d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Siegen](https://github.com/siegeout) 翻译) +* [好的设计准则是如何塑造更强大的产品形态的](http://gold.xitu.io/entry/57db572ed203090069d2e201?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([rottenpen](https://github.com/rottenpen) 翻译) +* [用心设计的艺术](http://gold.xitu.io/entry/57d6bd1bd20309006a08e25e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [设计一个你自己不会去用的产品](http://gold.xitu.io/entry/57ce923c816dfa00541bf9a2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [视觉设计本地化的重要性](http://gold.xitu.io/entry/57ce9d4c7db2a200680f6fc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cbangchen](https://github.com/cbangchen) 翻译) +* [你的设计应该「所见即所得」](http://gold.xitu.io/entry/57c5978f128fe1005fdf4858?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [根据 OS 设计你的应用](http://gold.xitu.io/entry/57bebe962e958a006958e73b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/Kulbear) 翻译) +* [嘿,Logo,你应该是这个尺寸的!](http://gold.xitu.io/entry/57bb183279bc440063a6f290?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) +* [别再设计你的应用界面了,在用户体验上下点功夫吧](http://gold.xitu.io/entry/57b1e47ac4c97100548c964e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/Kulbear) 翻译) +* [移动开发中的极简设计](http://gold.xitu.io/entry/57abf8735bbb500062b1becb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardhua](https://github.com/edvardhua) 翻译) +* [设计,其实是一种产生共鸣的过程](http://gold.xitu.io/entry/57a41ffca341310063262054?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Rottenpen](https://github.com/Rottenpen) 翻译) +* [如何在应用内设计一份调查?](https://gold.xitu.io/entry/579ae2a85bbb500064c9233e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gran](https://github.com/graning) 翻译) +* [移动应用设计新趋势](http://gold.xitu.io/entry/5796ee065bbb500063ef3535?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shixinzhang](https://github.com/shixinzhang) 翻译) +* [移动开发中用 1x 视觉稿设计的好处](http://gold.xitu.io/entry/578840f9d342d30058a29968?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wildflame](https://github.com/wild-flame/) 翻译) +* [用户界面中的字体](http://gold.xitu.io/entry/57859bb9d342d300578b1ebf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [从产品设计到虚拟现实](https://gold.xitu.io/entry/5783aa752e958a0054dad3bc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [UI 的黑暗面!暗色背景的优势](https://gold.xitu.io/entry/577c9385a633bd005be7fe7a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yangzj1992](http://www.qcyoung.com/) 翻译) +* [如何在移动 APP 中设计输入框](http://gold.xitu.io/entry/5745af0a2e958a002db75980?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第三部分](https://gold.xitu.io/entry/576cc25f2e958a00571dfb5f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Hugo](https://github.com/xcc3641) 翻译) +* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第二部分](http://gold.xitu.io/entry/574eb491d342d300434cec1c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangzhaoqi](https://github.com/joddiy) 翻译) +* [使用 Sketch 和 Pixate 构建 Material Design 原型 - 第一部分](http://gold.xitu.io/entry/574d062b2e958a0069335d8e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Sausure](https://github.com/Sausure) 翻译) +* [我是如何为 Mac 应用 Flinto 设计 UI 图标的](http://gold.xitu.io/entry/57315d571ea4930064f6bd45?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([edvardHua](https://github.com/edvardHua) 翻译) +* [下拉菜单为何是一种不好的用户体验?](http://gold.xitu.io/entry/573154c249830c0061bdc180?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([邵辉Vista](https://github.com/shaohui10086) 翻译) +* [Sketch的过去现在和未来](http://gold.xitu.io/entry/5721e59771cfe40057521079?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lfkdsk](https://github.com/lfkdsk) 翻译) +* [为什么我们喜欢丑的、一团糟的界面以及你为什么也要这样](http://gold.xitu.io/entry/57172a4f2e958a0054a8ffcf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [写给设计师的字偶距调整指南](http://gold.xitu.io/entry/570e5530c4c971005496adc4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [设计一款移动应用前你应该知道这些事情](http://gold.xitu.io/entry/57034d617db2a200592a5213?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Adam Shen](https://github.com/shenxn) 翻译) +* [11 个顶级设计师分享他们的职业建议](http://gold.xitu.io/entry/56ea5b03731956005d025af3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Adam Shen](https://github.com/shenxn) 翻译) +* [为什么有些设计初衷很好,结果却很糟糕](http://gold.xitu.io/entry/56e000421532bc005161b4af?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [Mastering Sketch 3](http://gold.xitu.io/entry/5659daf9ddb299ad38f9e446?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jabez128](https://github.com/jabez128) 翻译) +* [[译] 通过设计让学习变轻松 - Google 的 Primer 团队是如何做用户体验设计的](http://gold.xitu.io/entry/56cbbf9671cfe40054e91c02?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([s2dongman](https://github.com/s2dongman) 翻译) +* [关于 Sprite 动画简介](http://gold.xitu.io/entry/56d7e5207db2a2005122f2a2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aaaaaashu](https://github.com/Aaaaaashu?tab=repositories) 翻译) +* [Animated SVG vs GIF](http://gold.xitu.io/entry/56cb0c95efa631005c3a50f2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([rainyear](https://github.com/rainyear) 翻译) +* [探索 Stripe Dashboard 产品设计之道](http://gold.xitu.io/entry/56c7cad1d342d30054334db5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([CaesarPan](https://github.com/CaesarPan) 翻译) +* [苹果正在带坏整个设计圈](https://github.com/xitu/gold-miner/blob/master/TODO/how-apple.md)([crackhy](https://github.com/crackhy) 翻译) +* [Slack如此成功的秘诀](http://gold.xitu.io/entry/56cbd5427db2a20051a7dbb2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Boyce Chang](https://github.com/boycechang) 翻译) diff --git a/front-end.md b/front-end.md index 2fdaffdc637..4c171b10415 100644 --- a/front-end.md +++ b/front-end.md @@ -1,602 +1,827 @@ -* [通过阅读源码提高您的 JavaScript 水平](https://juejin.im/post/5d3c56c26fb9a07efd475414) ([MarchYuanx](https://github.com/MarchYuanx) 翻译) -* [作为初级开发人员,我没有学过的 7 个绝对真理](https://juejin.im/post/5d3d25dce51d457756536881) ([cyz980908](https://github.com/cyz980908) 翻译) -* [仅使用 HTML 和 CSS 创建多级嵌套弹出式导航菜单](https://juejin.im/post/5d3c2852f265da1bac405fae) ([yzw7489757](https://github.com/yzw7489757) 翻译) -* [CSS 开发必知必会的 16 个调试工具技巧](https://juejin.im/post/5d39d27cf265da1bc14b6f47) ([Usey95](https://github.com/Usey95) 翻译) -* [多网站项目的 CSS 架构](https://juejin.im/post/5d3a58df5188251ce02ff228) ([Baddyo](https://github.com/Baddyo) 翻译) -* [使用 Cypress 进行 React 应用的端到端测试](https://juejin.im/post/5d3702dcf265da1b961345d1) ([Stevens1995](https://github.com/Stevens1995) 翻译) -* [CSS 思维模式](https://juejin.im/post/5d295380f265da1bab29dc13) ([MarchYuanx](https://github.com/MarchYuanx) 翻译) -* [使用 SVG 和 Vue.Js 构建动态树图](https://juejin.im/post/5d2806fb518825121c0058d8) ([YueYongDev](https://github.com/YueYongDev) 翻译) -* [推广 PWA 安装的模式(移动端)](https://juejin.im/post/5d2746f1f265da1b7638cd1f) ([xutaogit](https://github.com/xutaogit) 翻译) -* [Web 流式文字排版的现状](https://juejin.im/post/5d267d9de51d45773d4686ab) ([Jenniferyingni](https://github.com/Jenniferyingni) 翻译) -* [自托管你的静态资源](https://juejin.im/post/5d258a77f265da1bca5202dc) ([twang1727](https://github.com/twang1727) 翻译) -* [微前端:未来前端开发的新趋势 — 第四部分](https://juejin.im/post/5d23394ae51d45778f076db0) ([Usey95](https://github.com/Usey95) 翻译) -* [微前端:未来前端开发的新趋势 — 第三部分](https://juejin.im/post/5d2755c4e51d45105e021360) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [微前端:未来前端开发的新趋势 — 第二部分](https://juejin.im/post/5d1a91c7e51d45775f516ab9) ([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) -* [微前端:未来前端开发的新趋势 — 第一部分](https://juejin.im/post/5d0e367b6fb9a07ebf4b781a) ([Jenniferyingni](https://github.com/Jenniferyingni) 翻译) -* [理解 React 中的高阶组件](https://juejin.im/post/5d1037966fb9a07ee4636de3) ([ZavierTang](https://github.com/ZavierTang) 翻译) -* [JavaScript 简明代码 — 最佳实践](https://juejin.im/post/5d07abcc6fb9a07eda031858) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [4 个 CSS 调色滤镜](https://juejin.im/post/5d039c36f265da1b60290096) ([iceytea](https://github.com/iceytea) 翻译) -* [TypeScript 3.0: unknown 类型](https://juejin.im/post/5d04ac745188250a8b1fd203) ([shixi-li](https://github.com/shixi-li) 翻译) -* [在 npm 上启用现在 JavaScript](https://juejin.im/post/5d15d64be51d4510a5033603) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [npm 的经济风云 —— 上半部分](https://juejin.im/post/5d146225e51d4556db694a4b) ([Baddyo](https://github.com/Baddyo) 翻译) -* [JavaScript 中 JSON.stringify 的帕累托法则手册](https://juejin.im/post/5d11d8d4f265da1baf7cfa13) ([Jerry-FD](https://github.com/Jerry-FD) 翻译) -* [JavaScript 线性代数:使用 ThreeJS 制作线性变换动画](https://juejin.im/post/5d05dba86fb9a07ece67ce76) ([lsvih](https://github.com/lsvih) 翻译) -* [线性代数:矩阵基本运算](https://juejin.im/post/5d107b00f265da1b67211a21) ([lsvih](https://github.com/lsvih) 翻译) -* [为什么我们要切换到 gRPC](https://juejin.im/post/5cff855c518825612f412526) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [JavaScript 线性代数:向量](https://juejin.im/post/5cf61bf8e51d45775653674e) ([lsvih](https://github.com/lsvih) 翻译) -* [JavaScript 线性代数:线性变换与矩阵](https://juejin.im/post/5cfdc1fb518825361d02aa41) ([lsvih](https://github.com/lsvih) 翻译) -* [8 个有用的 JavaScript 技巧](https://juejin.im/post/5cff97276fb9a07ea420749f) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [将第三方动画库集成到项目中 —— 第 1 部分](https://juejin.im/post/5d037b655188252af2012702) ([TUARAN](https://github.com/TUARAN) 翻译) -* [揭秘变量提升](https://juejin.im/post/5d026b71518825710d2b1f63) ([Usey95](https://github.com/Usey95) 翻译) -* [ECMAScript 类 - 定义私有属性](https://juejin.im/post/5d006e406fb9a07ed22465de) ([ZavierTang](https://github.com/ZavierTang) 翻译) -* [支持 JavaScript 三元运算符](https://juejin.im/post/5cfb1d85f265da1b8f1ab359) ([ZavierTang](https://github.com/ZavierTang) 翻译) -* [如何用 React Hooks 打造一个不到 100 行代码的异步表单校验库](https://juejin.im/post/5cf4e2c2f265da1b80202f83) ([Jerry-FD](https://github.com/Jerry-FD) 翻译) -* [13 种用于 DOM 操作的 JavaScript 方法](https://juejin.im/post/5cf65369f265da1bc94edad8) ([fireairforce](https://github.com/fireairforce) 翻译) -* [深入理解图片和框架的原生懒加载功能](https://juejin.im/post/5cfb1e36e51d45554877a597) ([Baddyo](https://github.com/Baddyo) 翻译) -* [用 React 制作线性代数教程示例:网格与箭头](https://juejin.im/post/5cefbc37f265da1bd260d129) ([lsvih](https://github.com/lsvih) 翻译) -* [通过一些例子深入了解 JavaScript 的 Async 和 Await](https://juejin.im/post/5cec8a475188255816489878) ([xionglong58](https://github.com/xionglong58) 翻译) -* [如何在 Google Play 应用商店中发布 PWA](https://juejin.im/post/5cefe63a6fb9a07ef3764dbe) ([Baddyo](https://github.com/Baddyo) 翻译) -* [Redux vs. React 的 Context API](https://juejin.im/post/5cee43ad518825526b294a32) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [什么是 `this`?JavaScript 对象的内部工作原理](https://juejin.im/post/5cedfdbd5188252fbc37f920) ([fireairforce](https://github.com/fireairforce) 翻译) -* [在项目中集成第三方动画库 —— 第二部分](https://juejin.im/post/5ce973a75188257ac625162b) ([Baddyo](https://github.com/Baddyo) 翻译) -* [用 React 的钩子函数和调试工具提升应用性能](https://juejin.im/post/5ce974d76fb9a07f0420250e) ([Baddyo](https://github.com/Baddyo) 翻译) -* [从原型图到成品:步步深入 CSS 布局](https://juejin.im/post/5cebb52651882530be7b16a4) ([Baddyo](https://github.com/Baddyo) 翻译) -* [如何用 CSS Animations 实现图片滑动出文字](https://juejin.im/post/5ce8c9c26fb9a07ed0648d26) ([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) -* [理解 WebView](https://juejin.im/post/5ce76ee4f265da1b8d15f700) ([CoolRice](https://github.com/CoolRice) 翻译) -* [为什么 HTML 中复选框样式难写 — 本文给你答案](https://juejin.im/post/5ce65dd36fb9a07ef06f6cd2) ([jilanlan](https://github.com/jilanlan) 翻译) -* [Elixir、Phoenix、Absinthe、GraphQL、React 和 Apollo:一次近乎疯狂的深度实践 —— 第二部分](https://juejin.im/post/5ce4dae36fb9a07ed524755d) ([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) -* [在 Google Apps 脚本中使用 ES6 和 npm 模块](https://juejin.im/post/5ce350c3e51d4510727c7fd0) ([xingqiwu55555](https://github.com/xingqiwu55555) 翻译) -* [Web 使用 CSS Shapes 的艺术设计](https://juejin.im/post/5cdba21051882568841f0f47) ([xujiujiu](https://github.com/xujiujiu) 翻译) -* [理解 Vue.js 中的 Mixins](https://juejin.im/post/5cdeac5851882525f52cf662) ([Reaper622](https://github.com/Reaper622) 翻译) -* [现代 JavaScript 开发中的设计模式](https://juejin.im/post/5cd62b9d6fb9a032321999ec) ([HydeSong](https://github.com/HydeSong) 翻译) -* [完美的 Javascript 单元测试](https://juejin.im/post/5cd3ce3a6fb9a032484d7f73) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [Javascript Array.push 要比 Array.concat 快 945 倍!🤯🤔](https://juejin.im/post/5cd67fb9f265da037129bb64) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [Elixir、Phoenix、Absinthe、GraphQL、React 和 Apollo:一次近乎疯狂的深度实践 — 第一部分](https://juejin.im/post/5cce99d3518825405a198e52) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [ES6:理解参数默认值的实现细节](https://juejin.im/post/5cd0eab95188251b984d8abe) ([Chorer](https://github.com/Chorer) 翻译) -* [使用 React 和 ImmutableJS 构建一个拖放布局构建器](https://juejin.im/post/5cccfa56f265da034c7038f3) ([fireairforce](https://github.com/fireairforce) 翻译) -* [使用 closest() 函数获取正确的 DOM 元素](https://juejin.im/post/5cc811796fb9a0321c45e5e0) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [你认为“figure”怎么用?](https://juejin.im/post/5cc5ad456fb9a032233532df) ([HydeSong](https://github.com/HydeSong) 翻译) -* [我多希望在我学习 React.js 之前就已经知晓这些小窍门](https://juejin.im/post/5cc53af6f265da038e54b2e6) ([xionglong58](https://github.com/xionglong58) 翻译) -* [图片懒加载](https://juejin.im/post/5cc183436fb9a032363936c3) ([nanjingboy](https://github.com/nanjingboy) 翻译) -* [创意运用 Console API!](https://juejin.im/post/5cc1517e5188252e7a0247dd) ([wznonstop](https://github.com/wznonstop) 翻译) -* [构建世界上最快的会议网站](https://juejin.im/post/5cbdafce6fb9a031fe3bc5db) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [如何让你的 CSS Grid 布局有良好可读性](https://juejin.im/post/5cc156a2f265da034e7e9139) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [2019 前端工具调研](https://juejin.im/post/5cb800fce51d456e4514f550) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [对 React 组件进行单元测试](https://juejin.im/post/5cb9c62a6fb9a0688d2e4689) ([xionglong58](https://github.com/xionglong58) 翻译) -* [使用 Shadow DOM 封装样式和结构](https://juejin.im/post/5cb3f5b95188251add7f11bc) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [你需要知道的 CSS 中所有 hyphenation 的使用](https://juejin.im/post/5cb2968df265da039f0f02d2) ([Augustwuli](https://github.com/Augustwuli) 翻译) -* [图解 Map、Reduce 和 Filter 数组方法](https://juejin.im/post/5caf030d6fb9a068736d2d7c) ([FrankXiong](https://github.com/FrankXiong) 翻译) -* [Web Components 的高级工具](https://juejin.im/post/5caef9f25188251b2b20b20b) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [使用网格布局实现响应式图片](https://juejin.im/post/5ca0ad80f265da30920059ae) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [写给大家看的 Cache-Control 指令配置](https://juejin.im/post/5c9d92506fb9a070f5067b3d) ([sunui](https://github.com/sunui) 翻译) -* [从没有人告诉过我的 CSS 小知识](https://juejin.im/post/5ca2fa5551882543db10d489) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [React 中的调度](https://juejin.im/post/5ca347306fb9a05e4c0e69e5) ([Xuyuey](https://github.com/Xuyuey) 翻译) -* [编写可以复用的 HTML 模板](https://juejin.im/post/5ca5b858e51d4524a918560f) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [2019 React Redux 完全指南](https://juejin.im/post/5cac8ccd6fb9a068530111c7) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [从 0 创建自定义元素](https://juejin.im/post/5cb2b5465188257abd66c354) ([yzw7489757](https://github.com/yzw7489757) 翻译) -* [如何使用 Phaser 3 和 TypeScript 在浏览器中构建一个简单的游戏](https://juejin.im/post/5c91b77ee51d4574b27c9219) ([iceytea](https://github.com/iceytea) 翻译) -* [深入 React Hook 系统的原理](https://juejin.im/post/5c99a75af265da60ef635898) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Vue.js 逐渐集成 第三方 JavaScript](https://juejin.im/post/5c8e5a776fb9a070d013ef71) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [监测与调试 Vue.js 的响应式系统:计算属性树(Computed Tree)](https://juejin.im/post/5c9ca62e5188251d80672b0d) ([SHERlocked93](https://github.com/SHERlocked93) 翻译) -* [JavaScript 中为什么会有 Symbols 类型?](https://juejin.im/post/5c9b11e8518825529a0c78c9) ([xionglong58](https://github.com/xionglong58) 翻译) -* [了解“多态”JSON 数据的性能问题](https://juejin.im/post/5c9982d16fb9a071061f09ce) ([shixi-li](https://github.com/shixi-li) 翻译) -* [TypeScript 和 Babel:美丽的结合](https://juejin.im/post/5c8f4dcb5188252db02e404c) ([zsky](https://github.com/zsky) 翻译) -* [Javascript 中的最长关键字序列长什么样子?](https://juejin.im/post/5c8efaf951882545e85c20e2) ([xionglong58](https://github.com/xionglong58) 翻译) -* [我是怎么最终玩转了 Vue 的作用域插槽](https://juejin.im/post/5c8856e6e51d456b30397f31) ([shixi-li](https://github.com/shixi-li) 翻译) -* [正在消失的小型网站](https://juejin.im/post/5c81de696fb9a049e702e6ac) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [避免那些可恶的 "cannot read property of undefined" 错误](https://juejin.im/post/5c810170e51d450a453fb48e) ([Xcco](https://github.com/Xcco) 翻译) -* [JSX 的替代方案](https://juejin.im/post/5c807f73e51d453ba723d88d) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [选择 Grid 还是 Flex?](https://juejin.im/post/5c7ce781e51d4514913c5bc4) ([Reaper622](https://github.com/Reaper622) 翻译) -* [Javascript - Generator-Yield/Next 和 Async-Await](https://juejin.im/post/5c7ca6d95188256ec63f289c) ([iceytea](https://github.com/iceytea) 翻译) -* [TSLint in 2019](https://juejin.im/post/5c7c0451e51d4569951518fe) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [在 JSX 代码中可以加入 console.log 吗?](https://juejin.im/post/5c7b1a146fb9a049c8502caf) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [网速敏感的视频延迟加载方案](https://juejin.im/post/5c7b84356fb9a049ab0e5630) ([SHERlocked93](https://github.com/SHERlocked93) 翻译) -* [浏览器中 CSS 支持指南](https://juejin.im/post/5c87a9006fb9a049e4138c7e) ([huimingwu](https://github.com/huimingwu) 翻译) -* [为什么我用 JavaScript 来编写 CSS](https://juejin.im/post/5c8878b7f265da2deb6ae6f2) ([Ivocin](https://github.com/Ivocin) 翻译) -* [Hooks 对 Vue 而言意味着什么](https://juejin.im/post/5c7784d5f265da2de713629c) ([Ivocin](https://github.com/Ivocin) 翻译) -* [如何学习 CSS](https://juejin.im/post/5c74daaaf265da2d9d1cb774) ([Mcskiller](https://github.com/Mcskiller) 翻译) -* [已经 2019 年了,我依然赤手空拳制作网站](https://juejin.im/post/5c74ad81f265da2da00ebaf6) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [模块化系统中的 event.stopPropagation ()](https://juejin.im/post/5c74a8bef265da2d881b331f) ([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) -* [HTML 一直是我们编译的目标 — 我们可以解决好它吗?](https://juejin.im/post/5c6ec3fc6fb9a049b07df54c) ([CoderMing](https://github.com/CoderMing) 翻译) -* [2019 前端性能优化年度总结 — 第一部分](https://juejin.im/post/5c4418006fb9a049c043545e) ([Hopsken](https://github.com/Hopsken) 翻译) -* [2019 前端性能优化年度总结 — 第二部分](https://juejin.im/post/5c47232b6fb9a049f8199ee2) ([KarthusLorin](https://github.com/KarthusLorin) 翻译) -* [2019 前端性能优化年度总结 — 第三部分](https://juejin.im/post/5c5ccbefe51d457f95354a46) ([Starriers](https://github.com/Starriers) 翻译) -* [2019 前端性能优化年度总结 — 第四部分](https://juejin.im/post/5c56345951882524b77b9f20) ([Ivocin](https://github.com/Ivocin) 翻译) -* [2019 前端性能优化年度总结 — 第五部分](https://juejin.im/post/5c60ed6cf265da2dd4274724) ([wznonstop](https://github.com/wznonstop) 翻译) -* [2019 前端性能优化年度总结 — 第六部分](https://juejin.im/post/5c6167f6f265da2ddf7866ec) ([CoolRice](https://github.com/CoolRice) 翻译) -* [Vue.js  —  注意事项和技巧](https://juejin.im/post/5c5c28cf518825627d37060a) ([xingqiwu55555](https://github.com/xingqiwu55555) 翻译) -* [5 个可以立刻在你的 Ionic App 中用上的动画包](https://juejin.im/post/5c517544f265da613b702848) ([lsvih](https://github.com/lsvih) 翻译) -* [为什么我不再使用 export default 来导出模块](https://juejin.im/post/5c4acd646fb9a049b5072f0e) ([KarthusLorin](https://github.com/KarthusLorin) 翻译) -* [使用 Recompose 来构建高阶组件](https://juejin.im/post/5c484a43e51d452ec621b6a9) ([SHERlocked93](https://github.com/SHERlocked93) 翻译) -* [使用 Proxy 来观测 Javascript 中的类](https://juejin.im/post/5c484b76e51d45522b4f5f7d) ([SHERlocked93](https://github.com/SHERlocked93) 翻译) -* [Rust 2018 已经发布...但它是到底什么呢?](https://juejin.im/post/5c47f714e51d4551b7481c8c) ([CoolRice](https://github.com/CoolRice) 翻译) -* [一文带你看完 2018 年浏览器之争的最新进展](https://juejin.im/post/5c45a392f265da61483be57c) ([HumesFork](https://github.com/HumesFork) 翻译) -* [💅 styled-components 背后的魔力](https://juejin.im/post/5c6d3a32e51d451804732248) ([WangLeto](https://github.com/WangLeto) 翻译) -* [资助 ESLint 的未来](https://juejin.im/post/5c6cc48551882562654ac2c0) ([EdmondWang](https://github.com/EdmondWang) 翻译) -* [Web 开发者需要了解的基础色彩理论](https://juejin.im/post/5c6caee26fb9a049df24a4df) ([lsvih](https://github.com/lsvih) 翻译) -* [X 为啥不是 hook?](https://juejin.im/post/5c6ca856f265da2dce1f3af9) ([Jerry-FD](https://github.com/Jerry-FD) 翻译) -* [关于 Yarn 和 npm 你所需要知道的一切](https://juejin.im/post/5c64e06ce51d457fce014370) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [谷歌迈出了消除 URL 的第一步](https://juejin.im/post/5c643cb7e51d450dfc6eec1e) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [使用智能 CSS 基于用户滚动位置应用样式](https://juejin.im/post/5c67817fe51d45082e13300c) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [设计一个页面原则上应该指的是编写 HTML 和 CSS](https://juejin.im/post/5c6425d6e51d454ba22ba414) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [如何利用 Webpack4 为你的 React.js 开发提速](https://juejin.im/post/5c669f14e51d457f093b1767) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [Vue Router 实战手册](https://juejin.im/post/5c62ab05f265da2da83555a0) ([xutaogit](https://github.com/xutaogit) 翻译) -* [十件你不知道的关于 WebPageTest.org 的事](https://juejin.im/post/5c679531f265da2dc45367ab) ([lsvih](https://github.com/lsvih) 翻译) -* [2019 CSS 新属性“连字符”初探](https://juejin.im/post/5c612cfee51d4501515c8edf) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [Webpack 4 的故事以及如何用正确的方式去最终配置它【更新版】](https://juejin.im/post/5c612ba351882562ea721b39) ([iceytea](https://github.com/iceytea) 翻译) -* [我们采用 GraphQL 技术的经验:营销技术活动](https://juejin.im/post/5c4522566fb9a049d2365cd6) ([xutaogit](https://github.com/xutaogit) 翻译) -* [通过垃圾回收机制理解 JavaScript 内存管理](https://juejin.im/post/5c4409fbf265da616f703d5a) ([wuzhengyan2015](https://github.com/wuzhengyan2015) 翻译) -* [新愿景: 未来的程序应用平台](https://juejin.im/post/5c2cce475188256a272ac4d6) ([skychenbo](https://github.com/skychenbo) 翻译) -* [2018 前端全面回顾](https://juejin.im/post/5c3eba70e51d4542253fd489) ([Ivocin](https://github.com/Ivocin) 翻译) -* [Lenses:可组合函数式编程的 Getter 和 Setter](https://juejin.im/post/5c3d35f8f265da611e4de068) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [2019 年值得学习的顶级 JavaScript 框架与主题](https://juejin.im/post/5c3cbb91e51d4550932771ce) ([ElizurHz](https://github.com/ElizurHz) 翻译) -* [CSS Shapes 简介](https://juejin.im/post/5c3740efe51d455211594993) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [理解异步 JavaScript](https://juejin.im/post/5c304097e51d45520c3b14cd) ([H246802](https://github.com/H246802) 翻译) -* [使用 Stripe, Vue.js 和 Flask 接受付款](https://juejin.im/post/5c3bed42f265da615064aacb) ([Mcskiller](https://github.com/Mcskiller) 翻译) -* [渐进增强的含义及意义](https://juejin.im/post/5c2f42556fb9a049f57148ca) ([RicardoCao-Biker](https://github.com/RicardoCao-Biker) 翻译) -* [Transducers: JavaScript 中高效的数据处理 pipeline](https://juejin.im/post/5c337b50f265da61746501bf) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [为什么我放弃了 React 而转向 Vue](https://juejin.im/post/5c2c27096fb9a049f66c3672) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [创建并发布一个小而美的 npm 包](https://juejin.im/post/5c26c1b65188252dcb312ad6) ([calpa](https://github.com/calpa) 翻译) -* [2019 年你应该要知道的 11 个 React UI 组件库](https://juejin.im/post/5c260f13e51d45473a5c07a4) ([ElizurHz](https://github.com/ElizurHz) 翻译) -* [5 款工具助力 React 快速开发](https://juejin.im/post/5c242e3f51882573d90678ad) ([Ivocin](https://github.com/Ivocin) 翻译) -* [React 路由和 React 组件的爱恨情仇](https://juejin.im/post/5c2217abe51d4570f1453cad) ([Augustwuli](https://github.com/Augustwuli) 翻译) -* [误解 ES6 模块,升级 Babel 的一个解决方案(泪奔)](https://juejin.im/post/5c223f4ce51d452626296b5d) ([Starriers](https://github.com/Starriers) 翻译) -* [继承 JavaScript 类中的静态属性](https://juejin.im/post/5c2217fc6fb9a049b348039d) ([Augustwuli](https://github.com/Augustwuli) 翻译) -* [用 Flask 和 Vue.js 开发一个单页面应用](https://juejin.im/post/5c1f7289f265da612e28a214) ([Mcskiller](https://github.com/Mcskiller) 翻译) -* [用 React 和 Node.js 实现受保护的路由和权限验证](https://juejin.im/post/5c1cdaaa6fb9a049aa6f0f8b) ([ElizurHz](https://github.com/ElizurHz) 翻译) -* [理解 React Render Props 和 HOC](https://juejin.im/post/5c1f8ded6fb9a049b506ce94) ([wuzhengyan2015](https://github.com/wuzhengyan2015) 翻译) -* [被污染的 npm 包:event-stream](https://juejin.im/post/5c1b02dcf265da6166246c25) ([CoderMing](https://github.com/CoderMing) 翻译) -* [用 Shadow DOM v1 和 Custom Elements v1 实现一个原生 Web Component](https://juejin.im/post/5c1a401b6fb9a049c042fa07) ([newraina](https://github.com/newraina) 翻译) -* [柯里化与函数组合](https://juejin.im/post/5c1a0d516fb9a049d05daee9) ([CoolRice](https://github.com/CoolRice) 翻译) -* [被遗忘的面向对象编程史(软件编写)(第十六部分)](https://juejin.im/post/5c19d249f265da61776be9b9) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [使用 GRAPHQL 构建项目的回顾](https://juejin.im/post/5c18ba5bf265da61715e44ed) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [怎么做:React Native 网页应用,一场开心的挣扎](https://juejin.im/post/5c13219d6fb9a049e82b65c3) ([weibinzhu](https://github.com/weibinzhu) 翻译) -* [使用 Capacitor 和 Vue.js 构建移动应用](https://juejin.im/post/5c0f0a9e518825428c5704d8) ([nanjingboy](https://github.com/nanjingboy) 翻译) -* [程序构建系列教程简介](https://juejin.im/post/5c0dd214518825444758453a) ([xutaogit](https://github.com/xutaogit) 翻译) -* [函数式编程:抽象与组合](https://juejin.im/post/5bfb989be51d45033627989a) ([Xekin-FE](https://github.com/Xekin-FE) 翻译) -* [你不知道的 console 命令](https://juejin.im/post/5bf64218e51d45194266acb7) ([Pomelo1213](https://github.com/Pomelo1213) 翻译) -* [理解 JavaScript 中的 undefined](https://juejin.im/post/5bf57e8ef265da612c5d8439) ([yanyixin](https://github.com/yanyixin) 翻译) -* [Javascript: call(), apply() 和 bind()](https://juejin.im/post/5bee3adef265da614c4c612e) ([YueYongDev](https://github.com/YueYongDev) 翻译) -* [关于 Angular 的变化检测,你需要知道的一切](https://juejin.im/post/5bf405f851882530d44b400a) ([tian-li](https://github.com/tian-li) 翻译) -* [我们是怎样把 Carousell 的移动 Web 体验搞快了 3 倍的?](https://juejin.im/post/5bee858ae51d45710c6a5500) ([noahziheng](https://github.com/noahziheng) 翻译) -* [React 是如何区分 Class 和 Function 的?](https://juejin.im/post/5c088c4ce51d451d8b7bd8de) ([tonghuashuo](https://github.com/tonghuashuo) 翻译) -* [写给 React 开发者的自定义元素指南](https://juejin.im/post/5c0873a8e51d451de96890dc) ([CoolRice](https://github.com/CoolRice) 翻译) -* [Netflix 的 Web 性能案例研究](https://juejin.im/post/5bf0c5d56fb9a049ec6aa902) ([CoolRice](https://github.com/CoolRice) 翻译) -* [揭开 React Hooks 的神秘面纱:数组解构融成魔法](https://juejin.im/post/5bebd1bbe51d4561ce39a23b) ([Xekin-FE](https://github.com/Xekin-FE) 翻译) -* [理解 React 钩子(Hooks)](https://juejin.im/post/5be98a87f265da616e4bf8a4) ([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) -* [Hook 介绍 — React 系列教程 Part 1](https://juejin.im/post/5be3e56ff265da613572117f) ([xutaogit](https://github.com/xutaogit) 翻译) -* [GitHub Actions 介绍,了解一下?](https://juejin.im/post/5be191736fb9a049de6cd463) ([CoolRice](https://github.com/CoolRice) 翻译) -* [Google 工程师提升网页性能的新策略:空闲到紧急](https://juejin.im/post/5bdec712e51d4505525b0fba) ([Ivocin](https://github.com/Ivocin) 翻译) -* [深入理解 React 高阶组件](https://juejin.im/entry/5bdd226cf265da616f6f6cce) ([CoderMing](https://github.com/CoderMing) 翻译) -* [如何停止使用 console.log() 并开始使用浏览器调试代码](https://juejin.im/post/5bd7cde4f265da0a96251de3) ([Augustwuli](https://github.com/Augustwuli) 翻译) -* [通过 Lighthouse 了解 JavaScript 性能](https://juejin.im/post/5bd5cfcbe51d456d4453572e) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [源代码映射(Source Map)简介](https://juejin.im/post/5bd65e1ae51d457aa071feaa) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [你需要知道的所有 Flexbox 排列方式](https://juejin.im/post/5bc728f2f265da0aef4e3f6d) ([CoderMing](https://github.com/CoderMing) 翻译) -* [从 2010 到 2018,你不知道的关于网页滚动和用户注意力的变化](https://juejin.im/post/5bcf0a38f265da0afb33834d) ([Ivocin](https://github.com/Ivocin) 翻译) -* [使用 JavaScript 和网络信息 API 实现自适应服务](https://juejin.im/post/5bc73482e51d450ea3639c7c) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [以面试官的角度来看 React 工作面试](https://juejin.im/post/5bca74cfe51d450e9163351b) ([CoolRice](https://github.com/CoolRice) 翻译) -* [开启性能预算](https://juejin.im/post/5bd40d3151882529642b24c8) ([xutaogit](https://github.com/xutaogit) 翻译) -* [现代浏览器内部揭秘(第四部分)](https://juejin.im/post/5bc95247e51d450e40072e49) ([ThomasWhyne](https://github.com/ThomasWhyne) 翻译) -* [Immer 下的不可突变数据和 React 的 setState](https://juejin.im/post/5bc06798e51d453eb93daa80) ([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) -* [使 WebAssembly 更快:Firefox 的新流式和分层编译器](https://juejin.im/post/5bc70955e51d450e98754dad) ([xutaogit](https://github.com/xutaogit) 翻译) -* [为数字优先新闻编辑室开发文本编辑器](https://juejin.im/post/5bc2f8a86fb9a05d151ccba8) ([diliburong](https://github.com/diliburong) 翻译) -* [现代浏览器内部揭秘(第二部分)](https://juejin.im/post/5bc293cf6fb9a05ce95c8468) ([CoolRice](https://github.com/CoolRice) 翻译) -* [现代浏览器内部揭秘(第三部分)](https://juejin.im/post/5bc29d56e51d450e9e4466cc) ([ssshooter](https://github.com/ssshooter) 翻译) -* [五个小技巧让你写出更好的 JavaScript 条件语句](https://juejin.im/post/5bb9e3085188255c352d7326) ([Hopsken](https://github.com/Hopsken) 翻译) -* [我在阅读 MDN 时发现的 3 个 Input 元素属性](https://juejin.im/post/5bbc6f035188255c5d56b160) ([ssshooter](https://github.com/ssshooter) 翻译) -* [当你创建 Flexbox 布局时,都发生了什么](https://juejin.im/post/5bb9740de51d450e782647ed) ([linxuesia](https://github.com/linxuesia) 翻译) -* [如何使用 JavaScript ES6 有条件地构造对象](https://juejin.im/post/5bb47db76fb9a05d071953ea) ([ssshooter](https://github.com/ssshooter) 翻译) -* [什么是模块化 CSS?](https://juejin.im/post/5bb6c5195188255c9e02e6f3) ([ssshooter](https://github.com/ssshooter) 翻译) -* [以申请大学流程来解释 JavaScript 的 filter](https://juejin.im/post/5b9f09685188255c5e66d60c) ([calpa](https://github.com/calpa) 翻译) -* [探索 SMACSS:可扩展的模块化 CSS 框架](https://juejin.im/post/5ba234c85188255c38535a47) ([Park-ma](https://github.com/Park-ma) 翻译) -* [this 到底指向什么 — 理解 JavaScript 中的 this、call、apply 和 bind](https://juejin.im/post/5b9f176b6fb9a05d3827d03f) ([CoolRice](https://github.com/CoolRice) 翻译) -* [理解 JavaScript 中的执行上下文和执行栈](https://juejin.im/post/5ba32171f265da0ab719a6d7) ([CoolRice](https://github.com/CoolRice) 翻译) -* [React Profiler 介绍](https://juejin.im/post/5ba0f8e4f265da0ab915bcf2) ([CoderMing](https://github.com/CoderMing) 翻译) -* [./dogs.html 和 /dogs.html 间有什么区别?](https://juejin.im/post/5ba7a5dfe51d450e4a1bc136) ([shery](https://github.com/shery) 翻译) -* [现代浏览器内部揭秘(第一部分)](https://juejin.im/post/5b9b0932e51d450e9059c16a) ([Colafornia](https://github.com/Colafornia) 翻译) -* [JAVASCRIPT 日期权威指南](https://juejin.im/post/5b9b4b7bf265da0af6099ed8) ([CoderMing](https://github.com/CoderMing) 翻译) -* [用 API 请求制作赏心悦目的 UX](https://juejin.im/post/5b992d13e51d450e894de541) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [如何使用原生 JavaScript 构建简单的 Chrome 扩展程序](https://juejin.im/post/5b98a58b6fb9a05cec4d92e0) ([shery](https://github.com/shery) 翻译) -* [CSS 变量和 JavaScript 让应用支持动态主题 🎨](https://juejin.im/post/5b9528de6fb9a05cf3710e00) ([CoolRice](https://github.com/CoolRice) 翻译) -* [JavaScript 2018 中即将迎来的新功能:异步生成器及更好的正则表达式](https://juejin.im/post/5b95be51f265da0adc18ac08) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [在 JavaScript 中 为什么你应当使用 map 和 filter 来替代 forEach](https://juejin.im/post/5b95c4fe5188255c402ae6fb) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [函数式 JavaScript 编程的简短介绍](https://juejin.im/post/5b8f97135188255c4a70f999) ([Zheng7426](https://github.com/Zheng7426) 翻译) -* [简单的响应式现代 css 网格布局](https://juejin.im/post/5b8b4ddef265da436d7e594d) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [使用原生 JavaScript 构建状态管理系统](https://juejin.im/post/5b763528e51d45559e3a5b64) ([shery](https://github.com/shery) 翻译) -* [布局的下一次革新会是怎样的](https://juejin.im/post/5b85586ce51d4538c77a9cc1) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [如何使用纯函数式 JavaScript 处理脏副作用](https://juejin.im/post/5b82bdb351882542e241ed32) ([Gavin-Gong](https://github.com/Gavin-Gong) 翻译) -* [2018 年七个通过脑电图分析实现“读心术”的 Javascript 库](https://juejin.im/post/5b7f63e651882542c20f22f0) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [一行 JavaScript 代码竟然让 FT.com 网站慢了十倍](https://juejin.im/post/5b7bb6dfe51d4538bf55aa5f) ([IridescentMia](https://github.com/IridescentMia) 翻译) -* [SpaceAce 了解一下,一个新的前端状态管理库](https://juejin.im/post/5b7653c96fb9a009c72cb7af) ([noahziheng](https://github.com/noahziheng) 翻译) -* [2018 来谈谈 Web 组件](https://juejin.im/post/5b780a98e51d4538980bf5cf) ([weberpan](https://github.com/weberpan) 翻译) -* [如何提升设计到开发的协作效率](https://juejin.im/post/5b83609de51d4538c210a957) ([meterscao](https://github.com/meterscao) 翻译) -* [优化 MP4 视频以获得更快的流传输速度](https://juejin.im/post/5b72bed8e51d45661e00f693) ([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) -* [如何向带有插槽的 React 组件传递多个 Children](https://juejin.im/post/5b72935a6fb9a009724b3e4e) ([Zheng7426](https://github.com/Zheng7426) 翻译) -* [用 React 和 Vue 创建了两个完全相同的应用后,发现了这些差异](https://juejin.im/post/5b63f50a5188253128337110) ([jonjia](https://github.com/jonjia) 翻译) -* [让我们一起解决“this”难题  —  第二部分](https://juejin.im/post/5b6915cce51d4519962f0ca7) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [让我们一起解决“this”难题 — 第一部分](https://juejin.im/post/5b680d8b518825196730a00f) ([doctype233](https://github.com/doctype233) 翻译) -* [设计 React 组件 API](https://juejin.im/post/5b545f0b6fb9a04fc93748ba) ([](https://github.com/) 翻译) -* [关于 React Motion 的简要介绍](https://juejin.im/post/5b48061551882519790c77f3) ([doctype233](https://github.com/doctype233) 翻译) -* [无头渲染组件](https://juejin.im/post/5b5e919f51882519d3467f41) ([](https://github.com/) 翻译) -* [用 30 分钟建立一个网站的方式来学习 Bootstrap 4](https://juejin.im/post/5b5eb7b2e51d451989055d9d) ([Zheng7426](https://github.com/Zheng7426) 翻译) -* [使用 Web Beacon API 记录活动](https://juejin.im/post/5b694b5de51d4519700fa56a) ([elliott-zhao](https://github.com/elliott-zhao) 翻译) -* [ECMAScript 修饰器微指南](https://juejin.im/post/5b543d8af265da0f4a4e711f) ([jonjia](https://github.com/jonjia) 翻译) -* [由 CSS 网格系统的创造者们所讲述的故事](https://juejin.im/post/5b503d9ef265da0f504a518e) ([Tivcrmn](https://github.com/Tivcrmn) 翻译) -* [Javascript(ES6)Generator 入门](https://juejin.im/post/5b4c22aa6fb9a04faf479be1) ([ssshooter](https://github.com/ssshooter) 翻译) -* [论 Rust 和 WebAssembly 对源码地址索引的极限优化](https://juejin.im/post/5b51948a5188251ac771c064) ([D-kylin](https://github.com/D-kylin) 翻译) -* [单元素组件模式简介](https://juejin.im/post/5b445d79e51d4519596b5f87) ([jonjia](https://github.com/jonjia) 翻译) -* [React 实现条件渲染的多种方式和性能考量](https://juejin.im/post/5b3e34905188251b1f223ad3) ([IveHD](https://github.com/IveHD) 翻译) -* [2018 年,如何选择最好的静态站点生成器](https://juejin.im/post/5b47079bf265da0faa3655be) ([ssshooter](https://github.com/ssshooter) 翻译) -* [将项目迁移到 Yarn 然后又迁回到 npm](https://juejin.im/post/5b3b5735f265da0f894b443d) ([zhongdeming428](https://github.com/zhongdeming428) 翻译) -* [或许你并不需要 Rust 和 WASM 来提升 JS 的执行效率 — 第二部分](https://juejin.im/post/5b357c20f265da595f0d3f91) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [怎样使用简单的三角函数来创建更好的加载动画](https://juejin.im/post/5b33055f518825748871c590) ([zhongdeming428](https://github.com/zhongdeming428) 翻译) -* [WOFF文件格式 1.0](https://github.com/xitu/gold-miner/blob/master/TODO1/recommendation-woff-2012-12-13.md) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [Vue.js 还是 React?你会选择哪一个?为什么?](https://juejin.im/post/5b25b3a16fb9a00e70686180) ([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) -* [或许你并不需要 Rust 和 WASM 来提升 JS 的执行效率 — 第一部分](https://juejin.im/post/5b24cf7e51882574c2652f61) ([shery15](https://github.com/shery15) 翻译) -* [从零开始,在 Redux 中构建时间旅行式调试](https://juejin.im/post/5b24c0bce51d4558ba1a5584) ([weberpan](https://github.com/weberpan) 翻译) -* [为何前端开发如此不稳定](https://juejin.im/post/5b1f2f1ae51d4506894983ae) ([Colafornia](https://github.com/Colafornia) 翻译) -* [前端开发框架实战对比(2018年更新)](https://juejin.im/post/5b20a5996fb9a01e6b2c21ec) ([geniusq1981](https://github.com/geniusq1981) 翻译) -* [我们距离 Babel 7.0 发布很近了。这里是所有我们一直在做的很酷的事情。](https://juejin.im/post/5b174f3e518825139b18e1f0) ([xueshuai](https://github.com/xueshuai) 翻译) -* [新的 CSS 特性正在改变网页设计](https://juejin.im/post/5b0cae8c6fb9a009de14c833) ([sophiayang1997](https://github.com/sophiayang1997) 翻译) -* [一个简单的 ES6 Promises 指南](https://juejin.im/post/5b0eb3b1f265da08f31e770a) ([sophiayang1997](https://github.com/sophiayang1997) 翻译) -* [JavaScript 是如何工作的:Service Worker 的生命周期与使用场景](https://juejin.im/post/5b14c1d86fb9a01e700ff2f2) ([talisk](https://github.com/talisk) 翻译) -* [使用 styled-components 的 React 服务器端渲染极简指南](https://juejin.im/post/5b0f9a4c51882515791502d0) ([elliott-zhao](https://github.com/elliott-zhao) 翻译) -* [什么是 JavaScript 生成器?如何使用生成器?](https://juejin.im/post/5b14faf2f265da6e4d5af3b9) ([lsvih](https://github.com/lsvih) 翻译) -* [为什么 VueX 是前端与 API 之间的完美接口](https://juejin.im/post/5b14d1bd6fb9a01e4508bfc1) ([zhmhhu](https://github.com/zhmhhu) 翻译) -* [Font-size:一个出乎意料复杂的 CSS 属性](https://juejin.im/post/5b1292355188251377116617) ([zephyrJS](https://github.com/zephyrJS) 翻译) -* [JavaScript 是如何工作的:深入网络层 + 如何优化性能和安全](https://juejin.im/post/5b02ae48518825429d1f9aff) ([Hopsken](https://github.com/Hopsken) 翻译) -* [JavaScript 是如何工作的:对比 WebAssembly + 为什么在某些场景下它比 JavaScript 更合适](https://juejin.im/post/5b0526e751882507c36d0167) ([stormluke](https://github.com/stormluke) 翻译) -* [怎样更好地使用 Vue:我在新工作中遇到的一些问题清单](https://juejin.im/post/5b0a36366fb9a07a9c04aca2) ([sophiayang1997](https://github.com/sophiayang1997) 翻译) -* [如何在 5 分钟之内写出一个不错的 loading 界面](https://juejin.im/post/5af54bbb518825426d2d2e63) ([whuzxq](https://github.com/whuzxq) 翻译) -* [使用 Puppeteer 和 Jest 测试你的 React 应用](https://juejin.im/post/5af90988518825426a1fcc2e) ([jonjia](https://github.com/jonjia) 翻译) -* [这就是为什么我们需要在 React 的类组件中为事件处理程序绑定 this](https://juejin.im/post/5afa6e2f6fb9a07aa2137f51) ([whuzxq](https://github.com/whuzxq) 翻译) -* [JavaScript 是如何工作的:CSS 和 JS 动画背后的原理 + 如何优化性能](https://juejin.im/post/5afaea6b6fb9a07aa34a6a74) ([NoName4Me](https://github.com/NoName4Me) 翻译) -* [⚛ React 状态管理工具博物馆](https://juejin.im/post/5afd18cf6fb9a07acb3d13ac) ([jonjia](https://github.com/jonjia) 翻译) -* [可用但最不常见的 HTML5 标签](https://juejin.im/post/5b0026e8f265da0b8c253c2a) ([lsvih](https://github.com/lsvih) 翻译) -* [JavaScript 是如何工作的:Web 推送通知的机制](https://juejin.im/post/5b002766518825429d1f90bc) ([Starriers](https://github.com/Starriers) 翻译) -* [漫画深入浅出 ES 模块](https://juejin.im/post/5aea6ae7f265da0ba4699e0a) ([stormluke](https://github.com/stormluke) 翻译) -* [JavaScript 是如何运作的:用 MutationObserver 追踪 DOM 的变化](https://juejin.im/post/5aee720df265da0b8f627173) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [深入浅出 JavaScript 关键词 — this](https://juejin.im/post/5aefe76e6fb9a07abc29d4a1) ([weberpan](https://github.com/weberpan) 翻译) -* [设计大型 JavaScript 应用程序](https://juejin.im/post/5aedd93b51882567244ddfc0) ([shery15](https://github.com/shery15) 翻译) -* [如何写出更好的 React 代码](https://juejin.im/post/5ae975d26fb9a07aa92588b7) ([jonjia](https://github.com/jonjia) 翻译) -* [使用 React, Redux, and SVG 开发游戏 - 第3部分](https://juejin.im/post/5af2a4d06fb9a07aa114302b) ([xueshuai](https://github.com/xueshuai) 翻译) -* [那些好玩却没有被 ECMAScript 2017 采纳的提案](https://juejin.im/post/5ae920fd51882567127852e7) ([Colafornia](https://github.com/Colafornia) 翻译) -* [Web 应用的未来:Heroku vs Docker](https://juejin.im/post/5ae7dae5518825670f7ba367) ([Hopsken](https://github.com/Hopsken) 翻译) -* [互联汽车是什么以及如何开发用于它的应用?](https://juejin.im/post/5ad419cb6fb9a028d9379e57) ([jonjia](https://github.com/jonjia) 翻译) -* [React 中的 Immutability:可变对象并没有什么问题](https://juejin.im/post/5ad807b36fb9a045d639ad18) ([jonjia](https://github.com/jonjia) 翻译) -* [如何调试前端:优化网络资源](https://juejin.im/post/5ade828751882567137dd2da) ([stormluke](https://github.com/stormluke) 翻译) -* [优化 WEBPACK 以更快地构建 REACT](https://juejin.im/post/5ae003d86fb9a07a9e4ce25d) ([Starriers](https://github.com/Starriers) 翻译) -* [深入浅出 SVG](https://juejin.im/post/5ad84f296fb9a045e8011be1) ([Starriers](https://github.com/Starriers) 翻译) -* [[1] + [2] - [3] === 9!? 类型转换深入研究](https://juejin.im/post/5ad5af7251882555894a5054) ([sunhaokk](https://github.com/sunhaokk) 翻译) -* [使用 React、Redux 和 SVG 开发游戏 - Part 2](https://juejin.im/post/5ad373fef265da2395316f27) ([zephyrJS](https://github.com/zephyrJS) 翻译) -* [JavaScript 是如何工作的:渲染引擎和性能优化技巧](https://juejin.im/post/5ad5986bf265da23994f06ab) ([stormluke](https://github.com/stormluke) 翻译) -* [React 的内联函数和性能](https://juejin.im/post/5ac20b5ff265da23945fa6bd) ([wznonstop](https://github.com/wznonstop) 翻译) -* [Redux-Saga 为你打 call:管理你的异步 action (上)](https://juejin.im/post/5ac1cb9d6fb9a028cf32a046) ([jonjia](https://github.com/jonjia) 翻译) -* [JavaScript 单元测试框架:Jasmine, Mocha, AVA, Tape 和 Jest 的比较](https://juejin.im/post/5acc721a6fb9a028b77b23c9) ([ClarenceC](https://github.com/ClarenceC) 翻译) -* [写给前端开发者的 GraphQL 指南](https://juejin.im/post/5ac09072518825558c479215) ([ellcyyang](https://github.com/ellcyyang) 翻译) -* [提高 10 倍性能:优化静态网站](https://juejin.im/post/5ac9e430f265da2392369ec0) ([Starriers](https://github.com/Starriers) 翻译) -* [React & Redux 顶级开发伴侣](https://juejin.im/post/5acae8dc6fb9a028c06b1c4c) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [单向用户界面架构问题研究](https://juejin.im/post/5aca38c5518825482e392c00) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [How to NOT React:React 中常见的反模式与陷阱](https://juejin.im/post/5acad683f265da23953146cd) ([MechanicianW](https://github.com/MechanicianW) 翻译) -* [关于 SPA 你需要掌握的 4 层](https://juejin.im/post/5ac9ae935188255caf067974) ([zwwill](https://github.com/zwwill) 翻译) -* [拖放库中 React 性能的优化](https://juejin.im/post/5ac31b096fb9a028bc2dedfc) ([hexianga](https://github.com/hexianga) 翻译) -* [热爱 JavaScript,但是讨厌 CSS?](https://juejin.im/post/5aba0d37518825556a72708a) ([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) -* [使用 React、Redux、SVG 开发游戏 - Part 1](https://juejin.im/post/5abcdc2c5188255c887bb9ec) ([zephyrJS](https://github.com/zephyrJS) 翻译) -* [关于 CSS 变量,你需要了解的一切](https://juejin.im/post/5ab835225188255572085af4) ([MechanicianW](https://github.com/MechanicianW) 翻译) -* [Reducers VS Transducers](https://juejin.im/post/5ab8705e518825555c1da48f) ([jonjia](https://github.com/jonjia) 翻译) -* [2018 如何玩转 JavaScript](https://juejin.im/entry/5aa0e46d6fb9a028b54775cd/detail) ([llp0574](https://github.com/llp0574) 翻译) -* [为你的 React 应用制作 SVG 图标库](https://juejin.im/post/5a9e40fe518825558a061cfd) ([Albertao](https://github.com/Albertao) 翻译) -* [做好准备:新的 V8 即将到来,Node.js 的性能正在改变。](https://juejin.im/post/5aaf755851882555627d16e5) ([Starriers](https://github.com/Starriers) 翻译) -* [我们能从 Redux 源码中学到什么?](https://juejin.im/post/5ab3ca926fb9a028d6641605) ([goldEli](https://github.com/goldEli) 翻译) -* [使用 Travis CI 自动发布 npm](https://juejin.im/post/5ab39fedf265da23a04979cb) ([Starriers](https://github.com/Starriers) 翻译) -* [TypeScript:拥有超能力的 JavaScript(下)](https://juejin.im/post/5ab34794518825558b3dd627) ([jonjia](https://github.com/jonjia) 翻译) -* [function.caller 被认为是有害的](https://juejin.im/post/5aa098de51882555635ddc20) ([yankwan](https://github.com/yankwan) 翻译) -* [网站优化初学者指南](https://juejin.im/post/5ab1e3f4f265da23923637bb) ([Starriers](https://github.com/Starriers) 翻译) -* [Typescript : 类 vs 接口](https://juejin.im/post/5aa79a106fb9a028db585eae) ([xueshuai](https://github.com/xueshuai) 翻译) -* [TypeScript:拥有超能力的 JavaScript](https://juejin.im/post/5aa89d5bf265da239a5f7f44) ([jonjia](https://github.com/jonjia) 翻译) -* [测试 React & Redux 应用真实引导](https://juejin.im/post/5a9cc812518825556f54e3b6) ([jonjia](https://github.com/jonjia) 翻译) -* [React 应用中 “神奇” 的多态—性能隐患](https://juejin.im/post/5aa5ebe16fb9a028d04314b0) ([blizzardzheng](https://github.com/blizzardzheng) 翻译) -* [Service workers:Progressive Web Apps 背后的小英雄](https://juejin.im/post/5a9c8c87f265da238c3a23e4) ([FateZeros](https://github.com/FateZeros) 翻译) -* [json — JavaScript 对象表示法](https://juejin.im/post/5a9432ae5188257a5c6092b0) ([snowyYU](https://github.com/snowyYU) 翻译) -* [一份为 Node.js 应用准备的 Dockerfile 指南](https://juejin.im/post/5a9626abf265da4e9d225f4f) ([lsvih](https://github.com/lsvih) 翻译) -* [关于 Promise 的 9 个提示](https://juejin.im/post/5a9600526fb9a06333155141) ([yanyixin](https://github.com/yanyixin) 翻译) -* [在 V8 引擎中设置原型(prototypes)](https://juejin.im/post/5a9921e76fb9a028bd4bc3c4) ([goldEli](https://github.com/goldEli) 翻译) -* [嵌套三元表达式棒极了(软件编写)(第十四部分)](https://juejin.im/post/5a7d6769f265da4e7e10ad82) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [探索 ECMAScript 装饰器](https://juejin.im/post/5a7bc62d6fb9a063523ddf95) ([goldEli](https://github.com/goldEli) 翻译) -* [v3.1.0:大幅性能提升并支持流媒体服务端渲染](https://juejin.im/post/5a7ff4a56fb9a0635a65600e) ([FateZeros](https://github.com/FateZeros) 翻译) -* [JavaScript 工作原理:Web Worker 的内部构造以及 5 种你应当使用它的场景](https://juejin.im/post/5a90233bf265da4e92683de3) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [你前所未知的 JavaScript 调试器](https://juejin.im/post/5a7e94a66fb9a0633b2105ed) ([Serendipity96](https://github.com/Serendipity96) 翻译) -* [JavaScript 中的私有变量](https://juejin.im/post/5a8e9b6d5188257a5f1ed826) ([noahziheng](https://github.com/noahziheng) 翻译) -* [CSS Grid 之列宽自适应:`auto-fill` vs `auto-fit`](https://juejin.im/post/5a8c25d66fb9a0634d27b73b) ([pot-code](https://github.com/pot-code) 翻译) -* [也谈 React 16.3(.0-alpha) ](https://juejin.im/entry/5a82ada16fb9a063317c54f2) ([pot-code](https://github.com/pot-code) 翻译) -* [使用 SVG 符号和 CSS 变量实现多彩图标](https://juejin.im/post/5a8409e06fb9a063342672b6) ([pthtc](https://github.com/pthtc) 翻译) -* [教你使用 CSS 计数器](https://juejin.im/post/5a811c6251882528b63ff8d7) ([sakila1012](https://github.com/sakila1012) 翻译) -* [2018 前端性能优化清单 — 第 1 部分](https://juejin.im/post/5a67e49df265da3e377c2d59) ([tvChan](https://github.com/tvChan) 翻译) -* [2018 前端性能优化清单 — 第 2 部分](https://juejin.im/post/5a654e686fb9a01cb42c7894) ([sakila1012](https://github.com/sakila1012) 翻译) -* [2018 前端性能优化清单 — 第 3 部分](https://juejin.im/post/5a702160f265da3e4b771109) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [2018 前端性能优化清单 — 第 4 部分](https://juejin.im/post/5a62aa686fb9a01c91407a0b) ([ParadeTo](https://github.com/ParadeTo) 翻译) -* [这些 CSS 命名规范将省下你大把调试时间](https://juejin.im/post/5a6c5881518825733201daf7) ([unicar9](https://github.com/unicar9) 翻译) -* [PWA 实战:Tinder 的性能优化之道](https://juejin.im/post/5a5ed5f3f265da3e261bfb94) ([pot-code](https://github.com/pot-code) 翻译) -* [迎接新的 Dialog 元素](https://juejin.im/post/5a66cc165188257342170802) ([FateZeros](https://github.com/FateZeros) 翻译) -* [保持 webpack 快速运行的诀窍:一本提高构建性能的现场指导手册](https://juejin.im/post/5a6adc6d5188257350517033) ([noahziheng](https://github.com/noahziheng) 翻译) -* [Vue Devtools 4.0 有哪些新内容](https://juejin.im/post/5a676c33f265da3e5b32f43c) ([MechanicianW](https://github.com/MechanicianW) 翻译) -* [我未曾见过的 JS 特性](https://juejin.im/post/5a723216f265da3e2e62d0a5) ([NeilLi1992](https://github.com/NeilLi1992) 翻译) -* [现代浏览器是如何提升性能的:网络层](https://juejin.im/post/5a70755df265da3e283a4e5d) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [构造函数已死,构造函数万岁!](https://juejin.im/post/5a694be551882573541c8f29) ([unicar9](https://github.com/unicar9) 翻译) -* [🚀webpack 4 测试版 —— 现在让我们先一睹为快吧!](https://juejin.im/post/5a72d569f265da3e3a6e2118) ([FateZeros](https://github.com/FateZeros) 翻译) -* [Object Composition 中的宝藏](https://juejin.im/post/5a648ed0518825733201b818) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [Angular 安全 —— 使用 JSON 网络令牌(JWT)验证:完全指南](https://juejin.im/post/5a64267c518825734e3e5c22) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [使用深度学习自动生成HTML代码 - 第 1 部分](https://juejin.im/post/5a72744e6fb9a01cb64f1d66) ([sakila1012](https://github.com/sakila1012) 翻译) -* [JavaScript 自动化爬虫入门指北(Chrome + Puppeteer + Node JS):和 Headless Chrome 一起带你装逼带你飞](https://juejin.im/post/5a4e1038f265da3e591e1247) ([pot-code](https://github.com/pot-code) 翻译) -* [JavaScript 是如何工作的:深入 WebSockets 和使用了 SSE+ 的 HTTP/2,如何在二者当中做出选择](https://juejin.im/post/5a522647518825732d7f6cbb) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [Redux-recompose 介绍:优雅的编写 Redux 中的 action 和 reducer](https://juejin.im/post/5a4e0d7651882573315c28a1) ([pot-code](https://github.com/pot-code) 翻译) -* [2018 要学习的优秀 JavaScript 库与知识](https://juejin.im/post/5a4e23f0f265da3e377bce4f) ([gy134340](https://github.com/gy134340) 翻译) -* [JWT:JSON Web Tokens 全方位指南](https://juejin.im/entry/5a4f300f6fb9a01cb912b3c7/) ([rottenpen](https://github.com/rottenpen) 翻译) -* [前端 2017: 举要删芜](https://juejin.im/post/5a523271f265da3e2f00c7ab) ([gy134340](https://github.com/gy134340) 翻译) -* [使用 web 应用打包工具 Parcel 实现代码分割](https://juejin.im/post/5a478289f265da430d5859ff) ([kangkai124](https://github.com/kangkai124) 翻译) -* [关于 Parcel 你所需要知道的一切:快速的 Web 应用打包器 🚀](https://juejin.im/post/5a545c94518825733d68edae) ([FateZeros](https://github.com/FateZeros) 翻译) -* [Redux 的工作原理](https://juejin.im/post/5a532e466fb9a01ca9154a98) ([hexianga](https://github.com/hexianga) 翻译) -* [垂直排版:重提 writing-mode](https://juejin.im/post/5a5570fb6fb9a01c9e45d749) ([Usey95](https://github.com/Usey95) 翻译) -* [漫画图解 JavaScript 引擎: let jsCartoons = ‘Awesome’;](https://juejin.im/post/5a582b13f265da3e355aff46) ([MechanicianW](https://github.com/MechanicianW) 翻译) -* [HTML 5.2 有哪些新内容?](https://juejin.im/post/5a5dab05518825734107edda) ([lsvih](https://github.com/lsvih) 翻译) -* [2017 年 JavaScript 发展状况回顾](https://juejin.im/entry/5a44a500f265da43271887f0/) ([LeviDing](https://github.com/leviding) 翻译) -* [如何在 JavaScript 中使用 Generator?](https://juejin.im/post/5a44968df265da4335630fb9) ([jonjia](https://github.com/jonjia) 翻译) -* [在 React & Redux 中使用 AJAX 轮询](https://juejin.im/post/5a43b6da5188257d167a7aef) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [在 Redux 中使用 AJAX 轮询(二):Saga 篇](https://juejin.im/post/5a43b80df265da43176a6e4e) ([lcx-seima](https://github.com/lcx-seima) 翻译) -* [论原子 CSS 的日益普及](https://juejin.im/post/5a4387af6fb9a045186b04d1) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [使用 CSS Grid:以兼容不支持栅格化布局的浏览器](https://juejin.im/post/5a3f494d6fb9a0450a678f8d) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [用 CSS 选择器和自定义属性来升级你的项目](https://juejin.im/post/5a3c47386fb9a044fd11f278) ([MechanicianW](https://github.com/MechanicianW) 翻译) -* [将网站转换为渐进式 Web 应用程序之简易教程](https://juejin.im/post/5a3cdf52f265da4321543c95) ([bambooom](https://github.com/bambooom) 翻译) -* [创建无障碍 React 应用](https://llp0574.github.io/2017/12/20/creating-accessible-react-apps/) ([llp0574](https://github.com/llp0574) 翻译) -* [针对 Airbnb 清单页的 React 性能优化](https://juejin.im/post/5a3a733f6fb9a045263bbdf5) ([zwwill](https://github.com/zwwill) 翻译) -* [如何取消你的 Promise?](https://juejin.im/post/5a32705a6fb9a045117127fa) ([jonjia](https://github.com/jonjia) 翻译) -* [介绍 Turbo:比 Yarn 和 NPM 快 5 倍,可以在本地浏览器中运行](https://juejin.im/post/5a35d58ef265da431a434441) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [从 Gzip 压缩 SVG 说起 — 论如何减小资源文件的大小](https://juejin.im/post/5a30a7fdf265da4309452517) ([lsvih](https://github.com/lsvih) 翻译) -* [用 Render props 吧!](https://juejin.im/post/5a3087746fb9a0450c4963a5) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [你想学 React.js 吗?](https://juejin.im/post/5a2f8ea5f265da43305e6f6b) ([tvChan](https://github.com/tvChan) 翻译) -* [JavaScript 工作原理:内存管理 + 处理常见的 4 种内存泄漏](https://juejin.im/post/5a2559ae6fb9a044fe4634ba) ([caoxiaoshuai1](https://github.com/caoxiaoshuai1) 翻译) -* [Ant Design 3.0 驾到](https://juejin.im/post/5a28aab66fb9a0450a673c5e) ([zwwill](https://github.com/zwwill) 翻译) -* [Chrome DevTools - 性能监控](https://juejin.im/post/5a37b2f56fb9a0451e3fe73d) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [如何禁用链接](https://juejin.im/post/5a240aa66fb9a0452577f06a) ([Usey95](https://github.com/Usey95) 翻译) -* [模拟是一种代码异味(软件编写)(第十二部分)](https://juejin.im/post/5a2d363e6fb9a0450b6652c8) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [React 应用性能调优](https://juejin.im/post/5a289cc6f265da43346fcc8d) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [如何使用 AJAX 和 REST API 创建一个图表](https://juejin.im/post/5a20e18bf265da4318768b22) ([sakila1012](https://github.com/sakila1012) 翻译) -* [JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧](https://juejin.im/post/5a221d35f265da43356291cc) ([balancelove](https://github.com/balancelove) 翻译) -* [前端 Console 调试小技巧](https://juejin.im/post/5a08087f6fb9a04529363d71) ([lsvih](https://github.com/lsvih) 翻译) -* [ES6 中的元编程: 第三部分 - 代理(Proxies)](https://juejin.im/post/5a0f05496fb9a04508093ac4) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [Angular、React、Vue 三剑客: 在 2017 年的比较](https://juejin.im/post/5a0d5df1f265da43062a542f) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [元编程:Symbol,了不起的 Symbol](https://juejin.im/post/5a0e65c1f265da430702d6b9) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [重建 slack.com:使用 CSS Grid 重新设计,并针对性能和可访问性进行了优化。](https://juejin.im/post/5a029d986fb9a044fb072efb) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [JavaScript 如何工作:在 V8 引擎里 5 个优化代码的技巧](https://juejin.im/post/5a102e656fb9a044fd1158c6) ([balancelove](https://github.com/balancelove) 翻译) -* [ES6 中的元编程:第二部分 —— 反射(Reflect)](https://juejin.im/post/5a0e66386fb9a04523417418) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [14 个你可能不知道的 JavaScript 调试技巧](https://github.com/xitu/gold-miner/pull/2404) ([ParadeTo](https://github.com/ParadeTo) 翻译) -* [Rollup - 下一代 ES6 模块化打包工具 - 对 Rich Harris 的采访](https://juejin.im/post/5a09b4e56fb9a0451170a22e) ([Raoul1996](https://github.com/Raoul1996) 翻译) -* [Under-the-hood-ReactJS 系列教程翻译 — 共 17 篇](https://github.com/xitu/Under-the-hood-ReactJS/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Under-the-hood-ReactJS 翻译组](https://github.com/xitu/Under-the-hood-ReactJS/) 翻译) -* [找出可能影响性能的代码模式](https://juejin.im/post/59f95af951882574d1723e70?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) -* [React 组件的 8 个关键决策](https://juejin.im/post/59f7e2c5f265da4318760a5f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([undead25](https://github.com/undead25) 翻译) -* [借助函数完成可组合的数据类型(软件编写)(第十部分)](https://juejin.im/post/59e3f3786fb9a0450166ff7b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [性能指标都是些什么鬼?](https://juejin.im/entry/59e855b45188250989513220/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [webpack & HTTP/2](https://juejin.im/post/59e87b89f265da433226b0f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) -* [JavaScript 让 Monad 更简单(软件编写)(第十一部分)](https://juejin.im/post/59e55dbbf265da43333d7652?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [React 16 带来了什么以及对 Fiber 架构的解释](https://juejin.im/post/59de1b2a51882578c70c0833?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [Javascript 中各种各样的 this](https://juejin.im/post/59e066d551882578c3411908?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [修改 JavaScript 帧](https://juejin.im/entry/59d2ed6f6fb9a00a681b01f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [为什么在使用了类之后会使得组合变得愈发困难(第九部分)](https://juejin.im/post/59cf43ce6fb9a00a4e67cd36?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [离线友好的表单](https://juejin.im/post/59c138e35188253fbd46c5fc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [V8 引擎中的快速属性](https://juejin.im/post/59c1df855188257e826779f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [如何安全地使用 CSS-in-JS?](https://juejin.im/post/59c90a6df265da065270b004?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yuuoniy](https://github.com/Yuuoniy) 翻译) -* [网络现状:性能提升指南](https://juejin.im/post/59c4b6a55188257e764c9c20?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([undead25](https://github.com/undead25) 翻译) -* [ES6+ 中的 JavaScript 工厂函数](https://juejin.im/post/59c8c8756fb9a00a681ae5bd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lampui](https://github.com/lampui) 翻译) -* [使用 CSS 栅格和 Flexbox 打造 Trello 布局](https://juejin.im/post/59bb463d51882519777c5a85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [在 HTTP/2 的世界里管理 CSS 和 JS](https://juejin.im/post/59bb463d51882519777c5a85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [学习 JavaScript:9个常见错误阻碍你进步](https://juejin.im/post/59bb4a7c6fb9a00a53274cd7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lekenny](https://github.com/lekenny) 翻译) -* [使用 CSS 的 font-size-adjust 属性改善网页排版](https://juejin.im/post/59b8b97d5188257e8c54d816?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lampui](https://github.com/lampui) 翻译) -* [CSS 十六进制颜色揭秘](https://juejin.im/entry/59b887515188257e7973a60a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [原生 JavaScript 值得学习吗?答案是肯定的](https://juejin.im/post/59a535bd6fb9a0249975cb9b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lampui](https://github.com/lampui) 翻译) -* [你是如何拆分组件的?](https://juejin.im/post/59aa7f8c6fb9a024747f13b7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([undead25](https://github.com/undead25) 翻译) -* [Angular 与 React:谁更适合前端开发](https://juejin.im/post/59ab51746fb9a024865d202b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([stormrabbit](https://github.com/stormrabbit) 翻译) -* [JavaScript 二进制的 AST](https://juejin.im/post/599e6f246fb9a024985f0421?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [关于 React Router 4 的一切](https://juejin.im/post/5995a2506fb9a0249975a1a4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([undead25](https://github.com/undead25) 翻译) -* [如何在 Webpack 2 中使用 tree-shaking](https://juejin.im/post/599bc13b6fb9a024a370f4ec?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) -* [Redux 有多棒?](https://juejin.im/entry/599cff2551882524397f95c1/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZiXYu](https://github.com/ZiXYu) 翻译) -* [自定义 Babel 和 ESLint 插件是如何提高生产率与用户体验的](https://juejin.im/post/599519e06fb9a02499759f71?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([H2O-2](https://github.com/H2O-2) 翻译) -* [理解 Service Worker](https://juejin.im/post/599163316fb9a03c3c14d751?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zyziyun](https://github.com/zyziyun) 翻译) -* [学习 React.js 比你想象的要简单](https://juejin.im/post/599156cc6fb9a03c3a25db08?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [渐进增强的 CSS 布局:从浮动到 Flexbox 到 Grid](https://juejin.im/post/5987acfd6fb9a03c502288f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([leviding](https://github.com/leviding) 翻译) -* [Web 端的下一代三维图形](https://juejin.im/post/5983208c5188253c6f2d185d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [在大型应用中使用 Redux 的五个技巧](https://juejin.im/post/5980514151882537b41c4c0d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([loveky](https://github.com/loveky) 翻译) -* [在 CSS 中使用特征查询](https://juejin.im/post/58eb3004ac502e006c45454b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [构建渐进式 Web 应用入门指南](https://juejin.im/entry/5979666af265da3e161a6402/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [回顾 ESLint 的成功](https://juejin.im/post/5978227a518825175b1e8354?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) -* [CSS 才不是什么黑魔法呢](https://juejin.im/post/5976eb626fb9a06bba474cf1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xunge0613](https://github.com/xunge0613) 翻译) -* [高性能 React:3 个新工具加速你的应用](https://juejin.im/post/5971bc786fb9a06bad656523?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [2017 年了,这么多前端框架,你会怎样选择?](https://juejin.im/post/597022c6f265da6c2f0add39?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([leviding](https://github.com/leviding) 翻译) -* [Redux 并不慢,只是你使用姿势不对 —— 一份优化指南](https://juejin.im/post/596db2f9f265da6c4602ffc3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [即将到来的正则表达式新特性](https://juejin.im/post/59683f98f265da6c4f34eec6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [是的,ES2017 (ES8)来了](https://juejin.im/post/596713b75188250da20604cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ToBeNumerOne](https://github.com/ToBeNumerOne) 翻译) -* [任何网站都可以成为渐进式网络应用 - 但我们需要做的更好](https://juejin.im/post/5966bf2451882568b20dc2af?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wilsonandusa](https://github.com/wilsonandusa) 翻译) -* [JavaScript 的函数式编程是一种反模式](https://juejin.im/post/59645b29f265da6c20419170?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [你不需要基于 CSS Grid 的栅格布局系统](https://juejin.im/post/5960e73f6fb9a06bb5403f87?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([leviding](https://github.com/leviding) 翻译) -* [React 在服务端渲染的实现](https://juejin.im/post/595b01ad6fb9a06bb15a13b2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MuYunyun](https://github.com/MuYunyun) 翻译) -* [V8 性能优化杀手](https://juejin.im/post/5959edfc5188250d83241399?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [如何充分利用 JavaScript 控制台](https://juejin.im/post/59510ac45188250d8860c908?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [统一样式语言](https://juejin.im/post/595311fa6fb9a06b9d5b5f08?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [ESLint v4.0.0 升级指南](https://juejin.im/post/5954af2f6fb9a06baa63ab50?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xunge0613](https://github.com/xunge0613) 翻译) -* [RxJS Observable 之冷和热](https://juejin.im/entry/594c88765188250d9017d072/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([hikerpig](https://github.com/hikerpig) 翻译) -* [JavaScript:回调是什么鬼?](https://juejin.im/post/594b3607128fe100650355c7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [高阶函数一点通](https://juejin.im/entry/594a3eaaa0bb9f006b0c304a/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [一封写给 CSS 的情书](https://juejin.im/post/594c75c0f265da6c2b765b25?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [函数式 Mixin(软件编写)(第七部分)](https://juejin.im/post/594a2cf6ac502e006bc0bc3a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [webpack 3:官方发布!!](https://juejin.im/post/5949272551882520fa3df038?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [理解 NPM 5 中的 lock 文件](https://juejin.im/post/5943849aac502e006b84ce07?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [读完 flexbox 细则之后学到的 11 件事](https://juejin.im/post/5940bcef61ff4b006cb6b0d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XatMassacrE](https://github.com/XatMassacrE) 翻译) -* [RxJS 简介:可观察对象、观察者与操作符](https://juejin.im/post/5934d2532f301e00585ea5f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [利用“Immutability(不可变性)”编写更为简洁高效的代码](https://juejin.im/post/592eb8bfa22b9d005776d6df?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [Airbnb 的前端重构](https://juejin.im/post/592e3af8ac502e006c9c3f1f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [Web 开发者安全清单](https://juejin.im/post/592651c944d904006400cd88?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([GangsterHyj](https://github.com/GangsterHyj) 翻译) -* [解密 Quantum:现代浏览器引擎的构建之道](https://juejin.im/post/591bc865a22b9d00583c17b8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xunge0613](https://github.com/xunge0613) 翻译) -* [光速 React](https://juejin.im/post/591ad6b7128fe1005ce1123a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [我是如何实现世界上最快的 JavaScript 记忆化的](https://juejin.im/post/5912b635a0bb9f0058b44c60?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) -* [别让你的偏爱拖了后腿:快拥抱箭头函数吧!](https://juejin.im/post/59158c92a0bb9f005fd58fd7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [为何 TypeScript 愈发流行了?](https://juejin.im/post/59152911a22b9d0058fd5fe8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([loveky](https://github.com/loveky) 翻译) -* [何为 HTML API,如何设计之?](https://juejin.im/entry/59131ee7a0bb9f0058ba4a88/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [前端调试技巧与诀窍](https://juejin.im/post/5901e8d6a0bb9f0065e64f63?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [哪些项目需要 React?都需要!](https://juejin.im/post/5910050661ff4b0062553421?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [ES6 模块原生支持在浏览器中落地,是时候该重新考虑打包了吗?](https://juejin.im/post/590a990a5c497d005852cf61?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [JavaScript 中的 CSS:基于组件的样式的未来](https://juejin.im/post/590822768d6d810058e4d24d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom) 翻译) -* [代码中添加注释之好坏丑](https://juejin.im/post/5902126aa0bb9f0065e80ea9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom) 翻译) -* [真正行动之前 你将一无所成](https://juejin.im/entry/58f6136861ff4b00580aef28?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([owenlyn](https://github.com/owenlyn) 翻译) -* [高阶函数(软件编写)(第四部分)](https://juejin.im/post/58f6d6ff570c3500564fbddc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [为什么用 JavaScript 学习函数式编程?(软件编写)(第二部分)](https://juejin.im/post/58f5a2ecb123db2fa2b1b244?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [Functor 与 Category (软件编写)(第六部分)](https://juejin.im/post/58f58d5da0bb9f006aac3e8d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [函数式程序员的 JavaScript 简介 (软件编写)(第三部分)](https://juejin.im/post/58f58b06da2f60005d43388b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sunui](https://github.com/sunui) 翻译) -* [Reduce(软件编写)(第五部分)](https://juejin.im/post/58f44082da2f60005d3a3710?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) -* [跌宕起伏的函数式编程(软件编写)(第一部分)](https://juejin.im/post/58f0eb570ce463006ba37089?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [React 的慢与快:优化 React 应用实战](https://juejin.im/entry/58eb2fb0570c350057dd921a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie(Jiang Haichao)](https://github.com/AceLeeWinnie) 翻译) -* [使用开发者工具在浏览器中调整设计](https://juejin.im/post/58f0729b570c35005625630a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom) 翻译) -* [超越浏览器:从 web 应用到桌面应用](https://juejin.im/entry/58f07ea5ac502e006c1e0301?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bambooom](https://github.com/bambooom) 翻译) -* [同中有异的 Webpack 与 Rollup](https://juejin.im/post/58edb865570c350057f199a7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译) -* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译) -* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译) -* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译) -* [生活在 JavaScript 之中:学习第二门语言的好处](https://juejin.im/post/58d908deac502e0058db544b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [震惊,还可以用这种姿势学习编程](https://juejin.im/post/58d3ebd4128fe1006cb43722/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) -* [如何让你的 React 应用完全的函数式,响应式,并且能处理所有令人发狂的副作用](https://juejin.im/post/58d3287f61ff4b006cb3f56d/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [编写整洁 CSS 代码的黄金法则](https://juejin.im/post/58d34bed128fe1006caf8b6b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [创建和使用 WebAssembly 组件](https://juejin.im/post/58d0bbe144d90400684c0f3a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xilihuasi](https://github.com/xilihuasi) 翻译) -* [WebAssembly 的现在与未来](https://github.com/xitu/gold-miner/blob/master/TODO/where-is-webassembly-now-and-whats-next.md) ([huzidaha](https://github.com/huzidaha/) 翻译) -* [是什么让 WebAssembly 执行的这么快?](https://github.com/xitu/gold-miner/blob/master/TODO/what-makes-webassembly-fast.md) ([huzidaha](https://github.com/huzidaha/) 翻译) -* [新一代 JavaScript 的开发图谱(2017)](https://juejin.im/post/58cfe86f61ff4b006ca26aaf/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [React 未来之函数式 setState](https://juejin.im/post/58cfcf6e44d9040068478fc6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [看动画,学 RxJS](https://juejin.im/post/58cd146a61ff4b0060277d32/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [如何让你的 React Native 应用在键盘弹出时优雅地响应](https://juejin.im/entry/58c7ceab0ce4630054834b07/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Shangbin Yang](https://github.com/rccoder) 翻译) -* [JIT 编译器快速入门](https://gold.xitu.io/entry/58c7777eda2f605dc5b1c258/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) -* [看漫画,学 WebAssembly](https://gold.xitu.io/entry/58c76be244d90400699b3a1f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sqrthree](https://github.com/sqrthree) 翻译) -* [Redux 异步四兄弟](https://gold.xitu.io/entry/58c75f9444d90400699add86/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译) -* [再谈 CSS 中的代码味道](https://gold.xitu.io/entry/58c2034dac502e0062cf8e2a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia)) 翻译) -* [Web 分享 API 赋予浏览器原生分享能力](https://gold.xitu.io/entry/58c174ec44d9040069777f17/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) -* [React JSX 与 Vue 模板的对比:前端界的一次对决](https://gold.xitu.io/entry/58b9841dac502e006c0a69d5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译) -* [为多个品牌和应用构建 React 组件](https://gold.xitu.io/entry/58b92529128fe1007e4493da/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XatMassacrE](https://github.com/XatMassacrE) 翻译) -* [编写 React 组件的最佳实践](https://gold.xitu.io/entry/58b3bbf6b123db0052d23e42/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([imink](https://github.com/imink) 翻译) -* [如何实现 React 组件的可复用性](https://gold.xitu.io/entry/58ac4eb58d6d810058c1d325?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([aleen42](https://github.com/aleen42) 翻译) -* [React 中“灵光乍现”的那些瞬息](https://gold.xitu.io/entry/58aaec530ce463006b14aa69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([aleen42](https://github.com/aleen42) 翻译) -* [JavaScript 启动性能探究](https://gold.xitu.io/entry/58a5b7d21b69e6006d2008e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([vuuihc](https://github.com/vuuihc) 翻译) -* [几张 GIF 动图让你看懂弹性盒模型(Flexbox)如何工作](https://gold.xitu.io/entry/589d2dd886b599006b2c3308?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [一个关于 Styled Components 的五分钟介绍](https://gold.xitu.io/entry/589ac8b886b599006b1cec3d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sqrthree](https://github.com/sqrthree) 翻译) -* [Netflix: 使用 React 构建高性能的电视用户界面](https://gold.xitu.io/entry/589a93100ce4630056194875/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([vuuihc](https://github.com/vuuihc) 翻译) -* [怎样写一个能同时用于 Node 和浏览器的 JavaScript 包?](https://gold.xitu.io/entry/5899bc6e61ff4b006b21d0bc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [让 Node.js 核心更强大](https://gold.xitu.io/entry/5897289b0ce463005603a5d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([imink](https://github.com/imink) 翻译) -* [2017 年要去学的 3 个 CSS 新属性](https://gold.xitu.io/entry/5896c8ee570c3500623eeaeb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([熊贤仁](https://github.com/FrankXiong) 翻译) -* [快来和你的 Font Icons 说 Goodbye 吧](https://gold.xitu.io/entry/589591442f301e0069488788?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Aleen](https://github.com/aleen42) 翻译) -* [使用 WebSocket 和 CSS3 创造魔法](https://gold.xitu.io/entry/5894612a2f301e006900cfcc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [在 CSS 中使用恒定角度的斜边](https://gold.xitu.io/entry/5875af941b69e6005ceffe94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [在 `setState` 中使用函数替代对象](https://gold.xitu.io/entry/5873b04f61ff4b006d4d45f7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [书写干净的 CSS 代码 PART2](https://gold.xitu.io/entry/5870d0841b69e6005cd23edc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [书写干净的 CSS 代码 PART1](https://gold.xitu.io/entry/5870d03c1b69e6005cd23aaa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [看沃尔玛如何玩转 React Native](https://gold.xitu.io/entry/5864e40e1b69e675fce43a80?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Draftbk](https://github.com/draftbk) 翻译) -* [渐进增强的 Web AMP](https://gold.xitu.io/entry/585d35b561ff4b00580eccb3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [CSS 继承深度解析](https://gold.xitu.io/entry/585a29c01b69e6006cb89465?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://llp0574.github.io) 翻译) -* [响应式邮件设计](https://gold.xitu.io/entry/58516cc01b69e60056c04528?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Hyuni](https://github.com/xuzaixian) 翻译) -* [JavaScript 测试︰ 单元 vs 功能 vs 集成测试](https://gold.xitu.io/entry/584ab2dc128fe1006c7cdc11?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wild-flame](https://github.com/wild-flame) 翻译) -* [如何用 JavaScript 作图](https://gold.xitu.io/entry/58441f8f128fe1006c4d1191?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [实践 Redux,第 2 部分:Redux-ORM 的概念和技术](http://gold.xitu.io/entry/583d90aba22b9d006c1f092a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [使用 React.js 的渐进式 Web 应用程序:第 4 部分 - 渐进增强](http://gold.xitu.io/entry/58345f5cc4c9710054e187a5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([rccoder](https://github.com/rccoder) 翻译) -* [使用 React.js 的渐进式 Web 应用程序:第 3 部分 - 离线支持和网络恢复能力](http://gold.xitu.io/entry/58350983a22b9d006bbb90d3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) -* [CSS 变量的条件](http://gold.xitu.io/entry/58354e50a22b9d006bc01c06?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([rottenpen](https://github.com/rottenpen) 翻译) -* [JavaScript 包管理器工作原理简介](http://gold.xitu.io/entry/5835a2c0c59e0d005772a62f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [使用 React.js 的渐进式 Web 应用程序:第 2 部分 - 页面加载性能](http://gold.xitu.io/entry/583576f3c4c9710054a3e212?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([markzhai](https://github.com/markzhai) 翻译) -* [详解 React Native 使用 OneSignal 推送通知](http://gold.xitu.io/entry/58369fa5c59e0d005777d12f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoheiai4719](https://github.com/xiaoheiai4719) 翻译) -* [无需配置即可创建 React Apps](http://gold.xitu.io/entry/583266068ac2470061c24c06?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiakeqi](https://github.com/jiakeqi) 翻译) -* [React Native Android 应用内存使用探究](http://gold.xitu.io/entry/5834161bda2f600062be79b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([phxnirvana](https://github.com/phxnirvana) 翻译) -* [React Native Android 的 native 模块](http://gold.xitu.io/entry/5832e55fc4c971005f565b4c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XHShirley](https://github.com/XHShirley) 翻译) -* [我在手撕 SVG 条形图时踩过的定位坑](http://gold.xitu.io/entry/58306b428ac2470061b60ede?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cyseria](https://github.com/cyseria) 翻译) -* [使用 “Google 抓取方式” 测试 React 驱动的网站 SEO](http://gold.xitu.io/entry/582e8b2fd20309006702090f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [Node.js v6 LTS 中最激动人心的六个 ES6 特性](http://gold.xitu.io/entry/582dcfb067f356006336c834?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [10 个原则让动画带你飞](http://gold.xitu.io/entry/582dce6ea0bb9f0067ac0b4e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [一个健壮且可扩展的 CSS 架构所需的 8 个简单规则](http://gold.xitu.io/entry/582d137d128fe1006952b12c/detail/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [使用 React.js 的渐进式 Web 应用程序:第 1 部分 - 介绍](http://gold.xitu.io/post/582a64dd2e958a0069a507f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([markzhai](https://github.com/markzhai) 翻译) -* [无障碍网站开发工具](https://gold.xitu.io/entry/58294b222f301e00585ae000?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [全方位提升网站打开速度:前端、后端、新的技术)](https://gold.xitu.io/entry/582492025bbb5000590ef04d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [准备充分了嘛就想学函数式编程?(Part 5)](https://gold.xitu.io/entry/582490c3bf22ec0068f9935e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [实践 Redux,第 1 部分: Redux-ORM 基础](https://gold.xitu.io/entry/58249792a0bb9f0058dd30ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [成为一个编译器之「使用 JavaScript 来制作编译器」](https://gold.xitu.io/entry/582343555bbb500059056d4b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [准备充分了嘛就想学函数式编程?(Part 3)](https://gold.xitu.io/entry/581fedca2f301e005c2260a0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [准备充分了嘛就想学函数式编程?(Part 2)](https://gold.xitu.io/entry/581fed565bbb500059ec1184?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Airmacho](https://github.com/Airmacho) 翻译) -* [使用多背景来提高感知性能](https://gold.xitu.io/entry/58217e288ac247004f1d1b02?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cyseria](https://github.com/cyseria) 翻译) -* [Yarn 更快更可靠的 CI 创建工具](https://gold.xitu.io/entry/582019f5a0bb9f0058bb5f14?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [用 Yarn 你还能做这 5 件事](https://gold.xitu.io/entry/582185608ac247004f1d63a3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiakeqi](https://github.com/jiakeqi) 翻译) -* [准备充分了嘛就想学函数式编程?(Part 6)](https://gold.xitu.io/entry/58209780570c350060b75a93?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeadLion](https://github.com/DeadLion) 翻译) -* [实践 Redux,第 0 部分:简介](https://gold.xitu.io/entry/5820552eda2f60005d09c33c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [写了六个相同功能的函数之后,我学到了什么](https://gold.xitu.io/entry/58200ec367f3560058a6f8fc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Romeo0906](https://github.com/Romeo0906) 翻译) -* [准备充分了嘛就想学函数式编程?(第一部分)](https://gold.xitu.io/entry/581fe399d20309005507371c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [你怎么找到好工作,我在 Stack Overflow & GitHub 学电脑](https://gold.xitu.io/entry/581f3bd9da2f60005d02f561?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [准备充分了嘛就想学函数式编程?(第四部分)](https://gold.xitu.io/entry/581bf0a62e958a0054d783e1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [CSS 遮罩的过渡效果](https://gold.xitu.io/entry/5819d6f4a22b9d0067a5b394?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译) -* [JavaScript ES6 核心功能一览](https://gold.xitu.io/entry/58189177128fe100559efd51?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [与时俱进的 Reactivity](https://gold.xitu.io/entry/58130dcbbf22ec0068824bd2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Liz](https://github.com/lizwangying) 翻译) -* [重构,不要积压!](https://gold.xitu.io/entry/581066dc8ac247005b6b3d4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([rottenpen](https://github.com/rottenpen) 翻译) -* [Facebook 发布了新的 Node 模块管理器 Yarn,或取代 npm 客户端](https://gold.xitu.io/entry/57fe2f2b128fe1005483131b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/Zhangjd) 翻译) -* [构建应用状态时,你应该避免不必要的复杂性](https://gold.xitu.io/entry/58044c2a0e3dd900571475fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([chemzqm](https://github.com/chemzqm) 翻译) -* [开发 Electron app 必知的 4 个 tips](https://gold.xitu.io/entry/58025536bf22ec0064d5f3d9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huanglizhuo](https://github.com/huanglizhuo) 翻译) -* [VUE 和 VUEX 中的数据流](https://gold.xitu.io/entry/58007bcf0bd1d00058eefe69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [使用 Cordova 和 Vue.js 创建移动应用](https://gold.xitu.io/entry/57ea26f5da2f600060e59c5e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [使用 currentColor 属性写出更好的 CSS 代码](https://gold.xitu.io/entry/57eb30bebf22ec0058898ee7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yangzj1992](http://qcyoung.com) 翻译) -* [快速构建原型最好用的 10 个 ReactJS UI 框架](https://gold.xitu.io/entry/57ea0bc2a3413100624e62ff?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cyseria](https://github.com/cyseria) 翻译) -* [响应式设计的真正挑战:RSS](https://gold.xitu.io/entry/57d909170e3dd900694dc072?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) -* [3 分钟掌握 CSS Flexbox](https://gold.xitu.io/entry/57ce68bf2e958a00543a7df9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Graning](https://github.com/Graning) 翻译) -* [基于浏览器的 MapReduce](https://gold.xitu.io/entry/57cd7b9c8ac24700645b052b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mypchas6fans](https://github.com/mypchas6fans) 翻译) -* [如何编写更少的代码](https://gold.xitu.io/entry/57c6adc7a633bd005d8f2584?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [如何用 React 完成图片上传功能?](https://gold.xitu.io/entry/57b923225bbb50005b794943?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeadLion](https://github.com/DeadLion) 翻译) -* [你考虑清楚了吗就决定用 Bootstrap ?](http://gold.xitu.io/entry/57b67315a34131005f82d244?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) -* [如何运用最新的技术提升网页速度和性能](http://gold.xitu.io/entry/57b3f7928d2a3b0069605c2c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([hpoenixf](https://github.com/hpoenixf) 翻译) -* [Medium 内部使用 css/less 的代码风格指南](http://gold.xitu.io/entry/57b06a1b6be3ff006bab2030?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gran](https://github.com/Graning) 翻译) -* [CSS writing-mode 的特别技巧](http://gold.xitu.io/entry/57b08227165abd005426657b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huanglizhuo](https://github.com/huanglizhuo) 翻译) -* [如何搭建自动化、跨浏览器的 JavaScript 单元测试](http://gold.xitu.io/entry/579b2d6ea633bd0060eb965f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([owenlyn](https://github.com/owenlyn) 翻译) -* [ES6 中 的 var、let 和 const 应该如何选择?](http://gold.xitu.io/entry/57962ef22e958a00651f7387?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Graning](https://github.com/Graning) 翻译) -* [使用 Zopfli 优化 PNG 图片](http://gold.xitu.io/entry/578e3a34c4c971005e059ee9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cyseria](https://github.com/cyseria) 翻译) -* [jQuery 终于发布了](https://gold.xitu.io/entry/576917c0d342d30058097229?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Dwight](https://github.com/ldhlfzysys) 翻译) -* [如何理解 JavaScript 中的 Promise 机制](http://gold.xitu.io/entry/57890b881532bc0061d5ac52?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huanglizhuo](https://github.com/huanglizhuo) 翻译) -* [懒加载图片?不要依赖 JavaScript !](http://gold.xitu.io/entry/5787048a165abd0067f7e476?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jk77](https://github.com/jk77me) 翻译) -* [用 Javascript 编写λ演算解释器](http://gold.xitu.io/entry/57834783d342d30057db3f93?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangzhaoqi](https://github.com/joddiy) 翻译) -* [让你的网站更炫酷的一些小 tips](https://gold.xitu.io/entry/577f402b79bc4400329db962?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([达仔](https://github.com/zhangjd) 翻译) -* [较为完整的 React.js / Vue.js 的性能比较 Part 1](https://gold.xitu.io/entry/577bacc92e958a00549106dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [较为完整的 React.js / Vue.js 的性能比较 Part 2](https://gold.xitu.io/entry/57691d5d6be3ff006a438e09?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wild-flame](https://github.com/wild-flame) 翻译) -* [让 Webpack 来帮你打包吧](https://gold.xitu.io/entry/5767a975df0eea0062ffe193?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([达仔](https://github.com/Zhangjd) 翻译) -* [关于 PostCSS 普及的一点微小的工作](https://gold.xitu.io/entry/57635cdda341310064c5910a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [React 应用的性能优化之路](http://gold.xitu.io/entry/57621f7980dda4005f7332f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([woota](https://github.com/woota) 翻译) -* [如何编写避免垃圾开销的实时 Javascript 代码](http://gold.xitu.io/entry/575d14937db2a2005437df32?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yangzj1992](http://www.qcyoung.com/) 翻译) -* [如何用 Flexbox 构建一个新闻网站布局](http://gold.xitu.io/entry/57580e885bbb500053bc70c4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangzhaoqi](https://github.com/joddiy) 翻译) -* [使用 BEM 来模块化你的 CSS 代码](http://gold.xitu.io/entry/5757ce7b7db2a200540d51eb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([杨龙龙](https://github.com/yllziv) 翻译) -* [减少 JPG 文件大小](http://gold.xitu.io/entry/574fe1aa79bc440052f698de?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shenxn](https://github.com/shenxn) 翻译) -* [使用重构件(Codemod)加速 JavaScript 开发和重构](http://gold.xitu.io/entry/574e49662e958a005e00f543?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Hikerpig](https://github.com/hikerpig) 翻译) -* [如何用 Babel 和 Rollup 来构建和发布 ES6 模块](http://gold.xitu.io/entry/574445d579bc44005c63265b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [10 个你可能不知道的事,关于 Facebook 内部开发环境是如何使用 JavaScript 和 GraphQL 的](http://gold.xitu.io/entry/5739f5dc71cfe400570ea59f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Jack](https://github.com/Jack-Kingdom) 翻译) -* [使用 ES6 写更好的 JavaScript part III:好用的集合和反引号](http://gold.xitu.io/entry/573e7ef91ea49300601c7332?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([godofchina](https://github.com/godofchina) 翻译) -* [使用 ES6 编写更好的 JavaScript Part II:深入探究 [类]](http://gold.xitu.io/entry/573969b91ea4930060f3e31a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Malcolm](https://github.com/malcolmyu) 翻译) -* [使用 ES6 写更好的 JavaScript part I:广受欢迎的新特性](http://gold.xitu.io/entry/5736e4f41532bc006545106e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huanglizhuo](https://github.com/huanglizhuo) 翻译) -* [网页端字体加载优化](http://gold.xitu.io/entry/5732936d49830c0061c7ec72?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shenxn](https://github.com/shenxn) 翻译) -* [怎样在不使用框架的基础上开发一个 Javascript 组件](http://gold.xitu.io/entry/572d5f132e958a0066873e2c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [ECMAScript 6 里面的私有变量](http://gold.xitu.io/entry/572c0b2d2e958a00667a081d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XRene](https://github.com/CommanderXL) 翻译) -* [10 步带你做一个棒棒的 Hybrid 应用](http://gold.xitu.io/entry/5729a76479df5400608d1f9f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yves-X](https://github.com/Yves-X) 翻译) -* [JavaScript 姿势提升简略](http://gold.xitu.io/entry/5722c838128fe100601dc3a8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Hikerpig](https://github.com/hikerpig) 翻译) -* [Starlight - 在网页中运行 Lua](http://gold.xitu.io/entry/5719907eebcb7d005cc6acca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([narcotics726](https://github.com/narcotics726) 翻译) -* [React.js 新手村教程](http://gold.xitu.io/entry/5719b6acebcb7d006a007d9b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([markzhai](https://github.com/markzhai) 翻译) -* [使用 CSS 和 jQuery 来做一个墨水晕开的效果](http://gold.xitu.io/entry/57160c4b8ac2470062601b1f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [JavaScript 生态之乱象](http://gold.xitu.io/entry/5705e71ed342d3005418ea66?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([woota](https://github.com/woota) 翻译) -* [在网站 Logo 上右击时提示下载网站的 Logo 素材下载](http://gold.xitu.io/entry/570b2b671ea493005c024ee3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yushneng](https://github.com/rainyear) 翻译) -* [揭秘 IIFE 语法](http://gold.xitu.io/entry/5704e12771cfe4005dc85868?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huxpro](https://github.com/Huxpro) 翻译) -* [利用 :placeholder-shown 选择器实现 label 浮动效果](http://gold.xitu.io/entry/56de3c291532bc005620b320?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [响应式 GraphQL 结构](http://gold.xitu.io/entry/56de66fe731956005c46782a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shenxn](https://github.com/shenxn) 翻译) -* [[译] 在 BigCommerce 我们如何编写 CSS](http://gold.xitu.io/entry/56ce82cbc24aa800520f4215?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shenxn](https://github.com/shenxn) 翻译) -* [无缝迁移 Angular 1 项目到 Angular 2](http://gold.xitu.io/entry/56d3bd6a1ea493005c1eddfa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([BOBO](https://github.com/CoderBOBO) 翻译) -* [在 chrome 的开发者工具里 debug node.js 代码](http://gold.xitu.io/entry/56d3cfea6be3ff005c5f9b89?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sqrthree](https://github.com/sqrthree) 翻译) -* [350 个特性看透 ES6](https://github.com/xitu/gold-miner/blob/master/TODO/es6.md) ([Go7hic](https://github.com/dyygtfx) 翻译) -* [2015 年底 JS 必备工具集](http://gold.xitu.io/entry/56cee8afc24aa800545f73bb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([赵鑫晖](https://github.com/zxc0328) 翻译) -* [Promise 是如何工作的?](http://gold.xitu.io/entry/56cc0bcf8ac2470053b7c5ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/Zhangjd) 翻译) -* [JavaScript 开发者年度调查报告](http://gold.xitu.io/entry/56ca985071cfe40054d98994?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([sqrthree](https://github.com/sqrthree) 翻译) -* [Functional JavaScript 教程(一)](http://gold.xitu.io/entry/56d4e8b57db2a200556c64cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [人人须知的 jQuery 技巧](http://gold.xitu.io/entry/56e1a95b731956005da35c24?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Yves-X](https://github.com/Yves-X) 翻译) +* [为什么我对 TypeScript 黑转粉?一个 JS 开发者的深情自白](https://juejin.cn/post/6935629277870161957)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [在 React 中使用 Immer 管理不可变状态](https://juejin.cn/post/6935790852476239886)([zenblo](https://github.com/zenblo) 翻译) +* [TypeScript 4.2 正式发布:优化了类型和开发者体验](https://juejin.cn/post/6935255387893399560)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [自适应 CSS 栅格:自由布局的最终版本](https://juejin.cn/post/6935090806210428959)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [Deno 将停用 TypeScript 的五个原因](https://juejin.cn/post/6934140963262562312)([zenblo](https://github.com/zenblo) 翻译) +* [关于 Node.js 中的异步迭代器](https://juejin.cn/post/6934596464639213576)([Isildur46](https://github.com/Isildur46) 翻译) +* [CSS3 会替代 SCSS 吗?](https://juejin.cn/post/6934326962450071559)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [我后悔没有在自己成为 React 开发者之前做的 6 件事情](https://juejin.cn/post/6934144158332354567)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [JavaScript 中哪一种循环更快呢?](https://juejin.cn/post/6930973929452339213)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [3 个最棒的最值得你去在产品中使用的 CSS Grid 功能](https://juejin.cn/post/6931372123441233927)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [恭喜 Safari 荣获「第二个 Internet Explorer」的美誉](https://juejin.cn/post/6929754875001569294)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)([Usualminds](https://github.com/Usualminds) 翻译) +* [你应该编译你的 JavaScript 代码吗?](https://juejin.cn/post/6926927963636105223)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [简述 HTTP 请求与跨域资源共享 CORS](https://juejin.cn/post/6927191095470194695)([zenblo](https://github.com/zenblo) 翻译) +* [如何在浏览器上使用 NoSQL 数据库 IndexedDB](https://juejin.cn/post/6930883284456964109)([zenblo](https://github.com/zenblo) 翻译) +* [2021 年 JavaScript 测试框架回顾](https://juejin.cn/post/6927585452253790216)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [为什么 React Hooks 是错误的抽象](https://juejin.cn/post/6930529765048713229)([fltenwall](https://github.com/fltenwall) 翻译) +* [函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [掌握这 5 个 TypeScript 高级技巧,成为更好的开发者](https://juejin.cn/post/6924293152907984909)([Usualminds](https://github.com/Usualminds) 翻译) +* [如何让 JavaScript 中的循环慢下来](https://juejin.cn/post/6924512805135581197)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [只使用 CSS 进行用户追踪](https://juejin.cn/post/6887478219662950414)([MangoTsing](https://github.com/MangoTsing) 翻译) +* [哪个跨平台框架才是最好的选择?React Native、Flutter 还是 Ionic。](https://juejin.cn/post/6884099570435883022)([MangoTsing](https://github.com/MangoTsing) 翻译) +* [自己写一个 redux](https://juejin.cn/post/6923922875191656462)([tanglie1993](https://github.com/tanglie1993/) 翻译) +* [为什么你应该使用 Picture 标签而不是 Img 标签](https://juejin.cn/post/6923840549170446343)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [在 TypeScript 中引入 JSON 模块](https://juejin.cn/post/6923188659957006343)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [2021 年 Web 应用开发常用的五个图标库](https://juejin.cn/post/6922416136294252557)([zenblo](https://github.com/zenblo) 翻译) +* [虚拟 DOM 来源于文档片段吗?](https://juejin.cn/post/6902211857244028941)([regon-cao](https://github.com/regon-cao) 翻译) +* [对象展开运算符在 JavaScript 中的 5 大应用](https://juejin.cn/post/6895525536039174151)([Alfxjx](https://github.com/Alfxjx) 翻译) +* [使用 clamp() 进行响应式设计](https://juejin.cn/post/6890830054134611976)([Alfxjx](https://github.com/Alfxjx) 翻译) +* [Javascript Memoization 入门指南](https://juejin.cn/post/6920460950424256526)([samyu2000](https://github.com/samyu2000) 翻译) +* [深入了解 JavaScript 模块](https://juejin.cn/post/6920153306392166413)([regon-cao](https://github.com/regon-cao) 翻译) +* [解构标志性的 Apple Watch Bubble UI](https://juejin.cn/post/6919630087843217416)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [不同类型的浏览器存储](https://juejin.cn/post/6915263201882046472)([flashhu](https://github.com/flashhu) 翻译) +* [减少 Web 应用程序中 CORS 预检时间的 4 种方法](https://juejin.cn/post/6914561805465419784)([regon-cao](https://github.com/regon-cao) 翻译) +* [爱 GraphQL 胜过 REST](https://juejin.cn/post/6914306976294338567)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [为什么要让你的代码尽可能简单](https://juejin.cn/post/6914669681500487687)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [Web 应用缓存的基础知识](https://juejin.cn/post/6913898149740281870)([regon-cao](https://github.com/regon-cao) 翻译) +* [WebTransport 会在不久的将来取代 WebRTC 吗?](https://juejin.cn/post/6910186017190313991)([Usualminds](https://github.com/Usualminds) 翻译) +* [使用 CSS 提升页面渲染速度](https://juejin.cn/post/6911689122759475208)([Usualminds](https://github.com/Usualminds) 翻译) +* [在 Node.js 中避免内存泄漏:性能最佳实践](https://juejin.cn/post/6911488842079928327)([laampui](https://github.com/laampui) 翻译) +* [2021 年 Web 开发者应该掌握的 15 个 VSCode 扩展](https://juejin.cn/post/6910570256645914637)([regon-cao](https://github.com/regon-cao) 翻译) +* [单体应用与微前端开发对比](https://juejin.cn/post/6906021856210321422)([zenblo](https://github.com/zenblo) 翻译) +* [简单介绍就能理解的 React Portals(传送门)](https://juejin.cn/post/6904979968413925384)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [理解 JavaScript 中模块的导入和导出](https://juejin.cn/post/6904980094998020109)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [提高开发效率的五个 Chrome 扩展程序](https://juejin.cn/post/6903831004034072589)([zenblo](https://github.com/zenblo) 翻译) +* [继承 vs 组合:哪一个更适合你的 JavaScript 项目?](https://juejin.cn/post/6906288659742654478)([regon-cao](https://github.com/regon-cao) 翻译) +* [TypeScript 的 5 个建议](https://juejin.cn/post/6906307187816349703)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [增量 DOM 与虚拟 DOM 的对比使用](https://juejin.cn/post/6903765877296988174)([zenblo](https://github.com/zenblo) 翻译) +* [四个优秀 Vue.js 静态站点生成器](https://juejin.cn/post/6903309715309068295)([zenblo](https://github.com/zenblo) 翻译) +* [JavaScript 的面向切面编程](https://juejin.cn/post/6903484050095210509)([Liusq-Cindy](https://github.com/Liusq-Cindy) 翻译) +* [页面生命周期 API:每一个前端开发者都应该知道的浏览器 API](https://juejin.cn/post/6906779518040539144)([xutaogit](https://github.com/xutaogit) 翻译) +* [WebAssembly 及其 JavaScript API 的完整介绍](https://juejin.cn/post/6887953627302854669)([JohnieXu](https://github.com/JohnieXu) 翻译) +* [用 JavaScript 实现堆](https://juejin.cn/post/6893475005834330126)([HurryOwen](https://github.com/HurryOwen) 翻译) +* [前端应用的性能指标](https://juejin.cn/post/6884055395434758151)([nia3y](https://github.com/nia3y) 翻译) +* [Blitz.js 简介:一个新兴的 React 全栈框架](https://juejin.cn/post/6887201657801670669)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [如何使用 useRef 修复 React 性能问题](https://juejin.cn/post/6900510215851114509)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [使用 JavaScript 解构让代码更优雅](https://juejin.cn/post/6901081096260648974)([zenblo](https://github.com/zenblo) 翻译) +* [在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)([regon-cao](https://github.com/regon-cao) 翻译) +* [使用原生 CSS 实现自适应视频](https://juejin.cn/post/6898144070125518856)([zenblo](https://github.com/zenblo) 翻译) +* [从零开始了解 JavaScript 装饰器](https://juejin.cn/post/6898189092652384270)([regon-cao](https://github.com/regon-cao) 翻译) +* [使用 Svelte 开发前端应用的五个理由](https://juejin.cn/post/6897010393609142279)([zenblo](https://github.com/zenblo) 翻译) +* [抽象数据类型与软件危机](https://juejin.cn/post/6900761312532529166)([zenblo](https://github.com/zenblo) 翻译) +* [四种跨浏览器选项卡实时通信方法](https://juejin.cn/post/6896273264214179848)([zenblo](https://github.com/zenblo) 翻译) +* [如何在 Nextjs 中使用 cookies 来持久化保存用户信息](https://juejin.cn/post/6896062683263860749)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [浏览器 Web History API 的应用](https://juejin.cn/post/6891500768973553672)([zenblo](https://github.com/zenblo) 翻译) +* [分享九个 JavaScript 图片懒加载库](https://juejin.cn/post/6890325820200943629)([zenblo](https://github.com/zenblo) 翻译) +* [使用原生 CSS 设置响应式字体](https://juejin.cn/post/6888471725080903687)([zenblo](https://github.com/zenblo) 翻译) +* [Github Actions 工作流的创建与跟踪](https://juejin.cn/post/6892248874669309965)([zenblo](https://github.com/zenblo) 翻译) +* [JavaScript ES2021 中激动人心的特性](https://juejin.cn/post/6892246810250477575)([tonylua](https://github.com/tonylua) 翻译) +* [Web Locks API:跨 Tab 资源同步](https://juejin.cn/post/6895792867080405005)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [JavaScript 颜色处理库 Chroma.js 的应用](https://juejin.cn/post/6886263418907688974)([zenblo](https://github.com/zenblo) 翻译) +* [单页应用程序的哈希 URL 与普通 URL](https://juejin.cn/post/6884805346582331399)([zenblo](https://github.com/zenblo) 翻译) +* [NextJS vs. NuxtJS vs. GatsbyJS](https://juejin.cn/post/6882994530149203981)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [我的网站加载时间不到 1 秒,这是我如何做到的!](https://juejin.cn/post/6870329885034807310)([wangqinggang](https://github.com/wangqinggang) 翻译) +* [在 React 中使用 Service Worker](https://juejin.im/post/6881616183158636552)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [掌握 JavaScript ES6 中的 Symbol 类型](https://juejin.im/post/6880485630501978126)([Inchill](https://github.com/Inchill) 翻译) +* [TypeScript:一个好泛型的价值](https://juejin.im/post/6878868818836488205)([tonylua](https://github.com/tonylua) 翻译) +* [ES2017 最佳特性  —  数组中的异步函数以及共享缓冲区](https://juejin.im/post/6878849121269055501)([tonylua](https://github.com/tonylua) 翻译) +* [使用 React 和 localStorage 实现的简易 Dark Mode 开关](https://juejin.im/post/6875538309934743560)([Inchill](https://github.com/Inchill) 翻译) +* [VueJS 中更好的组件组合方式](https://juejin.im/post/6875236830984437768)([tonylua](https://github.com/tonylua) 翻译) +* [5 个鲜为人知的 Chrome 开发者工具的特性](https://juejin.im/post/6875240551390642189)([Shirley-He-Maker](https://github.com/Shirley-He-Maker) 翻译) +* [使用 JSON.stringify 处理 JavaScript 对象](https://juejin.im/post/6871807169562902541)([Inchill](https://github.com/Inchill) 翻译) +* [加速 vue.js 应用的六种绝技](https://juejin.im/post/6870808442911588365)([MangoTsing](https://github.com/MangoTsing) 翻译) +* [JavaScript 函数中一些你不知道的秘密](https://juejin.im/post/6871101056642711559)([Isildur46](https://github.com/Isildur46) 翻译) +* [如何处理 JavaScript 比较中的临界情况](https://juejin.im/post/6872682987859738632)([tonylua](https://github.com/tonylua) 翻译) +* [如何在悬停时创建菜单图像动画](https://juejin.im/post/6878561756793454599)([zenblo](https://github.com/zenblo) 翻译) +* [Vue 应用的代码覆盖率](https://juejin.im/post/6872653403177254919)([tonylua](https://github.com/tonylua) 翻译) +* [最常用的 4 种 JavaScript 设计模式](https://github.com/xitu/gold-miner/blob/master/article/2020/4-useful-javascript-design-patterns-you-should-know.md)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [JavaScript 引擎概述](https://juejin.im/post/6869976412745367566)([Isildur46](https://github.com/Isildur46) 翻译) +* [React vs. Svelte:虚拟与真实 DOM 间的战争](https://juejin.im/post/6870858079513247758)([nia3y](https://github.com/nia3y) 翻译) +* [让你的 Web 应用和移动应用选择 PWA 的 5 个理由](https://juejin.im/post/6868084125195042823)([rocwong-cn](https://github.com/rocwong-cn) 翻译) +* [JavaScript 生成器:何时用 yield,何时用 yield* ?](https://juejin.im/post/6867036974441005063)([Isildur46](https://github.com/Isildur46) 翻译) +* [TypeScript 4.0 终于发布了我一直在等待的东西](https://juejin.im/post/6864473591770152968)([rocwong-cn](https://github.com/rocwong-cn) 翻译) +* [如何实现交互式 WebGL 悬停效果](https://github.com/xitu/gold-miner/blob/master/article/2020/interactive-webgl-hover-effects.md)([zenblo](https://github.com/zenblo) 翻译) +* [8 个有用的 SCSS 最佳实践](https://juejin.im/post/6862499761351163911)([snowyYU](https://github.com/snowyYU) 翻译) +* [你应该了解的八种浏览器 API](https://github.com/xitu/gold-miner/blob/master/article/2020/8-unheard-of-browser-apis-you-should-be-aware-of.md)([zenblo](https://github.com/zenblo) 翻译) +* [分享我喜欢的十五条 JavaScript 编程技巧](https://github.com/xitu/gold-miner/blob/master/article/2020/my-favorite-javascript-tips-and-tricks.md)([zenblo](https://github.com/zenblo) 翻译) +* [前端开发 8 大性能分析工具](https://juejin.im/post/6860664312504320014)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [给前端开发者的 14 个 JavaScript 代码优化建议](https://juejin.im/post/6859562506721951751)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [如何利用 Polyfill 和转译在所有浏览器中使用最新 JavaScript 特性](https://juejin.im/post/6868513605055643662)([MangoTsing](https://github.com/MangoTsing) 翻译) +* [Javascript 应用中引入 CSS 的几种方式](https://juejin.im/post/6867054761741549576)([thisisandy](https://github.com/thisisandy) 翻译) +* [使用 Chrome 的 Shape Detection API 检测人脸,文本甚至条形码](https://juejin.im/post/6864391729693491207)([rocwong-cn](https://github.com/rocwong-cn) 翻译) +* [打包用于分发的 UI 库 —— 当你要发布一个 UI 组件库时,你可能需要遵守的指南](https://juejin.im/post/6863091746113323021)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [如何在字符串中隐藏秘密 —— JavaScript 中的现代文本隐藏](https://juejin.im/post/6856737400396349454)([nia3y](https://github.com/nia3y) 翻译) +* [JavaScript 技巧 —— 子代构造函数,文本选择,内联 Workers 等等](https://juejin.im/post/6854573219622420488)([plusmultiply0](https://github.com/plusmultiply0) 翻译) +* [Redux 中过时的 props 和僵尸子节点](https://juejin.im/post/5f0c1fd76fb9a07e8e44f2e5)([nia3y](https://github.com/nia3y) 翻译) +* [如何写一份能让你获得面试机会的前端求职简历](https://juejin.im/post/5ef5ef41f265da22ff543630)([febrainqu](https://github.com/febrainqu) 翻译) +* [改善 CSS 的 10 个最佳实践](https://juejin.im/post/5ede03a9f265da76fe6cde03)([febrainqu](https://github.com/febrainqu) 翻译) +* [Schema.org:你未曾耳闻的流行网页标准 🤫](https://juejin.im/post/5ee4ce2df265da770c0f08b6)([lhd951220](https://github.com/lhd951220) 翻译) +* [CSS Flexbox 中安全/不安全的对齐方式](https://juejin.im/post/5edf0333e51d457859656af0)([Baddyo](https://github.com/Baddyo) 翻译) +* [我是如何用 20 小时学会 Sass 的以及为什么你也应该这么做](https://juejin.im/post/5ede14f6e51d4578885ca8fc)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [我的 React 组件会渲染两次,我快疯了](https://juejin.im/post/6858508463274885134)([tanglie1993](https://github.com/tanglie1993/) 翻译) +* [鲜为人知的 GraphQL 特性](https://juejin.im/post/5edbaf2751882543281f73fc)([hansonfang](https://github.com/hansonfang) 翻译) +* [Object.freeze VS Object.seal —— JavaScript 数据不变性](https://juejin.im/post/5ed4b1b86fb9a047ce7c56ca)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [关于 let 和 const 的对比](https://juejin.im/post/5ed5ec4ae51d457b3e77e37c)([tanglie1993](https://github.com/tanglie1993/) 翻译) +* [Deno 会对 Node 造成威胁吗?](https://juejin.im/post/5ecf6f166fb9a047d77cbe35)([ZiXYu](https://github.com/ZiXYu) 翻译) +* [用 Python 写一个俄罗斯方块游戏](https://juejin.im/post/6844904183456350221)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [一个你不知道但可能会需要的 Vue 插件](https://juejin.im/post/5ed5c9e86fb9a047e02ef6eb)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [如何使用内联框架元素 IFrames 的沙箱属性提高安全性](https://juejin.im/post/5ee4a5fef265da76f9172940)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [移动端 WebKit 内核浏览器 100vh 问题的 CSS 修复方法](https://juejin.im/post/5ec87ef4e51d4578810b448d)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [使用 Deno 和 Oak 构建 CRUD API](https://juejin.im/post/5ed711086fb9a0479a801362)([lhd951220](https://github.com/lhd951220) 翻译) +* [重新思考前端:微前端](https://juejin.im/post/5ec882636fb9a047bb6a4618)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [看我如何把网站性能提升 422%](https://juejin.im/post/5ec793346fb9a0480659d6ef)([Baddyo](https://github.com/Baddyo) 翻译) +* [深入了解 React Fiber 内部实现](https://juejin.im/post/5ecb313d6fb9a0479a800294)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [ECMAScript 2020 新特性](https://juejin.im/post/5ec34ed96fb9a0437b76f638)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [用 JavaScript 中的蹦床函数实现安全递归](https://juejin.im/post/5ec3eec2f265da76d318644e)([Gesj-yean](https://github.com/Gesj-yean) 翻译) +* [纯 JavaScript 版本的 Lodash 数组 Filtering 和 Manipulation 方法](https://juejin.im/post/5ec614196fb9a047b46b14f3)([CoolRice](https://github.com/CoolRice) 翻译) +* [5 大 JavaScript 字符串操作库](https://juejin.im/post/5eba6becf265da7bb8773420)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [关于 JavaScript 中 Symbol 数据类型你需要了解的一切](https://juejin.im/post/5ebd353c5188256d9433b103)([cyz980908](https://github.com/cyz980908) 翻译) +* [深入浅出 array.fill() 函数](https://juejin.im/post/5ec783a251882543385d4693)([nia3y](https://github.com/nia3y) 翻译) +* [小品 JavaScript Proxy](https://juejin.im/post/5eb8f11de51d454dca710c1f)([Baddyo](https://github.com/Baddyo) 翻译) +* [11 个能让你的 App 像原生 App 的 Chrome API](https://juejin.im/post/5ebd3405e51d4534287a633b)([cyz980908](https://github.com/cyz980908) 翻译) +* [实际项目中关于 JavaScript 中 Promises 的最佳实践](https://juejin.im/post/5eb8faa76fb9a043877cdf88)([febrainqu](https://github.com/febrainqu) 翻译) +* [在 Node.js 中用 Puppeteer 实现网络爬虫](https://juejin.im/post/5eb25a806fb9a04356087809)([Baddyo](https://github.com/Baddyo) 翻译) +* [VueJS 3.0.0 Beta:那些令人兴奋的功能](https://juejin.im/post/5eafbf51f265da7b9005467b)([zhanght9527](https://github.com/zhanght9527) 翻译) +* [2020 十大 JavaScript 图像处理库](https://juejin.im/post/5eb0fe97e51d454def22679c)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [5 个优化技巧助你提高移动 Web 应用的用户留存率](https://juejin.im/post/5eb2a377f265da7bb563871f)([QinRoc](https://github.com/QinRoc) 翻译) +* [你可能会错过的 CSS 伪选择器](https://juejin.im/post/5eaea84f51882558dc24bc94)([nia3y](https://github.com/nia3y) 翻译) +* [在 JavaScript 中为什么 Math.max() 会比 Math.min() 小?](https://juejin.im/post/5ea2a2806fb9a03c5351a341)([zhanght9527](https://github.com/zhanght9527) 翻译) +* [编写类型安全的多态 React 组件(不会导致 TypeScript 崩溃)](https://juejin.im/post/5eb4327be51d454d980e3fec)([fireairforce](https://github.com/fireairforce) 翻译) +* [高性能 JavaScript 最佳实践](https://juejin.im/post/5e9e3b6ee51d4547134bead3)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [您知道 HTML 的键盘标签吗?](https://juejin.im/post/5e981dd2f265da47e64928db)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [为什么对象不变性很重要?](https://juejin.im/post/5e96703ef265da47ee3f64bb)([IAMSHENSH](https://github.com/IAMSHENSH) 翻译) +* [使用 JavaScript ES2020 中所有的 7 个新特性构建 App](https://juejin.im/post/5e9a685951882573834edc9e)([yvonneit](https://github.com/yvonneit) 翻译) +* [掌握 JavaScript 面试:什么是函数式编程](https://juejin.im/post/5e9a7394e51d4546d439826b)([fireairforce](https://github.com/fireairforce) 翻译) +* [JavaScript 中的 Generator 函数](https://juejin.im/post/5e9560def265da47e6492423)([nia3y](https://github.com/nia3y) 翻译) +* [JavaScript 风格元素](https://juejin.im/post/5e8ee9866fb9a03c546c3454)([febrainqu](https://github.com/febrainqu) 翻译) +* [2020 年排名前 6 位的 JavaScript 框架](https://juejin.im/post/5e8f33b951882573be11c546)([QinRoc](https://github.com/QinRoc) 翻译) +* [不变性之道](https://juejin.im/post/5e8b2e7451882573c32a15e6)([nia3y](https://github.com/nia3y) 翻译) +* [2020 年用各大前端框架构建的 RealWorld 应用对比](https://juejin.im/post/5e887c48f265da47f60ea6ce)([snowyYU](https://github.com/snowyYU) 翻译) +* [组合软件:书](https://juejin.im/post/5e88346cf265da47e159366a)([fireairforce](https://github.com/fireairforce) 翻译) +* [解决 web 应用程序中的内存泄漏问题](https://juejin.im/post/5e97b29851882573b21965a2)([febrainqu](https://github.com/febrainqu) 翻译) +* [掌握 JavaScript 面试:什么是纯函数?](https://juejin.im/post/5e7f3c3df265da7951664547)([nia3y](https://github.com/nia3y) 翻译) +* [Web 应用程序中的数据和 UI 分离](https://juejin.im/post/5e90831ee51d4560ea31fdf9)([fireairforce](https://github.com/fireairforce) 翻译) +* [JSON.stringify() 的 5 个秘密特性](https://juejin.im/post/5e842da76fb9a03c854610c7)([fireairforce](https://github.com/fireairforce) 翻译) +* [给 NodeJS 的 Logs 点颜色看看!](https://juejin.im/post/5e6f01b151882549422ef315)([cyz980908](https://github.com/cyz980908) 翻译) +* [前端代码中的 head 标签里都有些什么?](https://juejin.im/post/5e70b2606fb9a07cbf46d226)([cyz980908](https://github.com/cyz980908) 翻译) +* [如何在 JavaScript 中使用新特性“顶层 await”](https://juejin.im/post/5ec67516e51d45787161978e)([ssshooter](https://github.com/ssshooter) 翻译) +* [停止在任何地方使用 ===](https://juejin.im/post/5e5fb5e951882549522ac8a2)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [您可能不知道的原生 JavaScript 方法](https://juejin.im/post/5e4bc03cf265da572446685a)([cyz980908](https://github.com/cyz980908) 翻译) +* [在 Vue 中编写 SVG 图标组件](https://juejin.im/post/5e4fc62de51d4527110a85dd)([fireairforce](https://github.com/fireairforce) 翻译) +* [TypeScript 中带生成器的惰性管道](https://juejin.im/post/5eaa43616fb9a0432c4c8fc8)([febrainqu](https://github.com/febrainqu) 翻译) +* [理解 Service Worker 和缓存策略](https://juejin.im/post/5e60e0ce5188254919497644)([cyz980908](https://github.com/cyz980908) 翻译) +* [WebAssembly:带有代码示例的简单介绍](https://juejin.im/post/5e49394de51d452717262197)([fireairforce](https://github.com/fireairforce) 翻译) +* [使用 Nuxt (Vue.js)、Strapi 和 Apollo 构建博客](https://juejin.im/post/5e2a59ba6fb9a030026e8375)([vitoxli](https://github.com/vitoxli) 翻译) +* [在什么时候你需要使用 Web Workers?](https://juejin.im/post/5e290aaee51d451c8836284f)([weibinzhu](https://github.com/weibinzhu) 翻译) +* [5 个简单步骤为您的网站创建 Sitemap](https://juejin.im/post/5e22fc43f265da3e254c7555)([cyz980908](https://github.com/cyz980908) 翻译) +* [如何用 Nest.js、MongoDB 和 Vue.js 搭建一个博客](https://juejin.im/post/5e1820a951882526334a1d1f)([cyz980908](https://github.com/cyz980908) 翻译) +* [使用 Web Workers 优化事件监听器](https://juejin.im/post/5e241bb9f265da3e46090215)([vitoxli](https://github.com/vitoxli) 翻译) +* [论资历的级别](https://juejin.im/post/5e1549736fb9a0483c632bf8)([Baddyo](https://github.com/Baddyo) 翻译) +* [JavaScript 简史](https://juejin.im/post/5e158fe6e51d4541082c8143)([Pingren](https://github.com/Pingren) 翻译) +* [WebRTC 联手 Node.js:打造实时视频聊天应用](https://juejin.im/post/5e0ae59d5188253a5b3ccf74)([Baddyo](https://github.com/Baddyo) 翻译) +* [使用 JavaScript 编写 JSON 解析器](https://juejin.im/post/5e098728f265da33cd03c6c7)([Gavin-Gong](https://github.com/Gavin-Gong) 翻译) +* [为何 Svelte 杀不死 React](https://juejin.im/post/5e12aa81e51d4541162c9a3a)([Baddyo](https://github.com/Baddyo) 翻译) +* [使用 Redux Offline 和 Apollo 进行离线 GraphQL 查询](https://juejin.im/post/5e00a06f6fb9a0161a0c3d78)([vitoxli](https://github.com/vitoxli) 翻译) +* [我们为何抛弃 Redux 拥抱 MobX](https://juejin.im/post/5e068fa551882512657bc16c)([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) +* [将 GraphQL 概念可视化](https://juejin.im/post/5de480d7f265da05ce3b7368)([cyz980908](https://github.com/cyz980908) 翻译) +* [让字母“i”的点动起来的秘密](https://juejin.im/post/5dd7fe84e51d4523564243d5)([vitoxli](https://github.com/vitoxli) 翻译) +* [设计离线优先的网络应用](https://juejin.im/post/5dd608eef265da47f12cb018)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [如何将 SVG 图标用做 React 组件?](https://juejin.im/post/5df22bf7f265da33ea009225)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [JavaScript 的发布者/订阅者(Publisher/Subscriber)模式](https://juejin.im/post/5dbff49ff265da4d3761dd27)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Node.js 新特性将颠覆 AI、物联网等更多惊人领域](https://juejin.im/post/5dbb8d70f265da4d12067a3e)([Baddyo](https://github.com/Baddyo) 翻译) +* [趣味学习 CSS 布局 —— 第二部分:网格布局](https://juejin.im/post/5dafc45a51882555a8431266)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [TypeScript 3.7 Beta 版发布](https://juejin.im/post/5db2537d6fb9a0208b11f94f)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [什么将会替代 JavaScript 呢?](https://juejin.im/post/5daa897c6fb9a04e3902f4e6)([cyz980908](https://github.com/cyz980908) 翻译) +* [趣味学习 CSS 布局 —— 第一部分:弹性布局](https://juejin.im/post/5dafaca351882575446cd16e)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [CSS 小妙招:CSS 变量 —— 如何轻松创建一个🌞白色/🌑暗色主题](https://juejin.im/post/5da6c370e51d4524a0060385)([cyz980908](https://github.com/cyz980908) 翻译) +* [使用 `import()` 执行 JavaScript 代码](https://juejin.im/post/5dafc573e51d4524bb096393)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [现代脚本加载](https://juejin.im/post/5dafdcd45188256b030ad8cf)([w2ly](https://github.com/w2ly) 翻译) +* [如何编写全栈 JavaScript 应用](https://juejin.im/post/5d8ae3a56fb9a04e2902fbf6)([cyz980908](https://github.com/cyz980908) 翻译) +* [关于现代应用样式的探讨](https://juejin.im/post/5db93b67f265da4d417648a1)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [React 16 生命周期函数:如何以及何时使用它们](https://juejin.im/post/5d6dfefef265da0391353196)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [开发模式的工作原理是什么?](https://juejin.im/post/5d5e6964f265da0391351c59)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [小提示:伪元素是子元素,吧。](https://juejin.im/post/5d6271895188253a5635002e)([Baddyo](https://github.com/Baddyo) 翻译) +* [写给大家的代数效应入门](https://juejin.im/post/5dafe28b5188252e734f5376)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [使用 Typescript 使无效状态不可恢复](https://juejin.im/post/5d628841518825332d3fec3d)([solerji](https://github.com/solerji) 翻译) +* [愿未来没有 Webpack](https://juejin.im/post/5d4bcdb7e51d453b386a62c6)([Baddyo](https://github.com/Baddyo) 翻译) +* [如何用 JavaScript 编写扫雷游戏](https://juejin.im/post/5d6276cd6fb9a06ade111bb4)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [重建桌面端的 Slack 而不是重写](https://juejin.im/post/5d624db86fb9a06b2650a262)([cyz980908](https://github.com/cyz980908) 翻译) +* [我用 Javascript 实现 tic tac toe 游戏](https://juejin.im/post/5d627dc36fb9a06af05cbfdc)([lgh757079506](https://github.com/lgh757079506) 翻译) +* [Web 组件的问题](https://juejin.im/post/5d42aec96fb9a06ae94d1146)([Stevens1995](https://github.com/Stevens1995) 翻译) +* [逆向工程,如何在 JavaScript 中打造一个测试库](https://juejin.im/post/5d491b4af265da03ce39bfa4)([Usey95](https://github.com/Usey95) 翻译) +* [postMessage 很慢吗?](https://juejin.im/post/5d423cc4f265da03bf0f2159)([linxiaowu66](https://github.com/linxiaowu66) 翻译) +* [前端 vs 后端:哪一个适合你?](https://juejin.im/post/5d36b5e3f265da1bd3059a21)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [Google 的 Pagespeed 的工作原理:提升你的分数和搜索引擎排名](https://juejin.im/post/5d36903ce51d4510803ce491)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [从 Reddit 讨论中看到的 GraphQL 现状](https://juejin.im/post/5d380909e51d4510624f98a0)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [项目世界 — 在数字设计中实现上帝模式](https://juejin.im/post/5ce63193518825332978ef65)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [化 Markdown 为 HTML:用 Node.js 和 Express 搭建接口](https://juejin.im/post/5cdcc216e51d453a543f9e68)([Baddyo](https://github.com/Baddyo) 翻译) +* [2019 版 web 浏览器现状](https://juejin.im/post/5c89e69a51882536fe67b5b4)([xionglong58](https://github.com/xionglong58) 翻译) +* [为什么你的应用需要对各种尺寸屏幕做适配优化?](https://juejin.im/post/5c662023518825767633ab86)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [PWA 会取代原生移动应用吗?](https://juejin.im/post/5c627f76f265da2deb6a8828)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [构建未来的设计生态系统](https://juejin.im/post/5b992be8f265da0aa3591346)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [不要害怕 Rebase](https://juejin.im/post/5ab1bdbe518825556e5df5f8)([sqrthree](https://github.com/sqrthree) 翻译) +* [斐波那契数列中的偶数(Python vs. JavaScript)](https://juejin.im/post/5aaa61f8f265da237b21d258)([zephyrJS](https://github.com/zephyrJS) 翻译) +* [开始设计动画的九个步骤](https://juejin.im/post/5aa1f965f265da23994e1e1f)([reid3290](https://github.com/reid3290) 翻译) +* [也谈 React 16.3(.0-alpha)](https://juejin.im/entry/5a82ada16fb9a063317c54f2)([pot-code](https://github.com/pot-code) 翻译) +* [2018 前端性能优化清单 - 第 3 部分](https://juejin.im/post/5a702160f265da3e4b771109)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [2018 前端性能优化清单——第一部分](https://juejin.im/post/5a67e49df265da3e377c2d59)([tvChan](https://github.com/tvChan) 翻译) +* [2018 前端性能优化清单 - 第 2 部分](https://juejin.im/post/5a654e686fb9a01cb42c7894)([sakila1012](https://github.com/sakila1012) 翻译) +* [2018 前端性能优化清单 - 第 4 部分](https://juejin.im/post/5a62aa686fb9a01c91407a0b)([ParadeTo](https://github.com/ParadeTo) 翻译) +* [2018 年要学习的优秀 JavaScript 库与知识](https://juejin.im/post/5a4e23f0f265da3e377bce4f)([gy134340.com](http://gy134340.com/) 翻译) +* [CSV 注入:被人低估的风险](https://juejin.im/post/59eca3fef265da430b7a63c8)([mnikn](https://github.com/mnikn) 翻译) +* [iPhone X 网页设计](https://juejin.im/post/59e445816fb9a0450670ab82)([HydeSong](https://github.com/HydeSong) 翻译) +* [Web 设计准则](https://juejin.im/post/59c9c6f66fb9a00a4d53eec7)([xunge0613](https://github.com/xunge0613) 翻译) +* [原子设计:如何设计组件系统](https://juejin.im/post/59780066f265da6c3433872f)([H2O-2](https://github.com/H2O-2) 翻译) +* [通过阅读源码提高您的 JavaScript 水平](https://juejin.im/post/5d3c56c26fb9a07efd475414)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [作为初级开发人员,我没有学过的 7 个绝对真理](https://juejin.im/post/5d3d25dce51d457756536881)([cyz980908](https://github.com/cyz980908) 翻译) +* [仅使用 HTML 和 CSS 创建多级嵌套弹出式导航菜单](https://juejin.im/post/5d3c2852f265da1bac405fae)([yzw7489757](https://github.com/yzw7489757) 翻译) +* [CSS 开发必知必会的 16 个调试工具技巧](https://juejin.im/post/5d39d27cf265da1bc14b6f47)([Usey95](https://github.com/Usey95) 翻译) +* [多网站项目的 CSS 架构](https://juejin.im/post/5d3a58df5188251ce02ff228)([Baddyo](https://github.com/Baddyo) 翻译) +* [使用 Cypress 进行 React 应用的端到端测试](https://juejin.im/post/5d3702dcf265da1b961345d1)([Stevens1995](https://github.com/Stevens1995) 翻译) +* [CSS 思维模式](https://juejin.im/post/5d295380f265da1bab29dc13)([MarchYuanx](https://github.com/MarchYuanx) 翻译) +* [使用 SVG 和 Vue.Js 构建动态树图](https://juejin.im/post/5d2806fb518825121c0058d8)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [推广 PWA 安装的模式(移动端)](https://juejin.im/post/5d2746f1f265da1b7638cd1f)([xutaogit](https://github.com/xutaogit) 翻译) +* [Web 流式文字排版的现状](https://juejin.im/post/5d267d9de51d45773d4686ab)([Jenniferyingni](https://github.com/Jenniferyingni) 翻译) +* [自托管你的静态资源](https://juejin.im/post/5d258a77f265da1bca5202dc)([twang1727](https://github.com/twang1727) 翻译) +* [微前端:未来前端开发的新趋势 — 第四部分](https://juejin.im/post/5d23394ae51d45778f076db0)([Usey95](https://github.com/Usey95) 翻译) +* [微前端:未来前端开发的新趋势 — 第三部分](https://juejin.im/post/5d2755c4e51d45105e021360)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [微前端:未来前端开发的新趋势 — 第二部分](https://juejin.im/post/5d1a91c7e51d45775f516ab9)([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) +* [微前端:未来前端开发的新趋势 — 第一部分](https://juejin.im/post/5d0e367b6fb9a07ebf4b781a)([Jenniferyingni](https://github.com/Jenniferyingni) 翻译) +* [理解 React 中的高阶组件](https://juejin.im/post/5d1037966fb9a07ee4636de3)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [JavaScript 简明代码 — 最佳实践](https://juejin.im/post/5d07abcc6fb9a07eda031858)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [4 个 CSS 调色滤镜](https://juejin.im/post/5d039c36f265da1b60290096)([iceytea](https://github.com/iceytea) 翻译) +* [TypeScript 3.0: unknown 类型](https://juejin.im/post/5d04ac745188250a8b1fd203)([shixi-li](https://github.com/shixi-li) 翻译) +* [在 npm 上启用现在 JavaScript](https://juejin.im/post/5d15d64be51d4510a5033603)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [npm 的经济风云 —— 上半部分](https://juejin.im/post/5d146225e51d4556db694a4b)([Baddyo](https://github.com/Baddyo) 翻译) +* [JavaScript 中 JSON.stringify 的帕累托法则手册](https://juejin.im/post/5d11d8d4f265da1baf7cfa13)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [JavaScript 线性代数:使用 ThreeJS 制作线性变换动画](https://juejin.im/post/5d05dba86fb9a07ece67ce76)([lsvih](https://github.com/lsvih) 翻译) +* [线性代数:矩阵基本运算](https://juejin.im/post/5d107b00f265da1b67211a21)([lsvih](https://github.com/lsvih) 翻译) +* [为什么我们要切换到 gRPC](https://juejin.im/post/5cff855c518825612f412526)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [JavaScript 线性代数:向量](https://juejin.im/post/5cf61bf8e51d45775653674e)([lsvih](https://github.com/lsvih) 翻译) +* [JavaScript 线性代数:线性变换与矩阵](https://juejin.im/post/5cfdc1fb518825361d02aa41)([lsvih](https://github.com/lsvih) 翻译) +* [8 个有用的 JavaScript 技巧](https://juejin.im/post/5cff97276fb9a07ea420749f)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [将第三方动画库集成到项目中 —— 第 1 部分](https://juejin.im/post/5d037b655188252af2012702)([TUARAN](https://github.com/TUARAN) 翻译) +* [揭秘变量提升](https://juejin.im/post/5d026b71518825710d2b1f63)([Usey95](https://github.com/Usey95) 翻译) +* [ECMAScript 类 - 定义私有属性](https://juejin.im/post/5d006e406fb9a07ed22465de)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [支持 JavaScript 三元运算符](https://juejin.im/post/5cfb1d85f265da1b8f1ab359)([ZavierTang](https://github.com/ZavierTang) 翻译) +* [如何用 React Hooks 打造一个不到 100 行代码的异步表单校验库](https://juejin.im/post/5cf4e2c2f265da1b80202f83)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [13 种用于 DOM 操作的 JavaScript 方法](https://juejin.im/post/5cf65369f265da1bc94edad8)([fireairforce](https://github.com/fireairforce) 翻译) +* [深入理解图片和框架的原生懒加载功能](https://juejin.im/post/5cfb1e36e51d45554877a597)([Baddyo](https://github.com/Baddyo) 翻译) +* [用 React 制作线性代数教程示例:网格与箭头](https://juejin.im/post/5cefbc37f265da1bd260d129)([lsvih](https://github.com/lsvih) 翻译) +* [通过一些例子深入了解 JavaScript 的 Async 和 Await](https://juejin.im/post/5cec8a475188255816489878)([xionglong58](https://github.com/xionglong58) 翻译) +* [如何在 Google Play 应用商店中发布 PWA](https://juejin.im/post/5cefe63a6fb9a07ef3764dbe)([Baddyo](https://github.com/Baddyo) 翻译) +* [Redux vs. React 的 Context API](https://juejin.im/post/5cee43ad518825526b294a32)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [什么是 `this`?JavaScript 对象的内部工作原理](https://juejin.im/post/5cedfdbd5188252fbc37f920)([fireairforce](https://github.com/fireairforce) 翻译) +* [在项目中集成第三方动画库 —— 第二部分](https://juejin.im/post/5ce973a75188257ac625162b)([Baddyo](https://github.com/Baddyo) 翻译) +* [用 React 的钩子函数和调试工具提升应用性能](https://juejin.im/post/5ce974d76fb9a07f0420250e)([Baddyo](https://github.com/Baddyo) 翻译) +* [从原型图到成品:步步深入 CSS 布局](https://juejin.im/post/5cebb52651882530be7b16a4)([Baddyo](https://github.com/Baddyo) 翻译) +* [如何用 CSS Animations 实现图片滑动出文字](https://juejin.im/post/5ce8c9c26fb9a07ed0648d26)([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) +* [理解 WebView](https://juejin.im/post/5ce76ee4f265da1b8d15f700)([CoolRice](https://github.com/CoolRice) 翻译) +* [为什么 HTML 中复选框样式难写 — 本文给你答案](https://juejin.im/post/5ce65dd36fb9a07ef06f6cd2)([jilanlan](https://github.com/jilanlan) 翻译) +* [Elixir、Phoenix、Absinthe、GraphQL、React 和 Apollo:一次近乎疯狂的深度实践 —— 第二部分](https://juejin.im/post/5ce4dae36fb9a07ed524755d)([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) +* [在 Google Apps 脚本中使用 ES6 和 npm 模块](https://juejin.im/post/5ce350c3e51d4510727c7fd0)([xingqiwu55555](https://github.com/xingqiwu55555) 翻译) +* [Web 使用 CSS Shapes 的艺术设计](https://juejin.im/post/5cdba21051882568841f0f47)([xujiujiu](https://github.com/xujiujiu) 翻译) +* [理解 Vue.js 中的 Mixins](https://juejin.im/post/5cdeac5851882525f52cf662)([Reaper622](https://github.com/Reaper622) 翻译) +* [现代 JavaScript 开发中的设计模式](https://juejin.im/post/5cd62b9d6fb9a032321999ec)([HydeSong](https://github.com/HydeSong) 翻译) +* [完美的 Javascript 单元测试](https://juejin.im/post/5cd3ce3a6fb9a032484d7f73)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [Javascript Array.push 要比 Array.concat 快 945 倍!🤯🤔](https://juejin.im/post/5cd67fb9f265da037129bb64)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [Elixir、Phoenix、Absinthe、GraphQL、React 和 Apollo:一次近乎疯狂的深度实践 — 第一部分](https://juejin.im/post/5cce99d3518825405a198e52)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [ES6:理解参数默认值的实现细节](https://juejin.im/post/5cd0eab95188251b984d8abe)([Chorer](https://github.com/Chorer) 翻译) +* [使用 React 和 ImmutableJS 构建一个拖放布局构建器](https://juejin.im/post/5cccfa56f265da034c7038f3)([fireairforce](https://github.com/fireairforce) 翻译) +* [使用 closest() 函数获取正确的 DOM 元素](https://juejin.im/post/5cc811796fb9a0321c45e5e0)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [你认为“figure”怎么用?](https://juejin.im/post/5cc5ad456fb9a032233532df)([HydeSong](https://github.com/HydeSong) 翻译) +* [我多希望在我学习 React.js 之前就已经知晓这些小窍门](https://juejin.im/post/5cc53af6f265da038e54b2e6)([xionglong58](https://github.com/xionglong58) 翻译) +* [图片懒加载](https://juejin.im/post/5cc183436fb9a032363936c3)([nanjingboy](https://github.com/nanjingboy) 翻译) +* [创意运用 Console API!](https://juejin.im/post/5cc1517e5188252e7a0247dd)([wznonstop](https://github.com/wznonstop) 翻译) +* [构建世界上最快的会议网站](https://juejin.im/post/5cbdafce6fb9a031fe3bc5db)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [如何让你的 CSS Grid 布局有良好可读性](https://juejin.im/post/5cc156a2f265da034e7e9139)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [2019 前端工具调研](https://juejin.im/post/5cb800fce51d456e4514f550)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [对 React 组件进行单元测试](https://juejin.im/post/5cb9c62a6fb9a0688d2e4689)([xionglong58](https://github.com/xionglong58) 翻译) +* [使用 Shadow DOM 封装样式和结构](https://juejin.im/post/5cb3f5b95188251add7f11bc)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [你需要知道的 CSS 中所有 hyphenation 的使用](https://juejin.im/post/5cb2968df265da039f0f02d2)([Augustwuli](https://github.com/Augustwuli) 翻译) +* [图解 Map、Reduce 和 Filter 数组方法](https://juejin.im/post/5caf030d6fb9a068736d2d7c)([FrankXiong](https://github.com/FrankXiong) 翻译) +* [Web Components 的高级工具](https://juejin.im/post/5caef9f25188251b2b20b20b)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [使用网格布局实现响应式图片](https://juejin.im/post/5ca0ad80f265da30920059ae)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [写给大家看的 Cache-Control 指令配置](https://juejin.im/post/5c9d92506fb9a070f5067b3d)([sunui](https://github.com/sunui) 翻译) +* [从没有人告诉过我的 CSS 小知识](https://juejin.im/post/5ca2fa5551882543db10d489)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [React 中的调度](https://juejin.im/post/5ca347306fb9a05e4c0e69e5)([Xuyuey](https://github.com/Xuyuey) 翻译) +* [编写可以复用的 HTML 模板](https://juejin.im/post/5ca5b858e51d4524a918560f)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [2019 React Redux 完全指南](https://juejin.im/post/5cac8ccd6fb9a068530111c7)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [从 0 创建自定义元素](https://juejin.im/post/5cb2b5465188257abd66c354)([yzw7489757](https://github.com/yzw7489757) 翻译) +* [如何使用 Phaser 3 和 TypeScript 在浏览器中构建一个简单的游戏](https://juejin.im/post/5c91b77ee51d4574b27c9219)([iceytea](https://github.com/iceytea) 翻译) +* [深入 React Hook 系统的原理](https://juejin.im/post/5c99a75af265da60ef635898)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Vue.js 逐渐集成 第三方 JavaScript](https://juejin.im/post/5c8e5a776fb9a070d013ef71)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [监测与调试 Vue.js 的响应式系统:计算属性树(Computed Tree)](https://juejin.im/post/5c9ca62e5188251d80672b0d)([SHERlocked93](https://github.com/SHERlocked93) 翻译) +* [JavaScript 中为什么会有 Symbols 类型?](https://juejin.im/post/5c9b11e8518825529a0c78c9)([xionglong58](https://github.com/xionglong58) 翻译) +* [了解“多态”JSON 数据的性能问题](https://juejin.im/post/5c9982d16fb9a071061f09ce)([shixi-li](https://github.com/shixi-li) 翻译) +* [TypeScript 和 Babel:美丽的结合](https://juejin.im/post/5c8f4dcb5188252db02e404c)([zsky](https://github.com/zsky) 翻译) +* [Javascript 中的最长关键字序列长什么样子?](https://juejin.im/post/5c8efaf951882545e85c20e2)([xionglong58](https://github.com/xionglong58) 翻译) +* [我是怎么最终玩转了 Vue 的作用域插槽](https://juejin.im/post/5c8856e6e51d456b30397f31)([shixi-li](https://github.com/shixi-li) 翻译) +* [正在消失的小型网站](https://juejin.im/post/5c81de696fb9a049e702e6ac)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [避免那些可恶的 "cannot read property of undefined" 错误](https://juejin.im/post/5c810170e51d450a453fb48e)([Xcco](https://github.com/Xcco) 翻译) +* [JSX 的替代方案](https://juejin.im/post/5c807f73e51d453ba723d88d)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [选择 Grid 还是 Flex?](https://juejin.im/post/5c7ce781e51d4514913c5bc4)([Reaper622](https://github.com/Reaper622) 翻译) +* [Javascript - Generator-Yield/Next 和 Async-Await](https://juejin.im/post/5c7ca6d95188256ec63f289c)([iceytea](https://github.com/iceytea) 翻译) +* [TSLint in 2019](https://juejin.im/post/5c7c0451e51d4569951518fe)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [在 JSX 代码中可以加入 console.log 吗?](https://juejin.im/post/5c7b1a146fb9a049c8502caf)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [网速敏感的视频延迟加载方案](https://juejin.im/post/5c7b84356fb9a049ab0e5630)([SHERlocked93](https://github.com/SHERlocked93) 翻译) +* [浏览器中 CSS 支持指南](https://juejin.im/post/5c87a9006fb9a049e4138c7e)([huimingwu](https://github.com/huimingwu) 翻译) +* [为什么我用 JavaScript 来编写 CSS](https://juejin.im/post/5c8878b7f265da2deb6ae6f2)([Ivocin](https://github.com/Ivocin) 翻译) +* [Hooks 对 Vue 而言意味着什么](https://juejin.im/post/5c7784d5f265da2de713629c)([Ivocin](https://github.com/Ivocin) 翻译) +* [如何学习 CSS](https://juejin.im/post/5c74daaaf265da2d9d1cb774)([Mcskiller](https://github.com/Mcskiller) 翻译) +* [已经 2019 年了,我依然赤手空拳制作网站](https://juejin.im/post/5c74ad81f265da2da00ebaf6)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [模块化系统中的 event.stopPropagation ()](https://juejin.im/post/5c74a8bef265da2d881b331f)([Fengziyin1234](https://github.com/Fengziyin1234) 翻译) +* [HTML 一直是我们编译的目标 — 我们可以解决好它吗?](https://juejin.im/post/5c6ec3fc6fb9a049b07df54c)([CoderMing](https://github.com/CoderMing) 翻译) +* [2019 前端性能优化年度总结 — 第一部分](https://juejin.im/post/5c4418006fb9a049c043545e)([Hopsken](https://github.com/Hopsken) 翻译) +* [2019 前端性能优化年度总结 — 第二部分](https://juejin.im/post/5c47232b6fb9a049f8199ee2)([KarthusLorin](https://github.com/KarthusLorin) 翻译) +* [2019 前端性能优化年度总结 — 第三部分](https://juejin.im/post/5c5ccbefe51d457f95354a46)([Starriers](https://github.com/Starriers) 翻译) +* [2019 前端性能优化年度总结 — 第四部分](https://juejin.im/post/5c56345951882524b77b9f20)([Ivocin](https://github.com/Ivocin) 翻译) +* [2019 前端性能优化年度总结 — 第五部分](https://juejin.im/post/5c60ed6cf265da2dd4274724)([wznonstop](https://github.com/wznonstop) 翻译) +* [2019 前端性能优化年度总结 — 第六部分](https://juejin.im/post/5c6167f6f265da2ddf7866ec)([CoolRice](https://github.com/CoolRice) 翻译) +* [Vue.js  —  注意事项和技巧](https://juejin.im/post/5c5c28cf518825627d37060a)([xingqiwu55555](https://github.com/xingqiwu55555) 翻译) +* [5 个可以立刻在你的 Ionic App 中用上的动画包](https://juejin.im/post/5c517544f265da613b702848)([lsvih](https://github.com/lsvih) 翻译) +* [为什么我不再使用 export default 来导出模块](https://juejin.im/post/5c4acd646fb9a049b5072f0e)([KarthusLorin](https://github.com/KarthusLorin) 翻译) +* [使用 Recompose 来构建高阶组件](https://juejin.im/post/5c484a43e51d452ec621b6a9)([SHERlocked93](https://github.com/SHERlocked93) 翻译) +* [使用 Proxy 来观测 Javascript 中的类](https://juejin.im/post/5c484b76e51d45522b4f5f7d)([SHERlocked93](https://github.com/SHERlocked93) 翻译) +* [Rust 2018 已经发布...但它是到底什么呢?](https://juejin.im/post/5c47f714e51d4551b7481c8c)([CoolRice](https://github.com/CoolRice) 翻译) +* [一文带你看完 2018 年浏览器之争的最新进展](https://juejin.im/post/5c45a392f265da61483be57c)([HumesFork](https://github.com/HumesFork) 翻译) +* [💅 styled-components 背后的魔力](https://juejin.im/post/5c6d3a32e51d451804732248)([WangLeto](https://github.com/WangLeto) 翻译) +* [资助 ESLint 的未来](https://juejin.im/post/5c6cc48551882562654ac2c0)([EdmondWang](https://github.com/EdmondWang) 翻译) +* [Web 开发者需要了解的基础色彩理论](https://juejin.im/post/5c6caee26fb9a049df24a4df)([lsvih](https://github.com/lsvih) 翻译) +* [X 为啥不是 hook?](https://juejin.im/post/5c6ca856f265da2dce1f3af9)([Jerry-FD](https://github.com/Jerry-FD) 翻译) +* [关于 Yarn 和 npm 你所需要知道的一切](https://juejin.im/post/5c64e06ce51d457fce014370)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [谷歌迈出了消除 URL 的第一步](https://juejin.im/post/5c643cb7e51d450dfc6eec1e)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [使用智能 CSS 基于用户滚动位置应用样式](https://juejin.im/post/5c67817fe51d45082e13300c)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [设计一个页面原则上应该指的是编写 HTML 和 CSS](https://juejin.im/post/5c6425d6e51d454ba22ba414)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [如何利用 Webpack4 为你的 React.js 开发提速](https://juejin.im/post/5c669f14e51d457f093b1767)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [Vue Router 实战手册](https://juejin.im/post/5c62ab05f265da2da83555a0)([xutaogit](https://github.com/xutaogit) 翻译) +* [十件你不知道的关于 WebPageTest.org 的事](https://juejin.im/post/5c679531f265da2dc45367ab)([lsvih](https://github.com/lsvih) 翻译) +* [2019 CSS 新属性“连字符”初探](https://juejin.im/post/5c612cfee51d4501515c8edf)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [Webpack 4 的故事以及如何用正确的方式去最终配置它【更新版】](https://juejin.im/post/5c612ba351882562ea721b39)([iceytea](https://github.com/iceytea) 翻译) +* [我们采用 GraphQL 技术的经验:营销技术活动](https://juejin.im/post/5c4522566fb9a049d2365cd6)([xutaogit](https://github.com/xutaogit) 翻译) +* [通过垃圾回收机制理解 JavaScript 内存管理](https://juejin.im/post/5c4409fbf265da616f703d5a)([wuzhengyan2015](https://github.com/wuzhengyan2015) 翻译) +* [新愿景: 未来的程序应用平台](https://juejin.im/post/5c2cce475188256a272ac4d6)([skychenbo](https://github.com/skychenbo) 翻译) +* [2018 前端全面回顾](https://juejin.im/post/5c3eba70e51d4542253fd489)([Ivocin](https://github.com/Ivocin) 翻译) +* [Lenses:可组合函数式编程的 Getter 和 Setter](https://juejin.im/post/5c3d35f8f265da611e4de068)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [2019 年值得学习的顶级 JavaScript 框架与主题](https://juejin.im/post/5c3cbb91e51d4550932771ce)([ElizurHz](https://github.com/ElizurHz) 翻译) +* [CSS Shapes 简介](https://juejin.im/post/5c3740efe51d455211594993)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [理解异步 JavaScript](https://juejin.im/post/5c304097e51d45520c3b14cd)([H246802](https://github.com/H246802) 翻译) +* [使用 Stripe, Vue.js 和 Flask 接受付款](https://juejin.im/post/5c3bed42f265da615064aacb)([Mcskiller](https://github.com/Mcskiller) 翻译) +* [渐进增强的含义及意义](https://juejin.im/post/5c2f42556fb9a049f57148ca)([RicardoCao-Biker](https://github.com/RicardoCao-Biker) 翻译) +* [Transducers: JavaScript 中高效的数据处理 pipeline](https://juejin.im/post/5c337b50f265da61746501bf)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [为什么我放弃了 React 而转向 Vue](https://juejin.im/post/5c2c27096fb9a049f66c3672)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [创建并发布一个小而美的 npm 包](https://juejin.im/post/5c26c1b65188252dcb312ad6)([calpa](https://github.com/calpa) 翻译) +* [2019 年你应该要知道的 11 个 React UI 组件库](https://juejin.im/post/5c260f13e51d45473a5c07a4)([ElizurHz](https://github.com/ElizurHz) 翻译) +* [5 款工具助力 React 快速开发](https://juejin.im/post/5c242e3f51882573d90678ad)([Ivocin](https://github.com/Ivocin) 翻译) +* [React 路由和 React 组件的爱恨情仇](https://juejin.im/post/5c2217abe51d4570f1453cad)([Augustwuli](https://github.com/Augustwuli) 翻译) +* [误解 ES6 模块,升级 Babel 的一个解决方案(泪奔)](https://juejin.im/post/5c223f4ce51d452626296b5d)([Starriers](https://github.com/Starriers) 翻译) +* [继承 JavaScript 类中的静态属性](https://juejin.im/post/5c2217fc6fb9a049b348039d)([Augustwuli](https://github.com/Augustwuli) 翻译) +* [用 Flask 和 Vue.js 开发一个单页面应用](https://juejin.im/post/5c1f7289f265da612e28a214)([Mcskiller](https://github.com/Mcskiller) 翻译) +* [用 React 和 Node.js 实现受保护的路由和权限验证](https://juejin.im/post/5c1cdaaa6fb9a049aa6f0f8b)([ElizurHz](https://github.com/ElizurHz) 翻译) +* [理解 React Render Props 和 HOC](https://juejin.im/post/5c1f8ded6fb9a049b506ce94)([wuzhengyan2015](https://github.com/wuzhengyan2015) 翻译) +* [被污染的 npm 包:event-stream](https://juejin.im/post/5c1b02dcf265da6166246c25)([CoderMing](https://github.com/CoderMing) 翻译) +* [用 Shadow DOM v1 和 Custom Elements v1 实现一个原生 Web Component](https://juejin.im/post/5c1a401b6fb9a049c042fa07)([newraina](https://github.com/newraina) 翻译) +* [柯里化与函数组合](https://juejin.im/post/5c1a0d516fb9a049d05daee9)([CoolRice](https://github.com/CoolRice) 翻译) +* [被遗忘的面向对象编程史(软件编写)(第十六部分)](https://juejin.im/post/5c19d249f265da61776be9b9)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [使用 GRAPHQL 构建项目的回顾](https://juejin.im/post/5c18ba5bf265da61715e44ed)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [怎么做:React Native 网页应用,一场开心的挣扎](https://juejin.im/post/5c13219d6fb9a049e82b65c3)([weibinzhu](https://github.com/weibinzhu) 翻译) +* [使用 Capacitor 和 Vue.js 构建移动应用](https://juejin.im/post/5c0f0a9e518825428c5704d8)([nanjingboy](https://github.com/nanjingboy) 翻译) +* [程序构建系列教程简介](https://juejin.im/post/5c0dd214518825444758453a)([xutaogit](https://github.com/xutaogit) 翻译) +* [函数式编程:抽象与组合](https://juejin.im/post/5bfb989be51d45033627989a)([Xekin-FE](https://github.com/Xekin-FE) 翻译) +* [你不知道的 console 命令](https://juejin.im/post/5bf64218e51d45194266acb7)([Pomelo1213](https://github.com/Pomelo1213) 翻译) +* [理解 JavaScript 中的 undefined](https://juejin.im/post/5bf57e8ef265da612c5d8439)([yanyixin](https://github.com/yanyixin) 翻译) +* [Javascript: call(), apply() 和 bind()](https://juejin.im/post/5bee3adef265da614c4c612e)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [关于 Angular 的变化检测,你需要知道的一切](https://juejin.im/post/5bf405f851882530d44b400a)([tian-li](https://github.com/tian-li) 翻译) +* [我们是怎样把 Carousell 的移动 Web 体验搞快了 3 倍的?](https://juejin.im/post/5bee858ae51d45710c6a5500)([noahziheng](https://github.com/noahziheng) 翻译) +* [React 是如何区分 Class 和 Function 的?](https://juejin.im/post/5c088c4ce51d451d8b7bd8de)([tonghuashuo](https://github.com/tonghuashuo) 翻译) +* [写给 React 开发者的自定义元素指南](https://juejin.im/post/5c0873a8e51d451de96890dc)([CoolRice](https://github.com/CoolRice) 翻译) +* [Netflix 的 Web 性能案例研究](https://juejin.im/post/5bf0c5d56fb9a049ec6aa902)([CoolRice](https://github.com/CoolRice) 翻译) +* [揭开 React Hooks 的神秘面纱:数组解构融成魔法](https://juejin.im/post/5bebd1bbe51d4561ce39a23b)([Xekin-FE](https://github.com/Xekin-FE) 翻译) +* [理解 React 钩子(Hooks)](https://juejin.im/post/5be98a87f265da616e4bf8a4)([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) +* [Hook 介绍 — React 系列教程 Part 1](https://juejin.im/post/5be3e56ff265da613572117f)([xutaogit](https://github.com/xutaogit) 翻译) +* [GitHub Actions 介绍,了解一下?](https://juejin.im/post/5be191736fb9a049de6cd463)([CoolRice](https://github.com/CoolRice) 翻译) +* [Google 工程师提升网页性能的新策略:空闲到紧急](https://juejin.im/post/5bdec712e51d4505525b0fba)([Ivocin](https://github.com/Ivocin) 翻译) +* [深入理解 React 高阶组件](https://juejin.im/entry/5bdd226cf265da616f6f6cce)([CoderMing](https://github.com/CoderMing) 翻译) +* [如何停止使用 console.log() 并开始使用浏览器调试代码](https://juejin.im/post/5bd7cde4f265da0a96251de3)([Augustwuli](https://github.com/Augustwuli) 翻译) +* [通过 Lighthouse 了解 JavaScript 性能](https://juejin.im/post/5bd5cfcbe51d456d4453572e)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [源代码映射(Source Map)简介](https://juejin.im/post/5bd65e1ae51d457aa071feaa)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [你需要知道的所有 Flexbox 排列方式](https://juejin.im/post/5bc728f2f265da0aef4e3f6d)([CoderMing](https://github.com/CoderMing) 翻译) +* [从 2010 到 2018,你不知道的关于网页滚动和用户注意力的变化](https://juejin.im/post/5bcf0a38f265da0afb33834d)([Ivocin](https://github.com/Ivocin) 翻译) +* [使用 JavaScript 和网络信息 API 实现自适应服务](https://juejin.im/post/5bc73482e51d450ea3639c7c)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [以面试官的角度来看 React 工作面试](https://juejin.im/post/5bca74cfe51d450e9163351b)([CoolRice](https://github.com/CoolRice) 翻译) +* [开启性能预算](https://juejin.im/post/5bd40d3151882529642b24c8)([xutaogit](https://github.com/xutaogit) 翻译) +* [现代浏览器内部揭秘(第四部分)](https://juejin.im/post/5bc95247e51d450e40072e49)([ThomasWhyne](https://github.com/ThomasWhyne) 翻译) +* [Immer 下的不可突变数据和 React 的 setState](https://juejin.im/post/5bc06798e51d453eb93daa80)([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) +* [使 WebAssembly 更快:Firefox 的新流式和分层编译器](https://juejin.im/post/5bc70955e51d450e98754dad)([xutaogit](https://github.com/xutaogit) 翻译) +* [为数字优先新闻编辑室开发文本编辑器](https://juejin.im/post/5bc2f8a86fb9a05d151ccba8)([diliburong](https://github.com/diliburong) 翻译) +* [现代浏览器内部揭秘(第二部分)](https://juejin.im/post/5bc293cf6fb9a05ce95c8468)([CoolRice](https://github.com/CoolRice) 翻译) +* [现代浏览器内部揭秘(第三部分)](https://juejin.im/post/5bc29d56e51d450e9e4466cc)([ssshooter](https://github.com/ssshooter) 翻译) +* [五个小技巧让你写出更好的 JavaScript 条件语句](https://juejin.im/post/5bb9e3085188255c352d7326)([Hopsken](https://github.com/Hopsken) 翻译) +* [我在阅读 MDN 时发现的 3 个 Input 元素属性](https://juejin.im/post/5bbc6f035188255c5d56b160)([ssshooter](https://github.com/ssshooter) 翻译) +* [当你创建 Flexbox 布局时,都发生了什么](https://juejin.im/post/5bb9740de51d450e782647ed)([linxuesia](https://github.com/linxuesia) 翻译) +* [如何使用 JavaScript ES6 有条件地构造对象](https://juejin.im/post/5bb47db76fb9a05d071953ea)([ssshooter](https://github.com/ssshooter) 翻译) +* [什么是模块化 CSS?](https://juejin.im/post/5bb6c5195188255c9e02e6f3)([ssshooter](https://github.com/ssshooter) 翻译) +* [以申请大学流程来解释 JavaScript 的 filter](https://juejin.im/post/5b9f09685188255c5e66d60c)([calpa](https://github.com/calpa) 翻译) +* [探索 SMACSS:可扩展的模块化 CSS 框架](https://juejin.im/post/5ba234c85188255c38535a47)([Park-ma](https://github.com/Park-ma) 翻译) +* [this 到底指向什么 — 理解 JavaScript 中的 this、call、apply 和 bind](https://juejin.im/post/5b9f176b6fb9a05d3827d03f)([CoolRice](https://github.com/CoolRice) 翻译) +* [理解 JavaScript 中的执行上下文和执行栈](https://juejin.im/post/5ba32171f265da0ab719a6d7)([CoolRice](https://github.com/CoolRice) 翻译) +* [React Profiler 介绍](https://juejin.im/post/5ba0f8e4f265da0ab915bcf2)([CoderMing](https://github.com/CoderMing) 翻译) +* [./dogs.html 和 /dogs.html 间有什么区别?](https://juejin.im/post/5ba7a5dfe51d450e4a1bc136)([shery](https://github.com/shery) 翻译) +* [现代浏览器内部揭秘(第一部分)](https://juejin.im/post/5b9b0932e51d450e9059c16a)([Colafornia](https://github.com/Colafornia) 翻译) +* [JAVASCRIPT 日期权威指南](https://juejin.im/post/5b9b4b7bf265da0af6099ed8)([CoderMing](https://github.com/CoderMing) 翻译) +* [用 API 请求制作赏心悦目的 UX](https://juejin.im/post/5b992d13e51d450e894de541)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [如何使用原生 JavaScript 构建简单的 Chrome 扩展程序](https://juejin.im/post/5b98a58b6fb9a05cec4d92e0)([shery](https://github.com/shery) 翻译) +* [CSS 变量和 JavaScript 让应用支持动态主题 🎨](https://juejin.im/post/5b9528de6fb9a05cf3710e00)([CoolRice](https://github.com/CoolRice) 翻译) +* [JavaScript 2018 中即将迎来的新功能:异步生成器及更好的正则表达式](https://juejin.im/post/5b95be51f265da0adc18ac08)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [在 JavaScript 中 为什么你应当使用 map 和 filter 来替代 forEach](https://juejin.im/post/5b95c4fe5188255c402ae6fb)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [函数式 JavaScript 编程的简短介绍](https://juejin.im/post/5b8f97135188255c4a70f999)([Zheng7426](https://github.com/Zheng7426) 翻译) +* [简单的响应式现代 css 网格布局](https://juejin.im/post/5b8b4ddef265da436d7e594d)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [使用原生 JavaScript 构建状态管理系统](https://juejin.im/post/5b763528e51d45559e3a5b64)([shery](https://github.com/shery) 翻译) +* [布局的下一次革新会是怎样的](https://juejin.im/post/5b85586ce51d4538c77a9cc1)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [如何使用纯函数式 JavaScript 处理脏副作用](https://juejin.im/post/5b82bdb351882542e241ed32)([Gavin-Gong](https://github.com/Gavin-Gong) 翻译) +* [2018 年七个通过脑电图分析实现“读心术”的 Javascript 库](https://juejin.im/post/5b7f63e651882542c20f22f0)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [一行 JavaScript 代码竟然让 FT.com 网站慢了十倍](https://juejin.im/post/5b7bb6dfe51d4538bf55aa5f)([IridescentMia](https://github.com/IridescentMia) 翻译) +* [SpaceAce 了解一下,一个新的前端状态管理库](https://juejin.im/post/5b7653c96fb9a009c72cb7af)([noahziheng](https://github.com/noahziheng) 翻译) +* [2018 来谈谈 Web 组件](https://juejin.im/post/5b780a98e51d4538980bf5cf)([weberpan](https://github.com/weberpan) 翻译) +* [如何提升设计到开发的协作效率](https://juejin.im/post/5b83609de51d4538c210a957)([meterscao](https://github.com/meterscao) 翻译) +* [优化 MP4 视频以获得更快的流传输速度](https://juejin.im/post/5b72bed8e51d45661e00f693)([HaoChuan9421](https://github.com/HaoChuan9421) 翻译) +* [如何向带有插槽的 React 组件传递多个 Children](https://juejin.im/post/5b72935a6fb9a009724b3e4e)([Zheng7426](https://github.com/Zheng7426) 翻译) +* [用 React 和 Vue 创建了两个完全相同的应用后,发现了这些差异](https://juejin.im/post/5b63f50a5188253128337110)([jonjia](https://github.com/jonjia) 翻译) +* [让我们一起解决“this”难题  —  第二部分](https://juejin.im/post/5b6915cce51d4519962f0ca7)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [让我们一起解决“this”难题 — 第一部分](https://juejin.im/post/5b680d8b518825196730a00f)([doctype233](https://github.com/doctype233) 翻译) +* [设计 React 组件 API](https://juejin.im/post/5b545f0b6fb9a04fc93748ba)([](https://github.com/) 翻译) +* [关于 React Motion 的简要介绍](https://juejin.im/post/5b48061551882519790c77f3)([doctype233](https://github.com/doctype233) 翻译) +* [无头渲染组件](https://juejin.im/post/5b5e919f51882519d3467f41)([](https://github.com/) 翻译) +* [用 30 分钟建立一个网站的方式来学习 Bootstrap 4](https://juejin.im/post/5b5eb7b2e51d451989055d9d)([Zheng7426](https://github.com/Zheng7426) 翻译) +* [使用 Web Beacon API 记录活动](https://juejin.im/post/5b694b5de51d4519700fa56a)([elliott-zhao](https://github.com/elliott-zhao) 翻译) +* [ECMAScript 修饰器微指南](https://juejin.im/post/5b543d8af265da0f4a4e711f)([jonjia](https://github.com/jonjia) 翻译) +* [由 CSS 网格系统的创造者们所讲述的故事](https://juejin.im/post/5b503d9ef265da0f504a518e)([Tivcrmn](https://github.com/Tivcrmn) 翻译) +* [Javascript(ES6)Generator 入门](https://juejin.im/post/5b4c22aa6fb9a04faf479be1)([ssshooter](https://github.com/ssshooter) 翻译) +* [论 Rust 和 WebAssembly 对源码地址索引的极限优化](https://juejin.im/post/5b51948a5188251ac771c064)([D-kylin](https://github.com/D-kylin) 翻译) +* [单元素组件模式简介](https://juejin.im/post/5b445d79e51d4519596b5f87)([jonjia](https://github.com/jonjia) 翻译) +* [React 实现条件渲染的多种方式和性能考量](https://juejin.im/post/5b3e34905188251b1f223ad3)([IveHD](https://github.com/IveHD) 翻译) +* [2018 年,如何选择最好的静态站点生成器](https://juejin.im/post/5b47079bf265da0faa3655be)([ssshooter](https://github.com/ssshooter) 翻译) +* [将项目迁移到 Yarn 然后又迁回到 npm](https://juejin.im/post/5b3b5735f265da0f894b443d)([zhongdeming428](https://github.com/zhongdeming428) 翻译) +* [或许你并不需要 Rust 和 WASM 来提升 JS 的执行效率 — 第二部分](https://juejin.im/post/5b357c20f265da595f0d3f91)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [怎样使用简单的三角函数来创建更好的加载动画](https://juejin.im/post/5b33055f518825748871c590)([zhongdeming428](https://github.com/zhongdeming428) 翻译) +* [WOFF文件格式 1.0](https://github.com/xitu/gold-miner/blob/master/TODO1/recommendation-woff-2012-12-13.md)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [Vue.js 还是 React?你会选择哪一个?为什么?](https://juejin.im/post/5b25b3a16fb9a00e70686180)([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) +* [或许你并不需要 Rust 和 WASM 来提升 JS 的执行效率 — 第一部分](https://juejin.im/post/5b24cf7e51882574c2652f61)([shery15](https://github.com/shery15) 翻译) +* [从零开始,在 Redux 中构建时间旅行式调试](https://juejin.im/post/5b24c0bce51d4558ba1a5584)([weberpan](https://github.com/weberpan) 翻译) +* [为何前端开发如此不稳定](https://juejin.im/post/5b1f2f1ae51d4506894983ae)([Colafornia](https://github.com/Colafornia) 翻译) +* [前端开发框架实战对比(2018年更新)](https://juejin.im/post/5b20a5996fb9a01e6b2c21ec)([geniusq1981](https://github.com/geniusq1981) 翻译) +* [我们距离 Babel 7.0 发布很近了。这里是所有我们一直在做的很酷的事情。](https://juejin.im/post/5b174f3e518825139b18e1f0)([xueshuai](https://github.com/xueshuai) 翻译) +* [新的 CSS 特性正在改变网页设计](https://juejin.im/post/5b0cae8c6fb9a009de14c833)([sophiayang1997](https://github.com/sophiayang1997) 翻译) +* [一个简单的 ES6 Promises 指南](https://juejin.im/post/5b0eb3b1f265da08f31e770a)([sophiayang1997](https://github.com/sophiayang1997) 翻译) +* [JavaScript 是如何工作的:Service Worker 的生命周期与使用场景](https://juejin.im/post/5b14c1d86fb9a01e700ff2f2)([talisk](https://github.com/talisk) 翻译) +* [使用 styled-components 的 React 服务器端渲染极简指南](https://juejin.im/post/5b0f9a4c51882515791502d0)([elliott-zhao](https://github.com/elliott-zhao) 翻译) +* [什么是 JavaScript 生成器?如何使用生成器?](https://juejin.im/post/5b14faf2f265da6e4d5af3b9)([lsvih](https://github.com/lsvih) 翻译) +* [为什么 VueX 是前端与 API 之间的完美接口](https://juejin.im/post/5b14d1bd6fb9a01e4508bfc1)([zhmhhu](https://github.com/zhmhhu) 翻译) +* [Font-size:一个出乎意料复杂的 CSS 属性](https://juejin.im/post/5b1292355188251377116617)([zephyrJS](https://github.com/zephyrJS) 翻译) +* [JavaScript 是如何工作的:深入网络层 + 如何优化性能和安全](https://juejin.im/post/5b02ae48518825429d1f9aff)([Hopsken](https://github.com/Hopsken) 翻译) +* [JavaScript 是如何工作的:对比 WebAssembly + 为什么在某些场景下它比 JavaScript 更合适](https://juejin.im/post/5b0526e751882507c36d0167)([stormluke](https://github.com/stormluke) 翻译) +* [怎样更好地使用 Vue:我在新工作中遇到的一些问题清单](https://juejin.im/post/5b0a36366fb9a07a9c04aca2)([sophiayang1997](https://github.com/sophiayang1997) 翻译) +* [如何在 5 分钟之内写出一个不错的 loading 界面](https://juejin.im/post/5af54bbb518825426d2d2e63)([whuzxq](https://github.com/whuzxq) 翻译) +* [使用 Puppeteer 和 Jest 测试你的 React 应用](https://juejin.im/post/5af90988518825426a1fcc2e)([jonjia](https://github.com/jonjia) 翻译) +* [这就是为什么我们需要在 React 的类组件中为事件处理程序绑定 this](https://juejin.im/post/5afa6e2f6fb9a07aa2137f51)([whuzxq](https://github.com/whuzxq) 翻译) +* [JavaScript 是如何工作的:CSS 和 JS 动画背后的原理 + 如何优化性能](https://juejin.im/post/5afaea6b6fb9a07aa34a6a74)([NoName4Me](https://github.com/NoName4Me) 翻译) +* [⚛ React 状态管理工具博物馆](https://juejin.im/post/5afd18cf6fb9a07acb3d13ac)([jonjia](https://github.com/jonjia) 翻译) +* [可用但最不常见的 HTML5 标签](https://juejin.im/post/5b0026e8f265da0b8c253c2a)([lsvih](https://github.com/lsvih) 翻译) +* [JavaScript 是如何工作的:Web 推送通知的机制](https://juejin.im/post/5b002766518825429d1f90bc)([Starriers](https://github.com/Starriers) 翻译) +* [漫画深入浅出 ES 模块](https://juejin.im/post/5aea6ae7f265da0ba4699e0a)([stormluke](https://github.com/stormluke) 翻译) +* [JavaScript 是如何运作的:用 MutationObserver 追踪 DOM 的变化](https://juejin.im/post/5aee720df265da0b8f627173)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [深入浅出 JavaScript 关键词 — this](https://juejin.im/post/5aefe76e6fb9a07abc29d4a1)([weberpan](https://github.com/weberpan) 翻译) +* [设计大型 JavaScript 应用程序](https://juejin.im/post/5aedd93b51882567244ddfc0)([shery15](https://github.com/shery15) 翻译) +* [如何写出更好的 React 代码](https://juejin.im/post/5ae975d26fb9a07aa92588b7)([jonjia](https://github.com/jonjia) 翻译) +* [使用 React, Redux, and SVG 开发游戏 - 第3部分](https://juejin.im/post/5af2a4d06fb9a07aa114302b)([xueshuai](https://github.com/xueshuai) 翻译) +* [那些好玩却没有被 ECMAScript 2017 采纳的提案](https://juejin.im/post/5ae920fd51882567127852e7)([Colafornia](https://github.com/Colafornia) 翻译) +* [Web 应用的未来:Heroku vs Docker](https://juejin.im/post/5ae7dae5518825670f7ba367)([Hopsken](https://github.com/Hopsken) 翻译) +* [互联汽车是什么以及如何开发用于它的应用?](https://juejin.im/post/5ad419cb6fb9a028d9379e57)([jonjia](https://github.com/jonjia) 翻译) +* [React 中的 Immutability:可变对象并没有什么问题](https://juejin.im/post/5ad807b36fb9a045d639ad18)([jonjia](https://github.com/jonjia) 翻译) +* [如何调试前端:优化网络资源](https://juejin.im/post/5ade828751882567137dd2da)([stormluke](https://github.com/stormluke) 翻译) +* [优化 WEBPACK 以更快地构建 REACT](https://juejin.im/post/5ae003d86fb9a07a9e4ce25d)([Starriers](https://github.com/Starriers) 翻译) +* [深入浅出 SVG](https://juejin.im/post/5ad84f296fb9a045e8011be1)([Starriers](https://github.com/Starriers) 翻译) +* [[1] + [2] - [3] === 9!? 类型转换深入研究](https://juejin.im/post/5ad5af7251882555894a5054)([sunhaokk](https://github.com/sunhaokk) 翻译) +* [使用 React、Redux 和 SVG 开发游戏 - Part 2](https://juejin.im/post/5ad373fef265da2395316f27)([zephyrJS](https://github.com/zephyrJS) 翻译) +* [JavaScript 是如何工作的:渲染引擎和性能优化技巧](https://juejin.im/post/5ad5986bf265da23994f06ab)([stormluke](https://github.com/stormluke) 翻译) +* [React 的内联函数和性能](https://juejin.im/post/5ac20b5ff265da23945fa6bd)([wznonstop](https://github.com/wznonstop) 翻译) +* [Redux-Saga 为你打 call:管理你的异步 action (上)](https://juejin.im/post/5ac1cb9d6fb9a028cf32a046)([jonjia](https://github.com/jonjia) 翻译) +* [JavaScript 单元测试框架:Jasmine, Mocha, AVA, Tape 和 Jest 的比较](https://juejin.im/post/5acc721a6fb9a028b77b23c9)([ClarenceC](https://github.com/ClarenceC) 翻译) +* [写给前端开发者的 GraphQL 指南](https://juejin.im/post/5ac09072518825558c479215)([ellcyyang](https://github.com/ellcyyang) 翻译) +* [提高 10 倍性能:优化静态网站](https://juejin.im/post/5ac9e430f265da2392369ec0)([Starriers](https://github.com/Starriers) 翻译) +* [React & Redux 顶级开发伴侣](https://juejin.im/post/5acae8dc6fb9a028c06b1c4c)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [单向用户界面架构问题研究](https://juejin.im/post/5aca38c5518825482e392c00)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [How to NOT React:React 中常见的反模式与陷阱](https://juejin.im/post/5acad683f265da23953146cd)([MechanicianW](https://github.com/MechanicianW) 翻译) +* [关于 SPA 你需要掌握的 4 层](https://juejin.im/post/5ac9ae935188255caf067974)([zwwill](https://github.com/zwwill) 翻译) +* [拖放库中 React 性能的优化](https://juejin.im/post/5ac31b096fb9a028bc2dedfc)([hexianga](https://github.com/hexianga) 翻译) +* [热爱 JavaScript,但是讨厌 CSS?](https://juejin.im/post/5aba0d37518825556a72708a)([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) +* [使用 React、Redux、SVG 开发游戏 - Part 1](https://juejin.im/post/5abcdc2c5188255c887bb9ec)([zephyrJS](https://github.com/zephyrJS) 翻译) +* [关于 CSS 变量,你需要了解的一切](https://juejin.im/post/5ab835225188255572085af4)([MechanicianW](https://github.com/MechanicianW) 翻译) +* [Reducers VS Transducers](https://juejin.im/post/5ab8705e518825555c1da48f)([jonjia](https://github.com/jonjia) 翻译) +* [2018 如何玩转 JavaScript](https://juejin.im/entry/5aa0e46d6fb9a028b54775cd/detail)([llp0574](https://github.com/llp0574) 翻译) +* [为你的 React 应用制作 SVG 图标库](https://juejin.im/post/5a9e40fe518825558a061cfd)([Albertao](https://github.com/Albertao) 翻译) +* [做好准备:新的 V8 即将到来,Node.js 的性能正在改变。](https://juejin.im/post/5aaf755851882555627d16e5)([Starriers](https://github.com/Starriers) 翻译) +* [我们能从 Redux 源码中学到什么?](https://juejin.im/post/5ab3ca926fb9a028d6641605)([goldEli](https://github.com/goldEli) 翻译) +* [使用 Travis CI 自动发布 npm](https://juejin.im/post/5ab39fedf265da23a04979cb)([Starriers](https://github.com/Starriers) 翻译) +* [TypeScript:拥有超能力的 JavaScript(下)](https://juejin.im/post/5ab34794518825558b3dd627)([jonjia](https://github.com/jonjia) 翻译) +* [function.caller 被认为是有害的](https://juejin.im/post/5aa098de51882555635ddc20)([yankwan](https://github.com/yankwan) 翻译) +* [网站优化初学者指南](https://juejin.im/post/5ab1e3f4f265da23923637bb)([Starriers](https://github.com/Starriers) 翻译) +* [Typescript : 类 vs 接口](https://juejin.im/post/5aa79a106fb9a028db585eae)([xueshuai](https://github.com/xueshuai) 翻译) +* [TypeScript:拥有超能力的 JavaScript](https://juejin.im/post/5aa89d5bf265da239a5f7f44)([jonjia](https://github.com/jonjia) 翻译) +* [测试 React & Redux 应用真实引导](https://juejin.im/post/5a9cc812518825556f54e3b6)([jonjia](https://github.com/jonjia) 翻译) +* [React 应用中 “神奇” 的多态—性能隐患](https://juejin.im/post/5aa5ebe16fb9a028d04314b0)([blizzardzheng](https://github.com/blizzardzheng) 翻译) +* [Service workers:Progressive Web Apps 背后的小英雄](https://juejin.im/post/5a9c8c87f265da238c3a23e4)([FateZeros](https://github.com/FateZeros) 翻译) +* [json — JavaScript 对象表示法](https://juejin.im/post/5a9432ae5188257a5c6092b0)([snowyYU](https://github.com/snowyYU) 翻译) +* [一份为 Node.js 应用准备的 Dockerfile 指南](https://juejin.im/post/5a9626abf265da4e9d225f4f)([lsvih](https://github.com/lsvih) 翻译) +* [关于 Promise 的 9 个提示](https://juejin.im/post/5a9600526fb9a06333155141)([yanyixin](https://github.com/yanyixin) 翻译) +* [在 V8 引擎中设置原型(prototypes)](https://juejin.im/post/5a9921e76fb9a028bd4bc3c4)([goldEli](https://github.com/goldEli) 翻译) +* [嵌套三元表达式棒极了(软件编写)(第十四部分)](https://juejin.im/post/5a7d6769f265da4e7e10ad82)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [探索 ECMAScript 装饰器](https://juejin.im/post/5a7bc62d6fb9a063523ddf95)([goldEli](https://github.com/goldEli) 翻译) +* [v3.1.0:大幅性能提升并支持流媒体服务端渲染](https://juejin.im/post/5a7ff4a56fb9a0635a65600e)([FateZeros](https://github.com/FateZeros) 翻译) +* [JavaScript 工作原理:Web Worker 的内部构造以及 5 种你应当使用它的场景](https://juejin.im/post/5a90233bf265da4e92683de3)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [你前所未知的 JavaScript 调试器](https://juejin.im/post/5a7e94a66fb9a0633b2105ed)([Serendipity96](https://github.com/Serendipity96) 翻译) +* [JavaScript 中的私有变量](https://juejin.im/post/5a8e9b6d5188257a5f1ed826)([noahziheng](https://github.com/noahziheng) 翻译) +* [CSS Grid 之列宽自适应:`auto-fill` vs `auto-fit`](https://juejin.im/post/5a8c25d66fb9a0634d27b73b)([pot-code](https://github.com/pot-code) 翻译) +* [也谈 React 16.3(.0-alpha) ](https://juejin.im/entry/5a82ada16fb9a063317c54f2)([pot-code](https://github.com/pot-code) 翻译) +* [使用 SVG 符号和 CSS 变量实现多彩图标](https://juejin.im/post/5a8409e06fb9a063342672b6)([pthtc](https://github.com/pthtc) 翻译) +* [教你使用 CSS 计数器](https://juejin.im/post/5a811c6251882528b63ff8d7)([sakila1012](https://github.com/sakila1012) 翻译) +* [2018 前端性能优化清单 — 第 1 部分](https://juejin.im/post/5a67e49df265da3e377c2d59)([tvChan](https://github.com/tvChan) 翻译) +* [2018 前端性能优化清单 — 第 2 部分](https://juejin.im/post/5a654e686fb9a01cb42c7894)([sakila1012](https://github.com/sakila1012) 翻译) +* [2018 前端性能优化清单 — 第 3 部分](https://juejin.im/post/5a702160f265da3e4b771109)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [2018 前端性能优化清单 — 第 4 部分](https://juejin.im/post/5a62aa686fb9a01c91407a0b)([ParadeTo](https://github.com/ParadeTo) 翻译) +* [这些 CSS 命名规范将省下你大把调试时间](https://juejin.im/post/5a6c5881518825733201daf7)([unicar9](https://github.com/unicar9) 翻译) +* [PWA 实战:Tinder 的性能优化之道](https://juejin.im/post/5a5ed5f3f265da3e261bfb94)([pot-code](https://github.com/pot-code) 翻译) +* [迎接新的 Dialog 元素](https://juejin.im/post/5a66cc165188257342170802)([FateZeros](https://github.com/FateZeros) 翻译) +* [保持 webpack 快速运行的诀窍:一本提高构建性能的现场指导手册](https://juejin.im/post/5a6adc6d5188257350517033)([noahziheng](https://github.com/noahziheng) 翻译) +* [Vue Devtools 4.0 有哪些新内容](https://juejin.im/post/5a676c33f265da3e5b32f43c)([MechanicianW](https://github.com/MechanicianW) 翻译) +* [我未曾见过的 JS 特性](https://juejin.im/post/5a723216f265da3e2e62d0a5)([NeilLi1992](https://github.com/NeilLi1992) 翻译) +* [现代浏览器是如何提升性能的:网络层](https://juejin.im/post/5a70755df265da3e283a4e5d)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [构造函数已死,构造函数万岁!](https://juejin.im/post/5a694be551882573541c8f29)([unicar9](https://github.com/unicar9) 翻译) +* [🚀webpack 4 测试版 —— 现在让我们先一睹为快吧!](https://juejin.im/post/5a72d569f265da3e3a6e2118)([FateZeros](https://github.com/FateZeros) 翻译) +* [Object Composition 中的宝藏](https://juejin.im/post/5a648ed0518825733201b818)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [Angular 安全 —— 使用 JSON 网络令牌(JWT)验证:完全指南](https://juejin.im/post/5a64267c518825734e3e5c22)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [使用深度学习自动生成HTML代码 - 第 1 部分](https://juejin.im/post/5a72744e6fb9a01cb64f1d66)([sakila1012](https://github.com/sakila1012) 翻译) +* [JavaScript 自动化爬虫入门指北(Chrome + Puppeteer + Node JS):和 Headless Chrome 一起带你装逼带你飞](https://juejin.im/post/5a4e1038f265da3e591e1247)([pot-code](https://github.com/pot-code) 翻译) +* [JavaScript 是如何工作的:深入 WebSockets 和使用了 SSE+ 的 HTTP/2,如何在二者当中做出选择](https://juejin.im/post/5a522647518825732d7f6cbb)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [Redux-recompose 介绍:优雅的编写 Redux 中的 action 和 reducer](https://juejin.im/post/5a4e0d7651882573315c28a1)([pot-code](https://github.com/pot-code) 翻译) +* [2018 要学习的优秀 JavaScript 库与知识](https://juejin.im/post/5a4e23f0f265da3e377bce4f)([gy134340](https://github.com/gy134340) 翻译) +* [JWT:JSON Web Tokens 全方位指南](https://juejin.im/entry/5a4f300f6fb9a01cb912b3c7/)([rottenpen](https://github.com/rottenpen) 翻译) +* [前端 2017: 举要删芜](https://juejin.im/post/5a523271f265da3e2f00c7ab)([gy134340](https://github.com/gy134340) 翻译) +* [使用 web 应用打包工具 Parcel 实现代码分割](https://juejin.im/post/5a478289f265da430d5859ff)([kangkai124](https://github.com/kangkai124) 翻译) +* [关于 Parcel 你所需要知道的一切:快速的 Web 应用打包器 🚀](https://juejin.im/post/5a545c94518825733d68edae)([FateZeros](https://github.com/FateZeros) 翻译) +* [Redux 的工作原理](https://juejin.im/post/5a532e466fb9a01ca9154a98)([hexianga](https://github.com/hexianga) 翻译) +* [垂直排版:重提 writing-mode](https://juejin.im/post/5a5570fb6fb9a01c9e45d749)([Usey95](https://github.com/Usey95) 翻译) +* [漫画图解 JavaScript 引擎: let jsCartoons = ‘Awesome’;](https://juejin.im/post/5a582b13f265da3e355aff46)([MechanicianW](https://github.com/MechanicianW) 翻译) +* [HTML 5.2 有哪些新内容?](https://juejin.im/post/5a5dab05518825734107edda)([lsvih](https://github.com/lsvih) 翻译) +* [2017 年 JavaScript 发展状况回顾](https://juejin.im/entry/5a44a500f265da43271887f0/)([LeviDing](https://github.com/leviding) 翻译) +* [如何在 JavaScript 中使用 Generator?](https://juejin.im/post/5a44968df265da4335630fb9)([jonjia](https://github.com/jonjia) 翻译) +* [在 React & Redux 中使用 AJAX 轮询](https://juejin.im/post/5a43b6da5188257d167a7aef)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [在 Redux 中使用 AJAX 轮询(二):Saga 篇](https://juejin.im/post/5a43b80df265da43176a6e4e)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [论原子 CSS 的日益普及](https://juejin.im/post/5a4387af6fb9a045186b04d1)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [使用 CSS Grid:以兼容不支持栅格化布局的浏览器](https://juejin.im/post/5a3f494d6fb9a0450a678f8d)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [用 CSS 选择器和自定义属性来升级你的项目](https://juejin.im/post/5a3c47386fb9a044fd11f278)([MechanicianW](https://github.com/MechanicianW) 翻译) +* [将网站转换为渐进式 Web 应用程序之简易教程](https://juejin.im/post/5a3cdf52f265da4321543c95)([bambooom](https://github.com/bambooom) 翻译) +* [创建无障碍 React 应用](https://llp0574.github.io/2017/12/20/creating-accessible-react-apps/)([llp0574](https://github.com/llp0574) 翻译) +* [针对 Airbnb 清单页的 React 性能优化](https://juejin.im/post/5a3a733f6fb9a045263bbdf5)([zwwill](https://github.com/zwwill) 翻译) +* [如何取消你的 Promise?](https://juejin.im/post/5a32705a6fb9a045117127fa)([jonjia](https://github.com/jonjia) 翻译) +* [介绍 Turbo:比 Yarn 和 NPM 快 5 倍,可以在本地浏览器中运行](https://juejin.im/post/5a35d58ef265da431a434441)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [从 Gzip 压缩 SVG 说起 — 论如何减小资源文件的大小](https://juejin.im/post/5a30a7fdf265da4309452517)([lsvih](https://github.com/lsvih) 翻译) +* [用 Render props 吧!](https://juejin.im/post/5a3087746fb9a0450c4963a5)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [你想学 React.js 吗?](https://juejin.im/post/5a2f8ea5f265da43305e6f6b)([tvChan](https://github.com/tvChan) 翻译) +* [JavaScript 工作原理:内存管理 + 处理常见的 4 种内存泄漏](https://juejin.im/post/5a2559ae6fb9a044fe4634ba)([caoxiaoshuai1](https://github.com/caoxiaoshuai1) 翻译) +* [Ant Design 3.0 驾到](https://juejin.im/post/5a28aab66fb9a0450a673c5e)([zwwill](https://github.com/zwwill) 翻译) +* [Chrome DevTools - 性能监控](https://juejin.im/post/5a37b2f56fb9a0451e3fe73d)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [如何禁用链接](https://juejin.im/post/5a240aa66fb9a0452577f06a)([Usey95](https://github.com/Usey95) 翻译) +* [模拟是一种代码异味(软件编写)(第十二部分)](https://juejin.im/post/5a2d363e6fb9a0450b6652c8)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [React 应用性能调优](https://juejin.im/post/5a289cc6f265da43346fcc8d)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [如何使用 AJAX 和 REST API 创建一个图表](https://juejin.im/post/5a20e18bf265da4318768b22)([sakila1012](https://github.com/sakila1012) 翻译) +* [JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧](https://juejin.im/post/5a221d35f265da43356291cc)([balancelove](https://github.com/balancelove) 翻译) +* [前端 Console 调试小技巧](https://juejin.im/post/5a08087f6fb9a04529363d71)([lsvih](https://github.com/lsvih) 翻译) +* [ES6 中的元编程: 第三部分 - 代理(Proxies)](https://juejin.im/post/5a0f05496fb9a04508093ac4)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [Angular、React、Vue 三剑客: 在 2017 年的比较](https://juejin.im/post/5a0d5df1f265da43062a542f)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [元编程:Symbol,了不起的 Symbol](https://juejin.im/post/5a0e65c1f265da430702d6b9)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [重建 slack.com:使用 CSS Grid 重新设计,并针对性能和可访问性进行了优化。](https://juejin.im/post/5a029d986fb9a044fb072efb)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [JavaScript 如何工作:在 V8 引擎里 5 个优化代码的技巧](https://juejin.im/post/5a102e656fb9a044fd1158c6)([balancelove](https://github.com/balancelove) 翻译) +* [ES6 中的元编程:第二部分 —— 反射(Reflect)](https://juejin.im/post/5a0e66386fb9a04523417418)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [14 个你可能不知道的 JavaScript 调试技巧](https://github.com/xitu/gold-miner/pull/2404)([ParadeTo](https://github.com/ParadeTo) 翻译) +* [Rollup - 下一代 ES6 模块化打包工具 - 对 Rich Harris 的采访](https://juejin.im/post/5a09b4e56fb9a0451170a22e)([Raoul1996](https://github.com/Raoul1996) 翻译) +* [Under-the-hood-ReactJS 系列教程翻译 — 共 17 篇](https://github.com/xitu/Under-the-hood-ReactJS/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Under-the-hood-ReactJS 翻译组](https://github.com/xitu/Under-the-hood-ReactJS/) 翻译) +* [找出可能影响性能的代码模式](https://juejin.im/post/59f95af951882574d1723e70?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) +* [React 组件的 8 个关键决策](https://juejin.im/post/59f7e2c5f265da4318760a5f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([undead25](https://github.com/undead25) 翻译) +* [借助函数完成可组合的数据类型(软件编写)(第十部分)](https://juejin.im/post/59e3f3786fb9a0450166ff7b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [性能指标都是些什么鬼?](https://juejin.im/entry/59e855b45188250989513220/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [webpack & HTTP/2](https://juejin.im/post/59e87b89f265da433226b0f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) +* [JavaScript 让 Monad 更简单(软件编写)(第十一部分)](https://juejin.im/post/59e55dbbf265da43333d7652?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [React 16 带来了什么以及对 Fiber 架构的解释](https://juejin.im/post/59de1b2a51882578c70c0833?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [Javascript 中各种各样的 this](https://juejin.im/post/59e066d551882578c3411908?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [修改 JavaScript 帧](https://juejin.im/entry/59d2ed6f6fb9a00a681b01f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [为什么在使用了类之后会使得组合变得愈发困难(第九部分)](https://juejin.im/post/59cf43ce6fb9a00a4e67cd36?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [离线友好的表单](https://juejin.im/post/59c138e35188253fbd46c5fc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [V8 引擎中的快速属性](https://juejin.im/post/59c1df855188257e826779f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [如何安全地使用 CSS-in-JS?](https://juejin.im/post/59c90a6df265da065270b004?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yuuoniy](https://github.com/Yuuoniy) 翻译) +* [网络现状:性能提升指南](https://juejin.im/post/59c4b6a55188257e764c9c20?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([undead25](https://github.com/undead25) 翻译) +* [ES6+ 中的 JavaScript 工厂函数](https://juejin.im/post/59c8c8756fb9a00a681ae5bd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lampui](https://github.com/lampui) 翻译) +* [使用 CSS 栅格和 Flexbox 打造 Trello 布局](https://juejin.im/post/59bb463d51882519777c5a85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [在 HTTP/2 的世界里管理 CSS 和 JS](https://juejin.im/post/59bb463d51882519777c5a85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [学习 JavaScript:9个常见错误阻碍你进步](https://juejin.im/post/59bb4a7c6fb9a00a53274cd7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lekenny](https://github.com/lekenny) 翻译) +* [使用 CSS 的 font-size-adjust 属性改善网页排版](https://juejin.im/post/59b8b97d5188257e8c54d816?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lampui](https://github.com/lampui) 翻译) +* [CSS 十六进制颜色揭秘](https://juejin.im/entry/59b887515188257e7973a60a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [原生 JavaScript 值得学习吗?答案是肯定的](https://juejin.im/post/59a535bd6fb9a0249975cb9b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lampui](https://github.com/lampui) 翻译) +* [你是如何拆分组件的?](https://juejin.im/post/59aa7f8c6fb9a024747f13b7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([undead25](https://github.com/undead25) 翻译) +* [Angular 与 React:谁更适合前端开发](https://juejin.im/post/59ab51746fb9a024865d202b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([stormrabbit](https://github.com/stormrabbit) 翻译) +* [JavaScript 二进制的 AST](https://juejin.im/post/599e6f246fb9a024985f0421?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [关于 React Router 4 的一切](https://juejin.im/post/5995a2506fb9a0249975a1a4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([undead25](https://github.com/undead25) 翻译) +* [如何在 Webpack 2 中使用 tree-shaking](https://juejin.im/post/599bc13b6fb9a024a370f4ec?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) +* [Redux 有多棒?](https://juejin.im/entry/599cff2551882524397f95c1/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZiXYu](https://github.com/ZiXYu) 翻译) +* [自定义 Babel 和 ESLint 插件是如何提高生产率与用户体验的](https://juejin.im/post/599519e06fb9a02499759f71?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([H2O-2](https://github.com/H2O-2) 翻译) +* [理解 Service Worker](https://juejin.im/post/599163316fb9a03c3c14d751?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zyziyun](https://github.com/zyziyun) 翻译) +* [学习 React.js 比你想象的要简单](https://juejin.im/post/599156cc6fb9a03c3a25db08?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [渐进增强的 CSS 布局:从浮动到 Flexbox 到 Grid](https://juejin.im/post/5987acfd6fb9a03c502288f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([leviding](https://github.com/leviding) 翻译) +* [Web 端的下一代三维图形](https://juejin.im/post/5983208c5188253c6f2d185d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [在大型应用中使用 Redux 的五个技巧](https://juejin.im/post/5980514151882537b41c4c0d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([loveky](https://github.com/loveky) 翻译) +* [在 CSS 中使用特征查询](https://juejin.im/post/58eb3004ac502e006c45454b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [构建渐进式 Web 应用入门指南](https://juejin.im/entry/5979666af265da3e161a6402/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [回顾 ESLint 的成功](https://juejin.im/post/5978227a518825175b1e8354?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) +* [CSS 才不是什么黑魔法呢](https://juejin.im/post/5976eb626fb9a06bba474cf1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xunge0613](https://github.com/xunge0613) 翻译) +* [高性能 React:3 个新工具加速你的应用](https://juejin.im/post/5971bc786fb9a06bad656523?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [2017 年了,这么多前端框架,你会怎样选择?](https://juejin.im/post/597022c6f265da6c2f0add39?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([leviding](https://github.com/leviding) 翻译) +* [Redux 并不慢,只是你使用姿势不对 —— 一份优化指南](https://juejin.im/post/596db2f9f265da6c4602ffc3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [即将到来的正则表达式新特性](https://juejin.im/post/59683f98f265da6c4f34eec6?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [是的,ES2017 (ES8)来了](https://juejin.im/post/596713b75188250da20604cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ToBeNumerOne](https://github.com/ToBeNumerOne) 翻译) +* [任何网站都可以成为渐进式网络应用 - 但我们需要做的更好](https://juejin.im/post/5966bf2451882568b20dc2af?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wilsonandusa](https://github.com/wilsonandusa) 翻译) +* [JavaScript 的函数式编程是一种反模式](https://juejin.im/post/59645b29f265da6c20419170?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [你不需要基于 CSS Grid 的栅格布局系统](https://juejin.im/post/5960e73f6fb9a06bb5403f87?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([leviding](https://github.com/leviding) 翻译) +* [React 在服务端渲染的实现](https://juejin.im/post/595b01ad6fb9a06bb15a13b2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MuYunyun](https://github.com/MuYunyun) 翻译) +* [V8 性能优化杀手](https://juejin.im/post/5959edfc5188250d83241399?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [如何充分利用 JavaScript 控制台](https://juejin.im/post/59510ac45188250d8860c908?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [统一样式语言](https://juejin.im/post/595311fa6fb9a06b9d5b5f08?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [ESLint v4.0.0 升级指南](https://juejin.im/post/5954af2f6fb9a06baa63ab50?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xunge0613](https://github.com/xunge0613) 翻译) +* [RxJS Observable 之冷和热](https://juejin.im/entry/594c88765188250d9017d072/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([hikerpig](https://github.com/hikerpig) 翻译) +* [JavaScript:回调是什么鬼?](https://juejin.im/post/594b3607128fe100650355c7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [高阶函数一点通](https://juejin.im/entry/594a3eaaa0bb9f006b0c304a/detail?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [一封写给 CSS 的情书](https://juejin.im/post/594c75c0f265da6c2b765b25?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [函数式 Mixin(软件编写)(第七部分)](https://juejin.im/post/594a2cf6ac502e006bc0bc3a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [webpack 3:官方发布!!](https://juejin.im/post/5949272551882520fa3df038?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [理解 NPM 5 中的 lock 文件](https://juejin.im/post/5943849aac502e006b84ce07?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [读完 flexbox 细则之后学到的 11 件事](https://juejin.im/post/5940bcef61ff4b006cb6b0d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XatMassacrE](https://github.com/XatMassacrE) 翻译) +* [RxJS 简介:可观察对象、观察者与操作符](https://juejin.im/post/5934d2532f301e00585ea5f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [利用“Immutability(不可变性)”编写更为简洁高效的代码](https://juejin.im/post/592eb8bfa22b9d005776d6df?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [Airbnb 的前端重构](https://juejin.im/post/592e3af8ac502e006c9c3f1f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [Web 开发者安全清单](https://juejin.im/post/592651c944d904006400cd88?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([GangsterHyj](https://github.com/GangsterHyj) 翻译) +* [解密 Quantum:现代浏览器引擎的构建之道](https://juejin.im/post/591bc865a22b9d00583c17b8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xunge0613](https://github.com/xunge0613) 翻译) +* [光速 React](https://juejin.im/post/591ad6b7128fe1005ce1123a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [我是如何实现世界上最快的 JavaScript 记忆化的](https://juejin.im/post/5912b635a0bb9f0058b44c60?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aladdin-ADD](https://github.com/Aladdin-ADD) 翻译) +* [别让你的偏爱拖了后腿:快拥抱箭头函数吧!](https://juejin.im/post/59158c92a0bb9f005fd58fd7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [为何 TypeScript 愈发流行了?](https://juejin.im/post/59152911a22b9d0058fd5fe8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([loveky](https://github.com/loveky) 翻译) +* [何为 HTML API,如何设计之?](https://juejin.im/entry/59131ee7a0bb9f0058ba4a88/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [前端调试技巧与诀窍](https://juejin.im/post/5901e8d6a0bb9f0065e64f63?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [哪些项目需要 React?都需要!](https://juejin.im/post/5910050661ff4b0062553421?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [ES6 模块原生支持在浏览器中落地,是时候该重新考虑打包了吗?](https://juejin.im/post/590a990a5c497d005852cf61?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [JavaScript 中的 CSS:基于组件的样式的未来](https://juejin.im/post/590822768d6d810058e4d24d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [代码中添加注释之好坏丑](https://juejin.im/post/5902126aa0bb9f0065e80ea9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [真正行动之前 你将一无所成](https://juejin.im/entry/58f6136861ff4b00580aef28?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([owenlyn](https://github.com/owenlyn) 翻译) +* [高阶函数(软件编写)(第四部分)](https://juejin.im/post/58f6d6ff570c3500564fbddc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [为什么用 JavaScript 学习函数式编程?(软件编写)(第二部分)](https://juejin.im/post/58f5a2ecb123db2fa2b1b244?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [Functor 与 Category (软件编写)(第六部分)](https://juejin.im/post/58f58d5da0bb9f006aac3e8d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [函数式程序员的 JavaScript 简介 (软件编写)(第三部分)](https://juejin.im/post/58f58b06da2f60005d43388b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sunui](https://github.com/sunui) 翻译) +* [Reduce(软件编写)(第五部分)](https://juejin.im/post/58f44082da2f60005d3a3710?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yoyoyohamapi](https://github.com/yoyoyohamapi) 翻译) +* [跌宕起伏的函数式编程(软件编写)(第一部分)](https://juejin.im/post/58f0eb570ce463006ba37089?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [React 的慢与快:优化 React 应用实战](https://juejin.im/entry/58eb2fb0570c350057dd921a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie(Jiang Haichao)](https://github.com/AceLeeWinnie) 翻译) +* [使用开发者工具在浏览器中调整设计](https://juejin.im/post/58f0729b570c35005625630a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [超越浏览器:从 web 应用到桌面应用](https://juejin.im/entry/58f07ea5ac502e006c1e0301?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bambooom](https://github.com/bambooom) 翻译) +* [同中有异的 Webpack 与 Rollup](https://juejin.im/post/58edb865570c350057f199a7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([SunCafe](http://suncafe.cc/) 翻译) +* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译) +* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译) +* [生活在 JavaScript 之中:学习第二门语言的好处](https://juejin.im/post/58d908deac502e0058db544b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [震惊,还可以用这种姿势学习编程](https://juejin.im/post/58d3ebd4128fe1006cb43722/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) +* [如何让你的 React 应用完全的函数式,响应式,并且能处理所有令人发狂的副作用](https://juejin.im/post/58d3287f61ff4b006cb3f56d/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [编写整洁 CSS 代码的黄金法则](https://juejin.im/post/58d34bed128fe1006caf8b6b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [创建和使用 WebAssembly 组件](https://juejin.im/post/58d0bbe144d90400684c0f3a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xilihuasi](https://github.com/xilihuasi) 翻译) +* [WebAssembly 的现在与未来](https://github.com/xitu/gold-miner/blob/master/TODO/where-is-webassembly-now-and-whats-next.md)([huzidaha](https://github.com/huzidaha/) 翻译) +* [是什么让 WebAssembly 执行的这么快?](https://github.com/xitu/gold-miner/blob/master/TODO/what-makes-webassembly-fast.md)([huzidaha](https://github.com/huzidaha/) 翻译) +* [新一代 JavaScript 的开发图谱(2017)](https://juejin.im/post/58cfe86f61ff4b006ca26aaf/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [React 未来之函数式 setState](https://juejin.im/post/58cfcf6e44d9040068478fc6/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [看动画,学 RxJS](https://juejin.im/post/58cd146a61ff4b0060277d32/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [如何让你的 React Native 应用在键盘弹出时优雅地响应](https://juejin.im/entry/58c7ceab0ce4630054834b07/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Shangbin Yang](https://github.com/rccoder) 翻译) +* [JIT 编译器快速入门](https://gold.xitu.io/entry/58c7777eda2f605dc5b1c258/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhouzihanntu](https://github.com/zhouzihanntu) 翻译) +* [看漫画,学 WebAssembly](https://gold.xitu.io/entry/58c76be244d90400699b3a1f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sqrthree](https://github.com/sqrthree) 翻译) +* [Redux 异步四兄弟](https://gold.xitu.io/entry/58c75f9444d90400699add86/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([reid3290](https://github.com/reid3290) 翻译) +* [再谈 CSS 中的代码味道](https://gold.xitu.io/entry/58c2034dac502e0062cf8e2a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译) +* [Web 分享 API 赋予浏览器原生分享能力](https://gold.xitu.io/entry/58c174ec44d9040069777f17/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Jiang Haichao](https://github.com/AceLeeWinnie) 翻译) +* [React JSX 与 Vue 模板的对比:前端界的一次对决](https://gold.xitu.io/entry/58b9841dac502e006c0a69d5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhangFe](https://github.com/ZhangFe) 翻译) +* [为多个品牌和应用构建 React 组件](https://gold.xitu.io/entry/58b92529128fe1007e4493da/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XatMassacrE](https://github.com/XatMassacrE) 翻译) +* [编写 React 组件的最佳实践](https://gold.xitu.io/entry/58b3bbf6b123db0052d23e42/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([imink](https://github.com/imink) 翻译) +* [如何实现 React 组件的可复用性](https://gold.xitu.io/entry/58ac4eb58d6d810058c1d325?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([aleen42](https://github.com/aleen42) 翻译) +* [React 中“灵光乍现”的那些瞬息](https://gold.xitu.io/entry/58aaec530ce463006b14aa69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([aleen42](https://github.com/aleen42) 翻译) +* [JavaScript 启动性能探究](https://gold.xitu.io/entry/58a5b7d21b69e6006d2008e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([vuuihc](https://github.com/vuuihc) 翻译) +* [几张 GIF 动图让你看懂弹性盒模型(Flexbox)如何工作](https://gold.xitu.io/entry/589d2dd886b599006b2c3308?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [一个关于 Styled Components 的五分钟介绍](https://gold.xitu.io/entry/589ac8b886b599006b1cec3d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sqrthree](https://github.com/sqrthree) 翻译) +* [Netflix: 使用 React 构建高性能的电视用户界面](https://gold.xitu.io/entry/589a93100ce4630056194875/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([vuuihc](https://github.com/vuuihc) 翻译) +* [怎样写一个能同时用于 Node 和浏览器的 JavaScript 包?](https://gold.xitu.io/entry/5899bc6e61ff4b006b21d0bc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [让 Node.js 核心更强大](https://gold.xitu.io/entry/5897289b0ce463005603a5d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([imink](https://github.com/imink) 翻译) +* [2017 年要去学的 3 个 CSS 新属性](https://gold.xitu.io/entry/5896c8ee570c3500623eeaeb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([熊贤仁](https://github.com/FrankXiong) 翻译) +* [快来和你的 Font Icons 说 Goodbye 吧](https://gold.xitu.io/entry/589591442f301e0069488788?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Aleen](https://github.com/aleen42) 翻译) +* [使用 WebSocket 和 CSS3 创造魔法](https://gold.xitu.io/entry/5894612a2f301e006900cfcc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [在 CSS 中使用恒定角度的斜边](https://gold.xitu.io/entry/5875af941b69e6005ceffe94?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [在 `setState` 中使用函数替代对象](https://gold.xitu.io/entry/5873b04f61ff4b006d4d45f7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [书写干净的 CSS 代码 PART2](https://gold.xitu.io/entry/5870d0841b69e6005cd23edc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [书写干净的 CSS 代码 PART1](https://gold.xitu.io/entry/5870d03c1b69e6005cd23aaa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [看沃尔玛如何玩转 React Native](https://gold.xitu.io/entry/5864e40e1b69e675fce43a80?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Draftbk](https://github.com/draftbk) 翻译) +* [渐进增强的 Web AMP](https://gold.xitu.io/entry/585d35b561ff4b00580eccb3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [CSS 继承深度解析](https://gold.xitu.io/entry/585a29c01b69e6006cb89465?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://llp0574.github.io) 翻译) +* [响应式邮件设计](https://gold.xitu.io/entry/58516cc01b69e60056c04528?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Hyuni](https://github.com/xuzaixian) 翻译) +* [JavaScript 测试︰ 单元 vs 功能 vs 集成测试](https://gold.xitu.io/entry/584ab2dc128fe1006c7cdc11?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wild-flame](https://github.com/wild-flame) 翻译) +* [如何用 JavaScript 作图](https://gold.xitu.io/entry/58441f8f128fe1006c4d1191?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [实践 Redux,第 2 部分:Redux-ORM 的概念和技术](http://gold.xitu.io/entry/583d90aba22b9d006c1f092a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [使用 React.js 的渐进式 Web 应用程序:第 4 部分 - 渐进增强](http://gold.xitu.io/entry/58345f5cc4c9710054e187a5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([rccoder](https://github.com/rccoder) 翻译) +* [使用 React.js 的渐进式 Web 应用程序:第 3 部分 - 离线支持和网络恢复能力](http://gold.xitu.io/entry/58350983a22b9d006bbb90d3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([AceLeeWinnie](https://github.com/AceLeeWinnie) 翻译) +* [CSS 变量的条件](http://gold.xitu.io/entry/58354e50a22b9d006bc01c06?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([rottenpen](https://github.com/rottenpen) 翻译) +* [JavaScript 包管理器工作原理简介](http://gold.xitu.io/entry/5835a2c0c59e0d005772a62f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [使用 React.js 的渐进式 Web 应用程序:第 2 部分 - 页面加载性能](http://gold.xitu.io/entry/583576f3c4c9710054a3e212?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([markzhai](https://github.com/markzhai) 翻译) +* [详解 React Native 使用 OneSignal 推送通知](http://gold.xitu.io/entry/58369fa5c59e0d005777d12f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([xiaoheiai4719](https://github.com/xiaoheiai4719) 翻译) +* [无需配置即可创建 React Apps](http://gold.xitu.io/entry/583266068ac2470061c24c06?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiakeqi](https://github.com/jiakeqi) 翻译) +* [React Native Android 应用内存使用探究](http://gold.xitu.io/entry/5834161bda2f600062be79b5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([phxnirvana](https://github.com/phxnirvana) 翻译) +* [React Native Android 的 native 模块](http://gold.xitu.io/entry/5832e55fc4c971005f565b4c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XHShirley](https://github.com/XHShirley) 翻译) +* [我在手撕 SVG 条形图时踩过的定位坑](http://gold.xitu.io/entry/58306b428ac2470061b60ede?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cyseria](https://github.com/cyseria) 翻译) +* [使用 “Google 抓取方式” 测试 React 驱动的网站 SEO](http://gold.xitu.io/entry/582e8b2fd20309006702090f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [Node.js v6 LTS 中最激动人心的六个 ES6 特性](http://gold.xitu.io/entry/582dcfb067f356006336c834?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [10 个原则让动画带你飞](http://gold.xitu.io/entry/582dce6ea0bb9f0067ac0b4e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [一个健壮且可扩展的 CSS 架构所需的 8 个简单规则](http://gold.xitu.io/entry/582d137d128fe1006952b12c/detail/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [使用 React.js 的渐进式 Web 应用程序:第 1 部分 - 介绍](http://gold.xitu.io/post/582a64dd2e958a0069a507f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([markzhai](https://github.com/markzhai) 翻译) +* [无障碍网站开发工具](https://gold.xitu.io/entry/58294b222f301e00585ae000?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [全方位提升网站打开速度:前端、后端、新的技术)](https://gold.xitu.io/entry/582492025bbb5000590ef04d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [准备充分了嘛就想学函数式编程?(Part 5)](https://gold.xitu.io/entry/582490c3bf22ec0068f9935e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [实践 Redux,第 1 部分: Redux-ORM 基础](https://gold.xitu.io/entry/58249792a0bb9f0058dd30ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [成为一个编译器之「使用 JavaScript 来制作编译器」](https://gold.xitu.io/entry/582343555bbb500059056d4b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [准备充分了嘛就想学函数式编程?(Part 3)](https://gold.xitu.io/entry/581fedca2f301e005c2260a0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [准备充分了嘛就想学函数式编程?(Part 2)](https://gold.xitu.io/entry/581fed565bbb500059ec1184?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Airmacho](https://github.com/Airmacho) 翻译) +* [使用多背景来提高感知性能](https://gold.xitu.io/entry/58217e288ac247004f1d1b02?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cyseria](https://github.com/cyseria) 翻译) +* [Yarn 更快更可靠的 CI 创建工具](https://gold.xitu.io/entry/582019f5a0bb9f0058bb5f14?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [用 Yarn 你还能做这 5 件事](https://gold.xitu.io/entry/582185608ac247004f1d63a3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiakeqi](https://github.com/jiakeqi) 翻译) +* [准备充分了嘛就想学函数式编程?(Part 6)](https://gold.xitu.io/entry/58209780570c350060b75a93?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeadLion](https://github.com/DeadLion) 翻译) +* [实践 Redux,第 0 部分:简介](https://gold.xitu.io/entry/5820552eda2f60005d09c33c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [写了六个相同功能的函数之后,我学到了什么](https://gold.xitu.io/entry/58200ec367f3560058a6f8fc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Romeo0906](https://github.com/Romeo0906) 翻译) +* [准备充分了嘛就想学函数式编程?(第一部分)](https://gold.xitu.io/entry/581fe399d20309005507371c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [你怎么找到好工作,我在 Stack Overflow & GitHub 学电脑](https://gold.xitu.io/entry/581f3bd9da2f60005d02f561?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [准备充分了嘛就想学函数式编程?(第四部分)](https://gold.xitu.io/entry/581bf0a62e958a0054d783e1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [CSS 遮罩的过渡效果](https://gold.xitu.io/entry/5819d6f4a22b9d0067a5b394?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([luoyaqifei](https://github.com/luoyaqifei) 翻译) +* [JavaScript ES6 核心功能一览](https://gold.xitu.io/entry/58189177128fe100559efd51?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [与时俱进的 Reactivity](https://gold.xitu.io/entry/58130dcbbf22ec0068824bd2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Liz](https://github.com/lizwangying) 翻译) +* [重构,不要积压!](https://gold.xitu.io/entry/581066dc8ac247005b6b3d4f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([rottenpen](https://github.com/rottenpen) 翻译) +* [Facebook 发布了新的 Node 模块管理器 Yarn,或取代 npm 客户端](https://gold.xitu.io/entry/57fe2f2b128fe1005483131b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/Zhangjd) 翻译) +* [构建应用状态时,你应该避免不必要的复杂性](https://gold.xitu.io/entry/58044c2a0e3dd900571475fa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([chemzqm](https://github.com/chemzqm) 翻译) +* [开发 Electron app 必知的 4 个 tips](https://gold.xitu.io/entry/58025536bf22ec0064d5f3d9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huanglizhuo](https://github.com/huanglizhuo) 翻译) +* [VUE 和 VUEX 中的数据流](https://gold.xitu.io/entry/58007bcf0bd1d00058eefe69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [使用 Cordova 和 Vue.js 创建移动应用](https://gold.xitu.io/entry/57ea26f5da2f600060e59c5e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [使用 currentColor 属性写出更好的 CSS 代码](https://gold.xitu.io/entry/57eb30bebf22ec0058898ee7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yangzj1992](http://qcyoung.com) 翻译) +* [快速构建原型最好用的 10 个 ReactJS UI 框架](https://gold.xitu.io/entry/57ea0bc2a3413100624e62ff?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cyseria](https://github.com/cyseria) 翻译) +* [响应式设计的真正挑战:RSS](https://gold.xitu.io/entry/57d909170e3dd900694dc072?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) +* [3 分钟掌握 CSS Flexbox](https://gold.xitu.io/entry/57ce68bf2e958a00543a7df9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Graning](https://github.com/Graning) 翻译) +* [基于浏览器的 MapReduce](https://gold.xitu.io/entry/57cd7b9c8ac24700645b052b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mypchas6fans](https://github.com/mypchas6fans) 翻译) +* [如何编写更少的代码](https://gold.xitu.io/entry/57c6adc7a633bd005d8f2584?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [如何用 React 完成图片上传功能?](https://gold.xitu.io/entry/57b923225bbb50005b794943?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeadLion](https://github.com/DeadLion) 翻译) +* [你考虑清楚了吗就决定用 Bootstrap ?](http://gold.xitu.io/entry/57b67315a34131005f82d244?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) +* [如何运用最新的技术提升网页速度和性能](http://gold.xitu.io/entry/57b3f7928d2a3b0069605c2c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([hpoenixf](https://github.com/hpoenixf) 翻译) +* [Medium 内部使用 css/less 的代码风格指南](http://gold.xitu.io/entry/57b06a1b6be3ff006bab2030?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gran](https://github.com/Graning) 翻译) +* [CSS writing-mode 的特别技巧](http://gold.xitu.io/entry/57b08227165abd005426657b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huanglizhuo](https://github.com/huanglizhuo) 翻译) +* [如何搭建自动化、跨浏览器的 JavaScript 单元测试](http://gold.xitu.io/entry/579b2d6ea633bd0060eb965f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([owenlyn](https://github.com/owenlyn) 翻译) +* [ES6 中 的 var、let 和 const 应该如何选择?](http://gold.xitu.io/entry/57962ef22e958a00651f7387?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Graning](https://github.com/Graning) 翻译) +* [使用 Zopfli 优化 PNG 图片](http://gold.xitu.io/entry/578e3a34c4c971005e059ee9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cyseria](https://github.com/cyseria) 翻译) +* [jQuery 终于发布了](https://gold.xitu.io/entry/576917c0d342d30058097229?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Dwight](https://github.com/ldhlfzysys) 翻译) +* [如何理解 JavaScript 中的 Promise 机制](http://gold.xitu.io/entry/57890b881532bc0061d5ac52?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huanglizhuo](https://github.com/huanglizhuo) 翻译) +* [懒加载图片?不要依赖 JavaScript !](http://gold.xitu.io/entry/5787048a165abd0067f7e476?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jk77](https://github.com/jk77me) 翻译) +* [用 Javascript 编写λ演算解释器](http://gold.xitu.io/entry/57834783d342d30057db3f93?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangzhaoqi](https://github.com/joddiy) 翻译) +* [让你的网站更炫酷的一些小 tips](https://gold.xitu.io/entry/577f402b79bc4400329db962?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([达仔](https://github.com/zhangjd) 翻译) +* [较为完整的 React.js / Vue.js 的性能比较 Part 1](https://gold.xitu.io/entry/577bacc92e958a00549106dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [较为完整的 React.js / Vue.js 的性能比较 Part 2](https://gold.xitu.io/entry/57691d5d6be3ff006a438e09?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wild-flame](https://github.com/wild-flame) 翻译) +* [让 Webpack 来帮你打包吧](https://gold.xitu.io/entry/5767a975df0eea0062ffe193?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([达仔](https://github.com/Zhangjd) 翻译) +* [关于 PostCSS 普及的一点微小的工作](https://gold.xitu.io/entry/57635cdda341310064c5910a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [React 应用的性能优化之路](http://gold.xitu.io/entry/57621f7980dda4005f7332f3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([woota](https://github.com/woota) 翻译) +* [如何编写避免垃圾开销的实时 Javascript 代码](http://gold.xitu.io/entry/575d14937db2a2005437df32?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yangzj1992](http://www.qcyoung.com/) 翻译) +* [如何用 Flexbox 构建一个新闻网站布局](http://gold.xitu.io/entry/57580e885bbb500053bc70c4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangzhaoqi](https://github.com/joddiy) 翻译) +* [使用 BEM 来模块化你的 CSS 代码](http://gold.xitu.io/entry/5757ce7b7db2a200540d51eb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([杨龙龙](https://github.com/yllziv) 翻译) +* [减少 JPG 文件大小](http://gold.xitu.io/entry/574fe1aa79bc440052f698de?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shenxn](https://github.com/shenxn) 翻译) +* [使用重构件(Codemod)加速 JavaScript 开发和重构](http://gold.xitu.io/entry/574e49662e958a005e00f543?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Hikerpig](https://github.com/hikerpig) 翻译) +* [如何用 Babel 和 Rollup 来构建和发布 ES6 模块](http://gold.xitu.io/entry/574445d579bc44005c63265b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [10 个你可能不知道的事,关于 Facebook 内部开发环境是如何使用 JavaScript 和 GraphQL 的](http://gold.xitu.io/entry/5739f5dc71cfe400570ea59f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Jack](https://github.com/Jack-Kingdom) 翻译) +* [使用 ES6 写更好的 JavaScript part III:好用的集合和反引号](http://gold.xitu.io/entry/573e7ef91ea49300601c7332?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([godofchina](https://github.com/godofchina) 翻译) +* [使用 ES6 编写更好的 JavaScript Part II:深入探究 [类]](http://gold.xitu.io/entry/573969b91ea4930060f3e31a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Malcolm](https://github.com/malcolmyu) 翻译) +* [使用 ES6 写更好的 JavaScript part I:广受欢迎的新特性](http://gold.xitu.io/entry/5736e4f41532bc006545106e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huanglizhuo](https://github.com/huanglizhuo) 翻译) +* [网页端字体加载优化](http://gold.xitu.io/entry/5732936d49830c0061c7ec72?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shenxn](https://github.com/shenxn) 翻译) +* [怎样在不使用框架的基础上开发一个 Javascript 组件](http://gold.xitu.io/entry/572d5f132e958a0066873e2c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [ECMAScript 6 里面的私有变量](http://gold.xitu.io/entry/572c0b2d2e958a00667a081d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([XRene](https://github.com/CommanderXL) 翻译) +* [10 步带你做一个棒棒的 Hybrid 应用](http://gold.xitu.io/entry/5729a76479df5400608d1f9f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yves-X](https://github.com/Yves-X) 翻译) +* [JavaScript 姿势提升简略](http://gold.xitu.io/entry/5722c838128fe100601dc3a8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Hikerpig](https://github.com/hikerpig) 翻译) +* [Starlight - 在网页中运行 Lua](http://gold.xitu.io/entry/5719907eebcb7d005cc6acca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([narcotics726](https://github.com/narcotics726) 翻译) +* [React.js 新手村教程](http://gold.xitu.io/entry/5719b6acebcb7d006a007d9b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([markzhai](https://github.com/markzhai) 翻译) +* [使用 CSS 和 jQuery 来做一个墨水晕开的效果](http://gold.xitu.io/entry/57160c4b8ac2470062601b1f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [JavaScript 生态之乱象](http://gold.xitu.io/entry/5705e71ed342d3005418ea66?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([woota](https://github.com/woota) 翻译) +* [在网站 Logo 上右击时提示下载网站的 Logo 素材下载](http://gold.xitu.io/entry/570b2b671ea493005c024ee3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yushneng](https://github.com/rainyear) 翻译) +* [揭秘 IIFE 语法](http://gold.xitu.io/entry/5704e12771cfe4005dc85868?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huxpro](https://github.com/Huxpro) 翻译) +* [利用 :placeholder-shown 选择器实现 label 浮动效果](http://gold.xitu.io/entry/56de3c291532bc005620b320?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [响应式 GraphQL 结构](http://gold.xitu.io/entry/56de66fe731956005c46782a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shenxn](https://github.com/shenxn) 翻译) +* [[译] 在 BigCommerce 我们如何编写 CSS](http://gold.xitu.io/entry/56ce82cbc24aa800520f4215?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shenxn](https://github.com/shenxn) 翻译) +* [无缝迁移 Angular 1 项目到 Angular 2](http://gold.xitu.io/entry/56d3bd6a1ea493005c1eddfa?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([BOBO](https://github.com/CoderBOBO) 翻译) +* [在 chrome 的开发者工具里 debug node.js 代码](http://gold.xitu.io/entry/56d3cfea6be3ff005c5f9b89?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sqrthree](https://github.com/sqrthree) 翻译) +* [350 个特性看透 ES6](https://github.com/xitu/gold-miner/blob/master/TODO/es6.md)([Go7hic](https://github.com/dyygtfx) 翻译) +* [2015 年底 JS 必备工具集](http://gold.xitu.io/entry/56cee8afc24aa800545f73bb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([赵鑫晖](https://github.com/zxc0328) 翻译) +* [Promise 是如何工作的?](http://gold.xitu.io/entry/56cc0bcf8ac2470053b7c5ab?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/Zhangjd) 翻译) +* [JavaScript 开发者年度调查报告](http://gold.xitu.io/entry/56ca985071cfe40054d98994?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([sqrthree](https://github.com/sqrthree) 翻译) +* [Functional JavaScript 教程(一)](http://gold.xitu.io/entry/56d4e8b57db2a200556c64cb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [人人须知的 jQuery 技巧](http://gold.xitu.io/entry/56e1a95b731956005da35c24?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Yves-X](https://github.com/Yves-X) 翻译) diff --git a/integrals.md b/integrals.md index 3eead8dffd5..0d2f3b22c49 100644 --- a/integrals.md +++ b/integrals.md @@ -1429,10 +1429,15 @@ |[好的与坏的,Swift 语言面面观(一)](http://gold.xitu.io/entry/578c647a6be3ff006ce49e91)|校对|1| |[Android 中美腻的下划线](http://gold.xitu.io/entry/578705faa34131005b46e9c2)|校对|1| -## 译者:[tanglie1993](https://github.com/tanglie1993/) 历史贡献积分:90.5 当前积分:90.5 二零二零:5.5 +## 译者:[tanglie1993](https://github.com/tanglie1993/) 历史贡献积分:109.5 当前积分:74.5 二零二一:13 |文章|类型|积分| |------|-------|-------| +|[自己写一个 redux](https://juejin.cn/post/6923922875191656462)|翻译|13| +|2020 年 5 月 兑换 小米台灯 1 个|减去积分|35| +|[分享我喜欢的十五条 JavaScript 编程技巧](https://github.com/xitu/gold-miner/blob/master/article/2020/my-favorite-javascript-tips-and-tricks.md)|校对|2| +|[我的 React 组件会渲染两次,我快疯了](https://juejin.im/post/6858508463274885134)|翻译|3| +|8 月推荐前端文章 1 篇|奖励|1| |[Deno 会对 Node 造成威胁吗?](https://juejin.im/post/5ecf6f166fb9a047d77cbe35)|校对|2| |[关于 let 和 const 的对比](https://juejin.im/post/5ed5ec4ae51d457b3e77e37c)|翻译|2.5| |5 月推荐前端文章 1 篇|奖励|1| @@ -1623,10 +1628,11 @@ |------|-------|-------| |[ES6 中 的 var、let 和 const 应该如何选择?](http://gold.xitu.io/entry/57962ef22e958a00651f7387)|校对|1| -## 译者:[rottenpen](https://github.com/rottenpen) 历史贡献积分:47.5 当前积分:47.5 +## 译者:[rottenpen](https://github.com/rottenpen) 历史贡献积分:47.5 当前积分:47.5 二零二一:0 |文章|类型|积分| |------|-------|-------| +|[GitHub 2020 报告:全球软件安全](https://github.com/xitu/Annual-Survey/blob/main/2020/github/GitHub%202020%20报告:全球软件安全.pdf)|翻译|0| |推荐英文文章一篇|奖励|1| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|3.5| |[JWT:JSON Web Tokens 全方位指南](https://juejin.im/entry/5a4f300f6fb9a01cb912b3c7/)|翻译|13| @@ -1943,10 +1949,11 @@ |[JavaScript ES6 核心功能一览](http://gold.xitu.io/entry/58189177128fe100559efd51/)|校对|1| |[Swift 3,这些陷阱在等你](http://gold.xitu.io/entry/57f6fa03816dfa0056a4d782/)|校对|1| -## 译者:[XatMassacrE](https://github.com/XatMassacrE) 历史贡献积分:96 当前积分:96 +## 译者:[XatMassacrE](https://github.com/XatMassacrE) 历史贡献积分:98 当前积分:98 二零二一:2 |文章|类型|积分| |------|-------|-------| +|[在 Flutter 中使用 Provider 构建底部导航栏](https://juejin.cn/post/6930515324815015949)|翻译|2| |[以太坊钱包详解](https://juejin.im/post/5ae2942ff265da0b886d23df)|翻译|12| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译|24| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译|14| @@ -2082,10 +2089,11 @@ |[理解 iOS 应用程序的代码签名 (CODE SIGN) 机制](http://gold.xitu.io/entry/5826ef85570c3500586b241d/)|校对|1| |[Swift 3 语言中的全模块优化](http://gold.xitu.io/entry/5818b6f52f301e005cf0ef8e/)|校对|1| -## 译者:[Herman](https://github.com/actini) 历史贡献积分:149 当前积分:54 +## 译者:[Herman](https://github.com/actini) 历史贡献积分:149 当前积分:19 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 米家 LED 智能台灯 1 个|减去积分|35| |[理解数据库分片](https://juejin.im/entry/5c791672f265da2da67c46eb)|翻译|7| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译|14| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译|9.5| @@ -2970,10 +2978,42 @@ |[你正在阅读的用户体验文章是不是在向你进行推销?](https://juejin.im/post/58d4c501a22b9d00645544d9)|校对|2| |[震惊,还可以用这种姿势学习编程](https://juejin.im/post/58d3ebd4128fe1006cb43722)|翻译|3| -## 译者:[lsvih](https://github.com/lsvih) 历史贡献积分:413.5 当前积分:347.5 二零二零:28.5 - -|文章|类型|积分| -|------|-------|-------| +## 译者:[lsvih](https://github.com/lsvih) 历史贡献积分:495.5 当前积分:415.5 二零二一:40.5 + +|文章|类型|积分| +|------|-------|-------| +|[TypeScript 4.2 正式发布:优化了类型和开发者体验](https://juejin.cn/post/6935255387893399560)|校对|2| +|[自适应 CSS 栅格:自由布局的最终版本](https://juejin.cn/post/6935090806210428959)|校对|1| +|[Bash 中的 if else 语句](https://juejin.cn/post/6934324540692496392)|校对|2| +|[你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)|校对|5| +|[恭喜 Safari 荣获「第二个 Internet Explorer」的美誉](https://juejin.cn/post/6929754875001569294)|校对|2| +|[基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)|校对|3| +|[如何利用隐语义模型在图数据库中构建推荐系统](https://juejin.cn/post/6925019556108828685)|校对|4| +|[自己写一个 redux](https://juejin.cn/post/6923922875191656462)|校对|8| +|[构建设计系统和组件库](https://juejin.cn/post/6924152501805678606)|校对|5| +|[UIKit 和 SwiftUI:我该选择哪一个运用在实际产品开发中?](https://juejin.cn/post/6923197105422991367)|校对|4| +|[10 个你应该现在启用的绝佳的 Chrome Flags](https://juejin.cn/post/6923198038894706701)|校对|1| +|[Flutter 中内置的显式动画](https://juejin.cn/post/6918698096109191175)|校对|2.5| +|[Flutter 中的交织动画](https://juejin.cn/post/6918693294083932173)|校对|1| +|[DeepSpeed:所有人都能用的超大规模模型训练工具](https://juejin.cn/post/6916500899577724942)|校对|0| +|由于 [7246](https://github.com/xitu/gold-miner/pull/7246) 减去积分|减去积分|6| +|[2021 年 Web 开发者应该掌握的 15 个 VSCode 扩展](https://juejin.cn/post/6910570256645914637)|校对|2| +|[提高开发效率的五个 Chrome 扩展程序](https://juejin.cn/post/6903831004034072589)|校对|0.5| +|[SwiftUI 黑暗模式——最简单的方法](https://juejin.cn/post/6905925634552233998)|校对|1| +|[寻找最优化 AutoML 库](https://juejin.cn/post/6906859687682965517)|校对|4| +|[在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)|校对|2| +|[JavaScript 颜色处理库 Chroma.js 的应用](https://juejin.cn/post/6886263418907688974)|校对|0.5| +|[浏览器 Web History API 的应用](https://juejin.cn/post/6891500768973553672)|校对|0.5| +|[抽象数据类型与软件危机](https://juejin.cn/post/6900761312532529166)|校对|5| +|[使用 Shpinx 为 Python 项目自动生成文档](https://juejin.cn/post/6882904677373968397)|校对|2| +|[让神经网络变得更小巧以方便部署](https://juejin.im/post/6873068232505458701)|校对|5| +|[使用合成数据改善机器学习中的极度不平衡数据集](https://juejin.im/post/6872609287802388488)|校对|2| +|[知识的极限](https://juejin.im/post/6874475968325484552)|校对|3| +|由于 [7130](https://github.com/xitu/gold-miner/pull/7130) 减去积分|减去积分|14| +|[从头开始到最初的 10 个客户:我是如何设计并推出一个 SaaS 产品](https://juejin.im/post/6860850397293232141)|校对|5| +|[JavaScript 技巧 —— 子代构造函数,文本选择,内联 Workers 等等](https://juejin.im/post/6854573219622420488)|校对|1| +|[Javascript 应用中引入 CSS 的几种方式](https://juejin.im/post/6867054761741549576)|翻译|3| +|[使用 Node.js 控制树莓派 4 的 GPIO](https://juejin.im/post/6868946182325043207)|校对|5| |[在 Swift 中使用 MVVM 架构实现无限滚动和图片加载](https://juejin.im/post/5ecb8115e51d4578540fcacd)|校对|3| |[0202 年了,是时候学习 Combine 了](https://juejin.im/post/5ec0d8946fb9a0433a19101f)|校对|5| |[用 SwiftUI 实现酷炫的颜色切换动画](https://juejin.im/post/5eb39472e51d454dae5575cd)|校对|3| @@ -3361,10 +3401,12 @@ |------|-------|-------| |[开发者(也就是我)与Rx Observable 类的对话 [ Android RxJava2 ] ( 这到底是什么?) 第五部分](https://juejin.im/post/590ab4f7128fe10058f35119)|校对|1| -## 译者:[leviding](https://github.com/leviding) 历史贡献积分:196 当前积分:151 +## 译者:[leviding](https://github.com/leviding) 历史贡献积分:196 当前积分:16 二零二一:0 |文章|类型|积分| |------|-------|-------| +|兑换 3 件卫衣|减去积分|135| +|[GitHub 2020 报告:在工作和娱乐之间找到平衡](https://github.com/xitu/Annual-Survey/blob/main/2020/github/GitHub%202020%20报告:在工作和娱乐之间找到平衡.pdf)|翻译|0| |[如何在 Keras 中用 YOLOv3 进行对象检测](https://juejin.im/post/5d12eef5e51d455a68490ba8)|校对|4| |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|7| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|20| @@ -3971,10 +4013,11 @@ |[结构体指针](https://juejin.im/post/59a60cc1f265da249a201ae9)|校对|1| |[iOS 响应式编程:Swift 中的轻量级状态容器](https://juejin.im/post/599652ee6fb9a024903a8d59)|校对|1| -## 译者:[lampui](https://github.com/lampui) 历史贡献积分:52.5 当前积分:37.5 +## 译者:[laampui](https://github.com/laampui) 历史贡献积分:58.5 当前积分:43.5 二零二一:6 |文章|类型|积分| |------|-------|-------| +|[在 Node.js 中避免内存泄漏:性能最佳实践](https://juejin.cn/post/6911488842079928327)|翻译|6| |[Python 是解决任何问题的完美工具](https://juejin.im/post/5aa74bf95188255568686ae0)|校对|1| |[前端开发者指南 2018](https://github.com/xitu/front-end-handbook-2018)|翻译校对|4.5| |[14 个你可能不知道的 JavaScript 调试技巧](https://juejin.im/entry/5a0001b86fb9a0451a75c591)|校对|1| @@ -4007,10 +4050,11 @@ |[如何在 iOS 上实现类似 Airbnb 中的可展开式菜单](https://juejin.im/post/59acdf2b6fb9a024763806cf)|校对|1| |[巧用 ARKit 和 SpriteKit 从零开始做 AR 游戏](https://juejin.im/post/599aaf746fb9a02477072380)|校对|2| -## 译者:[thisisandy](https://github.com/thisisandy) 历史贡献积分:5.5 当前积分:5.5 +## 译者:[thisisandy](https://github.com/thisisandy) 历史贡献积分:11.5 当前积分:11.5 |文章|类型|积分| |------|-------|-------| +|[Javascript 应用中引入 CSS 的几种方式](https://juejin.im/post/6867054761741549576)|翻译|6| |[扁平化的 UI 元素既朴实又玄乎](https://juejin.im/post/59c0d3305188256bce40e884)|校对|1.5| |[Angular 与 React:谁更适合前端开发](https://juejin.im/post/59ab51746fb9a024865d202b)|校对|3| |[别再使用图片轮播了](https://juejin.im/post/599cf1596fb9a02481205803)|校对|1| @@ -4400,10 +4444,13 @@ |------|-------|-------| |[RNN 循环神经网络系列 4: 注意力机制](https://juejin.im/post/59f72f61f265da432002871c)|校对|2| -## 译者:[Raoul1996](https://github.com/Raoul1996) 历史贡献积分:127.5 当前积分:44.5 二零二零:15.5 +## 译者:[Raoul1996](https://github.com/Raoul1996) 历史贡献积分:136.5 当前积分:5.5 |文章|类型|积分| |------|-------|-------| +|2020 年 5 月 兑换 小米台灯 1 个|减去积分|35| +|2020 年 10 月 兑换 鼠标垫 1 个|减去积分|13| +|[Web Locks API:跨 Tab 资源同步](https://juejin.cn/post/6895792867080405005)|翻译|9| |[使用 JavaScript ES2020 中所有的 7 个新特性构建 App](https://juejin.im/post/5e9a685951882573834edc9e)|校对|3| |[防止 Git 泄漏的 5 种最佳做法](https://juejin.im/post/5e9e971851882573b047541e)|校对|2| |[Kafka vs. RabbitMQ:为什么使用 Kafka?](https://juejin.im/post/5e9e29c8f265da47a831421a)|校对|2| @@ -5044,10 +5091,11 @@ |[做好准备:新的 V8 即将到来,Node.js 的性能正在改变。](https://juejin.im/post/5aaf755851882555627d16e5)|校对|3| |[论原子 CSS 的日益普及](https://juejin.im/post/5a4387af6fb9a045186b04d1)|校对|1.5| -## 译者:[lcx-seima](https://github.com/lcx-seima) 历史贡献积分:40 当前积分:40 +## 译者:[lcx-seima](https://github.com/lcx-seima) 历史贡献积分:46 当前积分:46 |文章|类型|积分| |------|-------|-------| +|[在 Swift 中玩转 emoji](https://juejin.cn/post/6887739774254841863)|翻译|6| |[在 Flask 中使用 Redis Queue 实现异步任务](https://juejin.im/post/5c407497e51d457cba6ca871)|翻译|2.5| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|5| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|4.5| @@ -5059,10 +5107,13 @@ |[在 Redux 中使用 AJAX 轮询](https://juejin.im/post/5a43b6da5188257d167a7aef)|翻译|2| |[在 Redux 中使用 AJAX 轮询(二):Saga 篇](https://juejin.im/post/5a43b80df265da43176a6e4e)|翻译|3| -## 译者:[FateZeros](https://github.com/FateZeros) 历史贡献积分:35 当前积分:10 +## 译者:[FateZeros](https://github.com/FateZeros) 历史贡献积分:43 当前积分:18 |文章|类型|积分| |------|-------|-------| +|[Vue 应用的代码覆盖率](https://juejin.im/post/6872653403177254919)|校对|2| +|[前端开发 8 大性能分析工具](https://juejin.im/post/6860664312504320014)|校对|3| +|[如何在字符串中隐藏秘密 —— JavaScript 中的现代文本隐藏](https://juejin.im/post/6856737400396349454)|校对|3| |[优化 WEBPACK 以更快地构建 REACT](https://juejin.im/post/5ae003d86fb9a07a9e4ce25d)|校对|0.5| |[Node.js 能进行 HTTP/2 推送啦!](https://juejin.im/post/5ad61595f265da23a04a129c)|校对|1| |[Web 爬虫下的 Python 数据分析:中情局全球概况图解](https://juejin.im/post/5ab9fcebf265da238e0dc349)|校对|1.5| @@ -5384,10 +5435,11 @@ |[这些 CSS 命名规范将省下你大把调试时间](https://juejin.im/post/5a6c5881518825733201daf7)|校对|2| |[Facebook 开源了物体检测研究项目 Detectron](https://juejin.im/post/5a6c2ba56fb9a01cb64f0591)|校对|0.5| -## 译者:[xingqiwu55555](https://github.com/xingqiwu55555) 历史贡献积分:17 当前积分:17 +## 译者:[xingqiwu55555](https://github.com/xingqiwu55555) 历史贡献积分:17 当前积分:11 |文章|类型|积分| |------|-------|-------| +|2019 年 8 月 兑换 纪念币 1 个|减去积分|6| |[在 Google Apps 脚本中使用 ES6 和 npm 模块](https://juejin.im/post/5ce350c3e51d4510727c7fd0)|翻译|5.5| |[ES6:理解参数默认值的实现细节](https://juejin.im/post/5cd0eab95188251b984d8abe)|校对|1.5| |[对 React 组件进行单元测试](https://juejin.im/post/5cb9c62a6fb9a0688d2e4689)|校对|3| @@ -5520,10 +5572,12 @@ |[从 SQLite 逐步迁移到 Room](https://juejin.im/post/5a8c3a2cf265da4e761fd721)|校对|1| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|1.5| -## 译者:[snowyYU](https://github.com/snowyYU) 历史贡献积分:14 当前积分:14 二零二零:5 +## 译者:[snowyYU](https://github.com/snowyYU) 历史贡献积分:19.5 当前积分:19.5 |文章|类型|积分| |------|-------|-------| +|[MVC,MVP,MVVM 对比](https://juejin.cn/post/6883088734699388941)|翻译|4| +|[8 个有用的 SCSS 最佳实践](https://juejin.im/post/6862499761351163911)|翻译|1.5| |[2020 年用各大前端框架构建的 RealWorld 应用对比](https://juejin.im/post/5e887c48f265da47f60ea6ce)|翻译|5| |[json — JavaScript 对象表示法](https://juejin.im/post/5a9432ae5188257a5c6092b0)|翻译|2.5| |[教你使用 CSS 计数器](https://juejin.im/post/5a811c6251882528b63ff8d7)|校对|0.5| @@ -5731,10 +5785,11 @@ |[在 V8 引擎中设置原型(prototypes)](https://juejin.im/post/5a9921e76fb9a028bd4bc3c4)|校对|1| |[json — JavaScript 对象表示法](https://juejin.im/post/5a9432ae5188257a5c6092b0)|校对|1| -## 译者:[rydensun](https://github.com/rydensun) 历史贡献积分:80 当前积分:44 +## 译者:[rydensun](https://github.com/rydensun) 历史贡献积分:80 当前积分:9 |文章|类型|积分| |------|-------|-------| +|2019 年 10 月 兑换 小米台灯 1 个|减去积分|35| |2019 年 3 月兑掘金鼠标垫 1 个|减去积分|13| |2019 年 3 月兑掘金鼠标垫 1 个|减去积分|13| |[快速原型设计的新手指南](https://juejin.im/user/585b9407da2f6000657a5c0c)|翻译|6| @@ -5952,10 +6007,11 @@ |[让 Apache Cassandra 尾部延迟减小 10 倍(已开源)](https://juejin.im/post/5ac31083f265da239a5fff0c)|翻译|4| |[让我们来简化 UserDefaults 的使用](https://juejin.im/post/5abde324f265da23826e1723)|校对|0.5| -## 译者:[EmilyQiRabbit](https://github.com/EmilyQiRabbit) 历史贡献积分:260.5 当前积分:240.5 二零二零:4 +## 译者:[EmilyQiRabbit](https://github.com/EmilyQiRabbit) 历史贡献积分:261.5 当前积分:241.5 |文章|类型|积分| |------|-------|-------| +|推荐前端文章 1 篇|奖励|1| |5 月推荐前端文章 1 篇|奖励|1| |4 月推荐前端文章一篇|奖励|1| |2020 年 2 月推荐文章 1 篇|奖励|1| @@ -6086,10 +6142,13 @@ |[使用 Swift 实现原型动画](https://juejin.im/post/5ae28a9b6fb9a07aaa10fa1e)|校对|2| |[不使用 fastlane 实现持续交付的 5 种选项](https://juejin.im/post/5acf47cb6fb9a028c523944c)|翻译|5| -## 译者:[luochen1992](https://github.com/luochen1992) 历史贡献积分:58.5 当前积分:13.5 +## 译者:[luochen1992](https://github.com/luochen1992) 历史贡献积分:67.5 当前积分:22.5 二零二一:6 |文章|类型|积分| |------|-------|-------| +|[DeepSpeed:所有人都能用的超大规模模型训练工具](https://juejin.cn/post/6916500899577724942)|校对|6| +|[Python List 使用注意事项](https://juejin.cn/post/6886633614717485070)|校对|2| +|[通过“四不要”掌握 Python 中的 Lambda 函数](https://juejin.cn/post/6883389756269395975)|校对|1| |[哪一个深度学习框架增长最迅猛?TensorFlow 还是 PyTorch?](https://juejin.im/post/5caefef45188251b070f7d70)|校对|1.5| |[为什么我放弃了 React 而转向 Vue](https://juejin.im/post/5c2c27096fb9a049f66c3672)|校对|2| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|1| @@ -6226,10 +6285,11 @@ |[用户体验中的稀缺性:成为常态的心理偏见](https://juejin.im/post/5aef0943518825672a02d2ca)|校对|1.5| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|2| -## 译者:[sisibeloved](https://github.com/sisibeloved) 历史贡献积分:85 当前积分:85 +## 译者:[sisibeloved](https://github.com/sisibeloved) 历史贡献积分:85 当前积分:85 二零二一:0 |文章|类型|积分| |------|-------|-------| +|[GitHub 2020 报告:赋能社区健康](https://github.com/xitu/Annual-Survey/blob/main/2020/github/GitHub%202020%20报告:赋能社区健康.pdf)|翻译|0| |[使用 WFST 进行语音识别](https://juejin.im/post/5cd7f7c56fb9a03218556ea4)|翻译|4.5| |[使用 Python Flask 框架发布机器学习 API](https://juejin.im/post/5cd7f862e51d453aa44ad6f3)|翻译|2.5| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|10| @@ -6421,10 +6481,12 @@ |[Awesome Flutter 校对](https://github.com/xitu/awesome-flutter)|校对|1| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|1| -## 译者:[lihanxiang](https://github.com/lihanxiang) 历史贡献积分:70 当前积分:32 二零二零:2 +## 译者:[lihanxiang](https://github.com/lihanxiang) 历史贡献积分:70 当前积分:2 |文章|类型|积分| |------|-------|-------| +|2020 年 9 月 兑换 掘金桌垫 1 个|减去积分|13| +|2019 年 8 月 兑换 鲁班锁 1 个|减去积分|17| |[如何使用 Python 生成随机文本验证码](https://juejin.im/post/5f1567a3f265da22db2c351d)|校对|2| |[开源难题:如何保持长久](https://juejin.im/post/5db27be36fb9a02040687055)|翻译|4.5| |[用 Apache Shiro 来强化一个 Spring Boot 应用](https://juejin.im/post/5c9f60c7e51d451cf929305d)|翻译|3.5| @@ -6571,7 +6633,7 @@ |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|4| |[怎样(以及为什么要)保持你的 Git 提交记录的整洁](https://juejin.im/post/5b29060ee51d4558cd2adac0)|校对|1.5| -## 译者:[xujunjiejack](https://github.com/xujunjiejack) 历史贡献积分:18 当前积分:18 二零二零:2 +## 译者:[xujunjiejack](https://github.com/xujunjiejack) 历史贡献积分:18 当前积分:18 |文章|类型|积分| |------|-------|-------| @@ -6807,10 +6869,11 @@ |[如何用 Python 从零开始构建你自己的神经网络](https://juejin.im/post/5c7a478c518825787e6a0f67)|翻译|4| |[从 Java EE 8 Security API 开始 — 第一部分](https://juejin.im/post/5b35a8d4f265da599423598b)|校对|3| -## 译者:[cf020031308](https://github.com/cf020031308) 历史贡献积分:50 当前积分:27 +## 译者:[cf020031308](https://github.com/cf020031308) 历史贡献积分:56 当前积分:33 二零二一:6 |文章|类型|积分| |------|-------|-------| +|识别网络中连接紧密的用户|翻译|6| |2019 年 05 月兑掘金鼠标垫 1 个|减去积分|13| |2018 年 10 月兑掘金鼠标垫 1 个|减去积分|10| |[2018 年度最佳数据库即服务解决方案](https://juejin.im/post/5ba784e3e51d450e9d64984d)|翻译|7| @@ -6838,10 +6901,11 @@ |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|3.5| |[修订 The JavaScript Tutorial](https://github.com/xitu/javascript-tutorial-zh/pull/151)|修订|1| -## 译者:[ssshooter](https://github.com/ssshooter) 历史贡献积分:62 当前积分:62 二零二零:3 +## 译者:[ssshooter](https://github.com/ssshooter) 历史贡献积分:62 当前积分:2 |文章|类型|积分| |------|-------|-------| +|2020 年 7 月 兑换 树莓派 1 个|减去积分|60| |[如何在 JavaScript 中使用新特性“顶层 await”](https://juejin.im/post/5ec67516e51d45787161978e)|翻译|3| |[我与 Flutter 的一年](https://juejin.im/post/5c5aeb8a6fb9a04a027acddf)|翻译|5| |[什么是模块化 CSS?](https://juejin.im/post/5bb6c5195188255c9e02e6f3)|翻译|9| @@ -6877,10 +6941,12 @@ |------|-------|-------| |[通过 SSH 远程使用 Python 解释器来运行 Flask](https://juejin.im/post/5b3e25a8e51d45191716d187)|校对|1.5| -## 译者:[yqian1991](https://github.com/yqian1991) 历史贡献积分:46.5 当前积分:46.5 +## 译者:[yqian1991](https://github.com/yqian1991) 历史贡献积分:52.5 当前积分:52.5 二零二一:5 |文章|类型|积分| |------|-------|-------| +|[Elasticsearch 新手指南](https://juejin.cn/post/6913725535717851144)|翻译|5| +|12 月推荐后端文章 1 篇|奖励|1| |[初创公司的数据科学:简介](https://juejin.im/post/5bd55b76f265da0ae472ce1b)|校对|2.5| |[开源项目之 Nginx](https://juejin.im/post/5bc55a25f265da0ae8014147)|校对|5| |[数据科学和机器学习面试问题](https://juejin.im/post/5bbb104f5188255c960c4d7e)|校对|1.5| @@ -6955,10 +7021,11 @@ |[让我们一起解决“this”难题  —  第二部分](https://juejin.im/post/5b6915cce51d4519962f0ca7)|校对|2| |[The JavaScript Tutorial 翻译](https://github.com/xitu/javascript-tutorial-en)|翻译校对|2.5| -## 译者:[xutaogit](https://github.com/xutaogit) 历史贡献积分:62 当前积分:55 +## 译者:[xutaogit](https://github.com/xutaogit) 历史贡献积分:67 当前积分:60 |文章|类型|积分| |------|-------|-------| +|[页面生命周期 API:每一个前端开发者都应该知道的浏览器 API](https://juejin.cn/post/6906779518040539144)|翻译|5| |[推广 PWA 安装的模式(移动端)](https://juejin.im/post/5d2746f1f265da1b7638cd1f)|翻译|6| |[Vue Router 实战手册](https://juejin.im/post/5c62ab05f265da2da83555a0)|翻译|5| |[我们采用 GraphQL 技术的经验:营销技术活动](https://juejin.im/post/5c4522566fb9a049d2365cd6)|翻译|5| @@ -7006,10 +7073,11 @@ |[在 Sketch 中使用一个设计体系创作: 第二部分 [教程]](https://juejin.im/post/5b5d2a456fb9a04fc80b8f4b)|翻译|2.5| |[在 Sketch 中使用一个设计体系创作:第一部分 [教程]](https://juejin.im/post/5b591a655188257bca290b24)|校对|0.5| -## 译者:[Park-ma](https://github.com/Park-ma) 历史贡献积分:54 当前积分:9 +## 译者:[Park-ma](https://github.com/Park-ma) 历史贡献积分:57 当前积分:12 |文章|类型|积分| |------|-------|-------| +|[用 Python 写一个俄罗斯方块游戏](https://juejin.im/post/6844904183456350221)|校对|3| |[用长短期记忆网络预测股票市场(使用 Tensorflow)](https://juejin.im/post/5c8114de51882540a830b910)|校对|2| |[论数据流的扩展性](https://juejin.im/post/5c8329d25188257ea038a05e)|翻译|4| |2019 年 3 月兑 Google DIY 纸板音箱 1 个|减去积分|45| @@ -7127,7 +7195,7 @@ |[关于 React Motion 的简要介绍](https://juejin.im/post/5b48061551882519790c77f3)|校对|1.5| |[设计 React 组件 API](https://juejin.im/post/5b545f0b6fb9a04fc93748ba)|翻译|3| -## 译者:[Eternaldeath](https://github.com/Eternaldeath) 历史贡献积分:10 当前积分:10 二零二零:2 +## 译者:[Eternaldeath](https://github.com/Eternaldeath) 历史贡献积分:10 当前积分:10 |文章|类型|积分| |------|-------|-------| @@ -7139,10 +7207,14 @@ |[一行 JavaScript 代码竟然让 FT.com 网站慢了十倍](https://juejin.im/post/5b7bb6dfe51d4538bf55aa5f)|校对|1| |[使用 Web Beacon API 记录活动](https://juejin.im/post/5b694b5de51d4519700fa56a)|校对|1| -## 译者:[YueYongDev](https://github.com/YueYongDev) 历史贡献积分:77.5 当前积分:42.5 二零二零:10.5 +## 译者:[YueYongDev](https://github.com/YueYongDev) 历史贡献积分:105.5 当前积分:70.5 |文章|类型|积分| |------|-------|-------| +|[5 分钟内从单体架构迁移到微服务架构](https://juejin.cn/post/6900884077226917901)|翻译|5| +|[在几秒钟内为你的开发环境创建一个私有 PostgreSQL 数据库](https://juejin.cn/post/6899674625325105159)|翻译|8| +|[从头开始到最初的 10 个客户:我是如何设计并推出一个 SaaS 产品](https://juejin.im/post/6860850397293232141)|翻译|12| +|[如何创建一个可复用的网页爬虫](https://juejin.im/post/6860354555759869966)|翻译|3| |[使用 GraphQL 的 6 个月](https://juejin.im/post/5eb63dfae51d454dea6fdd78)|翻译|3.5| |[防止 Git 泄漏的 5 种最佳做法](https://juejin.im/post/5e9e971851882573b047541e)|翻译|4| |[写一个愚蠢的 flutter 图标包](https://juejin.im/post/5dad820ce51d4524ce222642)|翻译|3| @@ -7170,10 +7242,12 @@ |------|-------|-------| |[Slidable:一个 Flutter 的故事](https://juejin.im/post/5b5e84b86fb9a04fa91bfeb6)|校对|1.5| -## 译者:[CoolRice](https://github.com/CoolRice) 历史贡献积分:138 当前积分:68 二零二零:16 +## 译者:[CoolRice](https://github.com/CoolRice) 历史贡献积分:138 当前积分:-27 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 树莓派 1 个|减去积分|60| +|2019 年 7 月 兑换 小米台灯 1 个|减去积分|35| |[5 大 JavaScript 字符串操作库](https://juejin.im/post/5eba6becf265da7bb8773420)|校对|2| |[ECMAScript 2020 新特性](https://juejin.im/post/5ec34ed96fb9a0437b76f638)|校对|2| |[纯 JavaScript 版本的 Lodash 数组 Filtering 和 Manipulation 方法](https://juejin.im/post/5ec614196fb9a047b46b14f3)|翻译|3.5| @@ -7226,10 +7300,11 @@ |[用 Scikit-Learn 实现 SVM 和 Kernel SVM](https://juejin.im/post/5b7fd39af265da43831fa136)|翻译|6| |[如何提升设计到开发的协作效率](https://juejin.im/post/5b83609de51d4538c210a957)|校对|2| -## 译者:[zhusimaji](https://github.com/zhusimaji) 历史贡献积分:57.5 当前积分:29.5 +## 译者:[zhusimaji](https://github.com/zhusimaji) 历史贡献积分:66.5 当前积分:38.5 |文章|类型|积分| |------|-------|-------| +|[寻找最优化 AutoML 库](https://juejin.cn/post/6906859687682965517)|翻译|9| |2019 年 04 月兑掘金鼠标垫 1 个,谷歌猪年手办 1 个|减去积分|28| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|17| |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|28| @@ -7237,10 +7312,13 @@ |[TensorFlow 官方文档翻译](https://github.com/xitu/tensorflow-docs)|翻译校对|8| |[用 Scikit-Learn 实现 SVM 和 Kernel SVM](https://juejin.im/post/5b7fd39af265da43831fa136)|校对|2| -## 译者:[TrWestdoor](https://github.com/TrWestdoor) 历史贡献积分:43 当前积分:33 +## 译者:[TrWestdoor](https://github.com/TrWestdoor) 历史贡献积分:49.5 当前积分:26.5 二零二一:6.5 |文章|类型|积分| |------|-------|-------| +|[如何利用隐语义模型在图数据库中构建推荐系统](https://juejin.cn/post/6925019556108828685)|校对|4| +|[Elasticsearch 新手指南](https://juejin.cn/post/6913725535717851144)|校对|2.5| +|2020 年 10 月 兑换 鼠标垫 1 个|减去积分|13| |[人工智能何以留存](https://juejin.im/post/5d4c1155e51d4562061159d1)|校对|2| |[由浅入深理解主成分分析](https://juejin.im/post/5d41321df265da03c926d65a)|校对|2| |[在 Python 中过度使用列表解析器和生成表达式](https://juejin.im/post/5d281b0ff265da1b8b2b8ae0)|校对|1.5| @@ -7535,10 +7613,11 @@ |[以面试官的角度来看 React 工作面试](https://juejin.im/post/5bca74cfe51d450e9163351b)|校对|1.5| |[你需要知道的所有 Flexbox 排列方式](https://juejin.im/post/5bc728f2f265da0aef4e3f6d)|校对|3.5| -## 译者:[Ivocin](https://github.com/Ivocin) 历史贡献积分:77.5 当前积分:77.5 +## 译者:[Ivocin](https://github.com/Ivocin) 历史贡献积分:78.5 当前积分:78.5 二零二一:1 |文章|类型|积分| |------|-------|-------| +|[我后悔没有在自己成为 React 开发者之前做的 6 件事情](https://juejin.cn/post/6934144158332354567)|校对|1| |[为什么我用 JavaScript 来编写 CSS](https://juejin.im/post/5c8878b7f265da2deb6ae6f2)|翻译|2| |[Hooks 对 Vue 而言意味着什么](https://juejin.im/post/5c7784d5f265da2de713629c)|翻译|4| |[2019 前端性能优化年度总结 — 第四部分](https://juejin.im/post/5c56345951882524b77b9f20)|翻译|13| @@ -7618,10 +7697,11 @@ |------|-------|-------| |[深入理解 React 高阶组件](https://juejin.im/entry/5bdd226cf265da616f6f6cce)|校对|4| -## 译者:[iWeslie](https://github.com/iWeslie) 历史贡献积分:135.5 当前积分:83.5 +## 译者:[iWeslie](https://github.com/iWeslie) 历史贡献积分:135.5 当前积分:23.5 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 树莓派套餐 1 个|减去积分|60| |[Xcode 和 LLDB 高级调试教程:第 3 部分](https://juejin.im/post/5d383c7d5188257dab043145)|校对|1| |[Web 端的 SwiftUI:SwiftWebUI](https://juejin.im/post/5d35e0ac5188257dc103e364)|校对|1.5| |[Xcode 和 LLDB 高级调试教程:第 2 部分](https://juejin.im/post/5d2321eee51d454f71439d64)|校对|1| @@ -7716,7 +7796,7 @@ |------|-------|-------| |[使用递归神经网络(LSTMs)对时序数据进行预测](https://juejin.im/post/5bf8a70cf265da61776ba1dc)|校对|2| -## 译者:[weibinzhu](https://github.com/weibinzhu) 历史贡献积分:22 当前积分:12 二零二零:3 +## 译者:[weibinzhu](https://github.com/weibinzhu) 历史贡献积分:22 当前积分:12 |文章|类型|积分| |------|-------|-------| @@ -7813,10 +7893,11 @@ |[避免那些可恶的 "cannot read property of undefined" 错误](https://juejin.im/post/5c810170e51d450a453fb48e)|翻译|3| |[写给 React 开发者的自定义元素指南](https://juejin.im/post/5c0873a8e51d451de96890dc)|校对|3| -## 译者:[newraina](https://github.com/newraina) 历史贡献积分:13 当前积分:13 +## 译者:[newraina](https://github.com/newraina) 历史贡献积分:14 当前积分:14 二零二一:1 |文章|类型|积分| |------|-------|-------| +|1 月推荐前端文章 1 篇|奖励|1| |推荐英文文章一篇|奖励|1| |[用 Shadow DOM v1 和 Custom Elements v1 实现一个原生 Web Component](https://juejin.im/post/5c1a401b6fb9a049c042fa07)|翻译|9| |[以太坊入门:互联网政府](https://juejin.im/post/5c03c68851882551236eaa82)|翻译|3| @@ -7937,16 +8018,26 @@ |推荐英文文章一篇|奖励|1| |[误解 ES6 模块,升级 Babel 的一个解决方案(泪奔)](https://juejin.im/post/5c223f4ce51d452626296b5d)|校对|1.5| -## 译者:[tonylua](https://github.com/tonylua) 历史贡献积分:2.5 当前积分:2.5 +## 译者:[tonylua](https://github.com/tonylua) 历史贡献积分:30 当前积分:30 |文章|类型|积分| |------|-------|-------| +|[JavaScript ES2021 中激动人心的特性](https://juejin.cn/post/6892246810250477575)|翻译|2| +|[TypeScript:一个好泛型的价值](https://juejin.im/post/6878868818836488205)|翻译|6| +|[ES2017 最佳特性  —  数组中的异步函数以及共享缓冲区](https://juejin.im/post/6878849121269055501)|翻译|3| +|[VueJS 中更好的组件组合方式](https://juejin.im/post/6875236830984437768)|翻译|3| +|[Vue 应用的代码覆盖率](https://juejin.im/post/6872653403177254919)|翻译|4| +|[如何处理 JavaScript 比较中的临界情况](https://juejin.im/post/6872682987859738632)|翻译|4.5| +|[世界比以往任何时候都更需要 Web 可访问性](https://juejin.im/post/6872684910058930189)|翻译|5| |[无容器下的云计算](https://juejin.im/post/5c24800a518825673b02dcfe)|校对|2.5| -## 译者:[SHERlocked93](https://github.com/SHERlocked93) 历史贡献积分:32 当前积分:32 +## 译者:[SHERlocked93](https://github.com/SHERlocked93) 历史贡献积分:36 当前积分:36 二零二一:1 |文章|类型|积分| |------|-------|-------| +|1 月推荐后端文章 1 篇|奖励|1| +|推荐前端文章 1 篇|奖励|1| +|8 月推荐前端文章 2 篇|奖励|2| |[监测与调试 Vue.js 的响应式系统:计算属性树(Computed Tree)](https://juejin.im/post/5c9ca62e5188251d80672b0d)|翻译|5| |[网速敏感的视频延迟加载方案](https://juejin.im/post/5c7b84356fb9a049ab0e5630)|翻译|3| |推荐英文文章一篇|奖励|1| @@ -8121,10 +8212,14 @@ |[💅 styled-components 背后的魔力](https://juejin.im/post/5c6d3a32e51d451804732248)|翻译|3| |推荐英文文章一篇|奖励|1| -## 译者:[shixi-li](https://github.com/shixi-li) 历史贡献积分:103 当前积分:103 二零二零:36.5 +## 译者:[shixi-li](https://github.com/shixi-li) 历史贡献积分:107.5 当前积分:30.5 |文章|类型|积分| |------|-------|-------| +|2020 年 5 月 兑换 谷歌纸板音箱 1 个 + 谷歌手提包 1 个 + 鲁班锁 1 个|减去积分|77| +|[Python List 使用注意事项](https://juejin.cn/post/6886633614717485070)|校对|2| +|[如何创建一个可复用的网页爬虫](https://juejin.im/post/6860354555759869966)|校对|1.5| +|[Syslog:系统管理员完整指南](https://juejin.im/post/6858168312388386824)|校对|1| |[理解 zip 和 gzip 压缩格式背后的压缩算法](https://juejin.im/post/5ecb7f9651882542f4488845)|校对|3| |[如何在自己的计算机上模拟 UDP Flood DoS 攻击](https://juejin.im/post/5eb8fb09e51d4540bb6172e1)|校对|2| |[记一次 —— 构建 API 网关服务的经历](https://juejin.im/post/5ef078666fb9a0589364a46b)|校对|5| @@ -8214,7 +8309,7 @@ |[为什么你的应用需要对各种尺寸屏幕做适配优化?](https://juejin.im/post/5c662023518825767633ab86)|翻译|3| |[我与 Flutter 的一年](https://juejin.im/post/5c5aeb8a6fb9a04a027acddf)|校对|3| -## 译者:[TUARAN](https://github.com/TUARAN) 历史贡献积分:36.5 当前积分:36.5 二零二零:6.5 +## 译者:[TUARAN](https://github.com/TUARAN) 历史贡献积分:36.5 当前积分:36.5 |文章|类型|积分| |------|-------|-------| @@ -8301,10 +8396,13 @@ |------|-------|-------| |[谷歌迈出了消除 URL 的第一步](https://juejin.im/post/5c643cb7e51d450dfc6eec1e)|校对|1| -## 译者:[iceytea](https://github.com/iceytea) 历史贡献积分:44.5 当前积分:44.5 +## 译者:[iceytea](https://github.com/iceytea) 历史贡献积分:46.5 当前积分:28.5 |文章|类型|积分| |------|-------|-------| +|2019 年 4 月 兑换 掘金纪念水杯 1 个、掘金 T 恤白色 1 件、虚拟比特币 1 个|减去积分|18| +|[8 个有用的 SCSS 最佳实践](https://juejin.im/post/6862499761351163911)|校对|0.5| +|[如何创建一个可复用的网页爬虫](https://juejin.im/post/6860354555759869966)|校对|1.5| |[设计的变革 —— 从用户体验到个人体验](https://juejin.im/post/5e00d1b4f265da33b636145a)|校对|1.5| |[4 个 CSS 调色滤镜](https://juejin.im/post/5d039c36f265da1b60290096)|翻译|3| |[Go 语言工具概述](https://juejin.im/post/5ce4dc17518825240245be5b)|翻译|10.5| @@ -8355,7 +8453,7 @@ |------|-------|-------| |推荐英文文章一系列|奖励|2| -## 译者:[Bruce-pac](https://github.com/Bruce-pac) 历史贡献积分:10 当前积分:10 二零二零:1 +## 译者:[Bruce-pac](https://github.com/Bruce-pac) 历史贡献积分:10 当前积分:10 |文章|类型|积分| |------|-------|-------| @@ -8372,10 +8470,12 @@ |[如何在远程服务器上运行 Jupyter Notebooks](https://juejin.im/post/5cb5e0a9f265da036c577f24)|翻译|4| |[数据科学领域十大必知机器学习算法](https://juejin.im/post/5c73bbfff265da2da771d42a)|校对|2| -## 译者:[xionglong58](https://github.com/xionglong58) 历史贡献积分:144 当前积分:64 二零二零:40.5 +## 译者:[xionglong58](https://github.com/xionglong58) 历史贡献积分:149 当前积分:0 |文章|类型|积分| |------|-------|-------| +|2020 年 9 月 兑换 树莓派套餐 1 份、小黄鸭 3 只|减去积分|69| +|[使用 Node.js 控制树莓派 4 的 GPIO](https://juejin.im/post/6868946182325043207)|校对|5| |[深入浅出 array.fill() 函数](https://juejin.im/post/5ec783a251882543385d4693)|校对|3| |[如何在 JavaScript 中使用新特性“顶层 await”](https://juejin.im/post/5ec67516e51d45787161978e)|校对|1.5| |[你不需要 passport.js — node.js 认证指南](https://juejin.im/post/5e060589f265da33b0718f55)|校对|2| @@ -8473,7 +8573,7 @@ |[避免那些可恶的 "cannot read property of undefined" 错误](https://juejin.im/post/5c810170e51d450a453fb48e)|校对|1| |[模块化系统中的 event.stopPropagation ()](https://juejin.im/post/5c74a8bef265da2d881b331f)|校对|1.5| -## 译者:[nettee](https://github.com/nettee) 历史贡献积分:45.5 当前积分:45.5 二零二零:5 +## 译者:[nettee](https://github.com/nettee) 历史贡献积分:45.5 当前积分:45.5 |文章|类型|积分| |------|-------|-------| @@ -8561,10 +8661,11 @@ |[Node.js 基础知识: 没有依赖关系的 Web 服务器](https://juejin.im/post/5c88a6855188257b0b126564)|校对|1| |[Golang 数据结构:树](https://juejin.im/post/5c8e023351882545eb718c9d)|校对|3| -## 译者:[portandbridge](https://github.com/portandbridge) 历史贡献积分:84.5 当前积分:84.5 +## 译者:[portandbridge](https://github.com/portandbridge) 历史贡献积分:85.5 当前积分:85.5 |文章|类型|积分| |------|-------|-------| +|[Syslog:系统管理员完整指南](https://juejin.im/post/6858168312388386824)|校对|1| |[设置 git 别名](https://juejin.im/post/5dafc502f265da5b783f1ae1)|校对|1| |[如何杀死一个进程和它的所有子进程](https://juejin.im/post/5d68a1a951882525830c7093)|校对|1| |[我用 Javascript 实现 tic tac toe 游戏](https://juejin.im/post/5d627dc36fb9a06af05cbfdc)|校对|2.5| @@ -8716,7 +8817,7 @@ |[用 Rust 打造你的第一个命令行工具](https://juejin.im/post/5cb33b94e51d456e63760453)|校对|1.5| |[如何在远程服务器上运行 Jupyter Notebooks](https://juejin.im/post/5cb5e0a9f265da036c577f24)|校对|1.5| -## 译者:[ccJia](https://github.com/ccJia) 历史贡献积分:39 当前积分:39 二零二零:2 +## 译者:[ccJia](https://github.com/ccJia) 历史贡献积分:39 当前积分:39 |文章|类型|积分| |------|-------|-------| @@ -8773,10 +8874,11 @@ |------|-------|-------| |[创意运用 Console API!](https://juejin.im/post/5cc1517e5188252e7a0247dd)|校对|2| -## 译者:[Charlo-O](https://github.com/Charlo-O) 历史贡献积分:58.5 当前积分:58.5 二零二零:12 +## 译者:[Charlo-O](https://github.com/Charlo-O) 历史贡献积分:65.5 当前积分:65.5 二零二一:7 |文章|类型|积分| |------|-------|-------| +|[构建设计系统和组件库](https://juejin.cn/post/6924152501805678606)|翻译|7| |[寻找 2020 年最有意义的十大网页设计流行趋势](https://juejin.im/post/5ed74ee0e51d45788a6d686e)|翻译|4| |[简单的谬误](https://juejin.im/post/5eca7e8ee51d45784a354d1c)|翻译|4| |[眼动跟踪和移动世界的最佳用户体验实践](https://zhuanlan.zhihu.com/p/120424545)|翻译|4| @@ -8837,7 +8939,7 @@ |[Keras 速查表:使用 Python 构建神经网络](https://juejin.im/post/5cd40d24f265da038412a8be)|翻译|3| |[在深度学习训练过程中如何设置数据增强?](https://juejin.im/post/5cc87ec8f265da03b446202b)|校对|2| -## 译者:[fireairforce](https://github.com/fireairforce) 历史贡献积分:110 当前积分:79 二零二零:45 +## 译者:[fireairforce](https://github.com/fireairforce) 历史贡献积分:110 当前积分:79 |文章|类型|积分| |------|-------|-------| @@ -8872,10 +8974,31 @@ |[自动补全规则](https://juejin.im/post/5cd556ef6fb9a03218556cb7)|翻译|3| |[使用 PyTorch 在 MNIST 数据集上进行逻辑回归](https://juejin.im/post/5cc66d946fb9a032286173a7)|校对|1| -## 译者:[Chorer](https://github.com/Chorer) 历史贡献积分:50.5 当前积分:40.5 二零二零:21 - -|文章|类型|积分| -|------|-------|-------| +## 译者:[Chorer](https://github.com/Chorer) 历史贡献积分:94 当前积分:74 二零二一:14 + +|文章|类型|积分| +|------|-------|-------| +|[自适应 CSS 栅格:自由布局的最终版本](https://juejin.cn/post/6935090806210428959)|校对|1| +|[CSS3 会替代 SCSS 吗?](https://juejin.cn/post/6934326962450071559)|校对|2| +|[JavaScript 中哪一种循环更快呢?](https://juejin.cn/post/6930973929452339213)|校对|1| +|[基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)|校对|3| +|[如何在浏览器上使用 NoSQL 数据库 IndexedDB](https://juejin.cn/post/6930883284456964109)|校对|2| +|[构建设计系统和组件库](https://juejin.cn/post/6924152501805678606)|校对|5| +|2020 年 8 月 兑换 掘金 T 恤 1 件|减去积分|10| +|[JavaScript 的面向切面编程](https://juejin.cn/post/6903484050095210509)|校对|2| +|[我的网站加载时间不到 1 秒,这是我如何做到的!](https://juejin.cn/post/6870329885034807310)|校对|1.5| +|[ES2017 最佳特性  —  数组中的异步函数以及共享缓冲区](https://juejin.im/post/6878849121269055501)|校对|1.5| +|[使用 JSON.stringify 处理 JavaScript 对象](https://juejin.im/post/6871807169562902541)|校对|1| +|[JavaScript 函数中一些你不知道的秘密](https://juejin.im/post/6871101056642711559)|校对|3| +|[加速 vue.js 应用的六种绝技](https://juejin.im/post/6870808442911588365)|校对|3| +|[分享我喜欢的十五条 JavaScript 编程技巧](https://github.com/xitu/gold-miner/blob/master/article/2020/my-favorite-javascript-tips-and-tricks.md)|校对|2| +|[JavaScript 引擎概述](https://juejin.im/post/6869976412745367566)|校对|2| +|[颜色为何成为数据可视化的关键,怎样使用它?](https://juejin.im/post/6872238362233831432)|校对|2.5| +|[世界比以往任何时候都更需要 Web 可访问性](https://juejin.im/post/6872684910058930189)|校对|2| +|[JavaScript 生成器:何时用 yield,何时用 yield* ?](https://juejin.im/post/6867036974441005063)|校对|1| +|[Javascript 应用中引入 CSS 的几种方式](https://juejin.im/post/6867054761741549576)|校对|3| +|[使用 Chrome 的 Shape Detection API 检测人脸,文本甚至条形码](https://juejin.im/post/6864391729693491207)|校对|3| +|[如何利用 Polyfill 和转译在所有浏览器中使用最新 JavaScript 特性](https://juejin.im/post/6868513605055643662)|校对|2| |[ECMAScript 2020 新特性](https://juejin.im/post/5ec34ed96fb9a0437b76f638)|校对|2| |[我并不讨厌箭头函数](https://juejin.im/post/5e8d58caf265da48062c7a64)|校对|3| |[关于 icon 设计的 7 大准则](https://juejin.im/post/5e5dbd3e6fb9a07cd323dd2b)|校对|3| @@ -8898,10 +9021,11 @@ |[ES6:理解参数默认值的实现细节](https://juejin.im/post/5cd0eab95188251b984d8abe)|翻译|3.5| |推荐英文文章一篇|奖励|1| -## 译者:[cyz980908](https://github.com/cyz980908) 历史贡献积分:197.5 当前积分:197.5 二零二零:129.5 +## 译者:[cyz980908](https://github.com/cyz980908) 历史贡献积分:197.5 当前积分:116.5 |文章|类型|积分| |------|-------|-------| +|2020 年 7 月 兑换 小米台灯 2 个 + 小黄鸭 3 个 + 纪念币 1 个|减去积分|81| |[用户体验案例学习:Mood Talk ——  一个心理健康应用](https://juejin.im/post/5ebbb38ae51d454dca711099)|校对|3| |[用 JavaScript 中的蹦床函数实现安全递归](https://juejin.im/post/5ec3eec2f265da76d318644e)|校对|1| |六月推荐前端文章 1 篇|奖励|1| @@ -8945,10 +9069,11 @@ |[在数据可视化中,我们曾经“画”下的那些错误](https://juejin.im/post/5cd39e1de51d453a3a0acb7b)|校对|1.5| |[使用 VS Code 调试 Node.js 的超简单方法](https://juejin.im/post/5cce9b976fb9a0322415aba4)|校对|1.5| -## 译者:[Baddyo](https://github.com/Baddyo) 历史贡献积分:235.5 当前积分:235.5 二零二零:61.5 +## 译者:[Baddyo](https://github.com/Baddyo) 历史贡献积分:235.5 当前积分:35.5 |文章|类型|积分| |------|-------|-------| +|2020 年 5 月 兑换 Kindle 1 个|减去积分|200| |[看我如何把网站性能提升 422%](https://juejin.im/post/5ec793346fb9a0480659d6ef)|翻译|4| |[小品 JavaScript Proxy](https://juejin.im/post/5eb8f11de51d454dca710c1f)|翻译|3| |[在图像中隐藏数据:用 Python 来实现图像隐写术](https://juejin.im/post/5f0bf4fce51d45347500b23d)|校对|2.5| @@ -9033,10 +9158,13 @@ |[声音设计与无声设计](https://juejin.im/post/5ce354bee51d4510727c7fd1)|翻译|2.5| |[Swift 里的强制 @inline 注解](https://juejin.im/post/5cd67d64518825686244635a)|校对|1.5| -## 译者:[suhanyujie](https://github.com/suhanyujie) 历史贡献积分:60 当前积分:60 +## 译者:[suhanyujie](https://github.com/suhanyujie) 历史贡献积分:65 当前积分:65 |文章|类型|积分| |------|-------|-------| +|[Golang 切片综合指南](https://juejin.cn/post/6883398632071462919)|校对|3| +|[TypeScript 4.0 终于发布了我一直在等待的东西](https://juejin.im/post/6864473591770152968)|校对|1| +|9 月推荐后端文章 1 篇|奖励|1| |[PHP 7.4 有什么新功能?你必须掌握的 10 大特性](https://juejin.im/post/5dfa04316fb9a0160770a501)|校对|2| |[通过 Rust 学习解析器组合器 — 第四部分](https://juejin.im/post/5d629f75e51d456210163bc0)|校对|2| |[思考实践:用 Go 实现 Flutter](https://juejin.im/post/5d215b8df265da1b7b31ac8f)|翻译|11| @@ -9065,7 +9193,7 @@ |[用 React 的钩子函数和调试工具提升应用性能](https://juejin.im/post/5ce974d76fb9a07f0420250e)|校对|1| |[理解 WebView](https://juejin.im/post/5ce76ee4f265da1b8d15f700)|校对|2| -## 译者:[jilanlan](https://github.com/jilanlan) 历史贡献积分:6 当前积分:6 二零二零:1 +## 译者:[jilanlan](https://github.com/jilanlan) 历史贡献积分:6 当前积分:6 |文章|类型|积分| |------|-------|-------| @@ -9085,10 +9213,16 @@ |[Android中的简易协程:viewModelScope](https://juejin.im/post/5cf35ec76fb9a07ed657bbcd)|翻译|3| |[C++ 和 Android 本地 Activity 初探](https://juejin.im/post/5ce62d4851882532e9631b63)|翻译|2| -## 译者:[ZavierTang](https://github.com/ZavierTang) 历史贡献积分:34 当前积分:34 二零二零:8 +## 译者:[ZavierTang](https://github.com/ZavierTang) 历史贡献积分:53.5 当前积分:33.5 二零二一:2 |文章|类型|积分| |------|-------|-------| +|[Web 应用缓存的基础知识](https://juejin.cn/post/6913898149740281870)|校对|2| +|[继承 vs 组合:哪一个更适合你的 JavaScript 项目?](https://juejin.cn/post/6906288659742654478)|校对|2| +|[页面生命周期 API:每一个前端开发者都应该知道的浏览器 API](https://juejin.cn/post/6906779518040539144)|校对|2| +|[TypeScript 的 5 个建议](https://juejin.cn/post/6906307187816349703)|翻译|5.5| +|2019 年 12 月 兑换 掘金笔记本 1 本、掘金纪念水杯 2 个|减去积分|20| +|[最常用的 4 种 JavaScript 设计模式](https://github.com/xitu/gold-miner/blob/master/article/2020/4-useful-javascript-design-patterns-you-should-know.md)|翻译|8| |[给 NodeJS 的 Logs 点颜色看看!](https://juejin.im/post/5e6f01b151882549422ef315)|校对|1| |[停止在任何地方使用 ===](https://juejin.im/post/5e5fb5e951882549522ac8a2)|翻译|7| |[如何将 SVG 图标用做 React 组件?](https://juejin.im/post/5df22bf7f265da33ea009225)|校对|1| @@ -9109,10 +9243,11 @@ |[WebSockets 与长轮询的较量](https://juejin.im/post/5d0b1381e51d455a694f9544)|校对|1.5| |[如何在 Google Play 应用商店中发布 PWA](https://juejin.im/post/5cefe63a6fb9a07ef3764dbe)|校对|2| -## 译者:[lgh757079506](https://github.com/lgh757079506) 历史贡献积分:20 当前积分:20 +## 译者:[lgh757079506](https://github.com/lgh757079506) 历史贡献积分:20 当前积分:-16 |文章|类型|积分| |------|-------|-------| +|2019 年 10 月 兑换 Github 会员 + 1 个纪念水杯 + 1 个纪念币 + 1 个笔记本|减去积分|36| |[小提示:伪元素是子元素,吧。](https://juejin.im/post/5d6271895188253a5635002e)|校对|1| |[使用 Typescript 使无效状态不可恢复](https://juejin.im/post/5d628841518825332d3fec3d)|校对|2| |[我用 Javascript 实现 tic tac toe 游戏](https://juejin.im/post/5d627dc36fb9a06af05cbfdc)|翻译|4.5| @@ -9155,10 +9290,11 @@ |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|40| |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|13| -## 译者:[smilemuffie](https://github.com/smilemuffie) 历史贡献积分:10 当前积分:10 +## 译者:[smilemuffie](https://github.com/smilemuffie) 历史贡献积分:10 当前积分:4 |文章|类型|积分| |------|-------|-------| +|2019 年 7 月 兑换 8p 白色手机壳 1 个|减去积分|6| |[Web 流式文字排版的现状](https://juejin.im/post/5d267d9de51d45773d4686ab)|校对|2| |[TypeScript 3.0: unknown 类型](https://juejin.im/post/5d04ac745188250a8b1fd203)|校对|1| |[JavaScript 简明代码 — 最佳实践](https://juejin.im/post/5d07abcc6fb9a07eda031858)|校对|1| @@ -9168,7 +9304,7 @@ |[Flutter 布局备忘录](https://juejin.im/post/5cfe0d136fb9a07efc497d7d)|校对|1.5| |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|1.5| -## 译者:[lihaobhsfer](https://github.com/lihaobhsfer) 历史贡献积分:40.5 当前积分:40.5 二零二零:19 +## 译者:[lihaobhsfer](https://github.com/lihaobhsfer) 历史贡献积分:40.5 当前积分:40.5 |文章|类型|积分| |------|-------|-------| @@ -9191,10 +9327,17 @@ |[改善 Android Studio 的构建速度](https://juejin.im/post/5d1388b1f265da1b6d403560)|校对|1.5| |[揭秘变量提升](https://juejin.im/post/5d026b71518825710d2b1f63)|校对|1.5| -## 译者:[JalanJiang](https://github.com/JalanJiang) 历史贡献积分:95 当前积分:95 二零二零:13 +## 译者:[JalanJiang](https://github.com/JalanJiang) 历史贡献积分:114 当前积分:19 二零二一:9 |文章|类型|积分| |------|-------|-------| +|[上手 Python 数据类前需要知道的 6 件事](https://juejin.cn/post/6926815217859559438)|翻译|6| +|[Python 定义函数的 5 种参数](https://juejin.cn/post/6927094483200770062)|校对|3| +|2019 年 11 月 兑换 google 套头衫 M 码*1 + 纪念币*1|减去积分|22| +|2020 年 3 月 兑换 树莓派三 1 个|减去积分|60| +|2020 年 9 月 兑换 鼠标垫 1 个|减去积分|13| +|[给初学者的示例:什么是 WSGI?](https://juejin.cn/post/6896716356054417416)|翻译|3| +|[Golang 切片综合指南](https://juejin.cn/post/6883398632071462919)|翻译|7| |[如何使用 Python 生成随机文本验证码](https://juejin.im/post/5f1567a3f265da22db2c351d)|校对|2| |[Python 内存管理之垃圾回收](https://juejin.im/post/5ecdcea6f265da77160035c7)|校对|1| |[在图像中隐藏数据:用 Python 来实现图像隐写术](https://juejin.im/post/5f0bf4fce51d45347500b23d)|校对|2.5| @@ -9248,10 +9391,11 @@ |[微前端:未来前端开发的新趋势 — 第一部分](https://juejin.im/post/5d0e367b6fb9a07ebf4b781a)|校对|1| |[JavaScript 线性代数:使用 ThreeJS 制作线性变换动画](https://juejin.im/post/5d05dba86fb9a07ece67ce76)|校对|1| -## 译者:[TiaossuP](https://github.com/TiaossuP) 历史贡献积分:45 当前积分:45 二零二零:5 +## 译者:[TiaossuP](https://github.com/TiaossuP) 历史贡献积分:47 当前积分:47 |文章|类型|积分| |------|-------|-------| +|[四种跨浏览器选项卡实时通信方法](https://juejin.cn/post/6896273264214179848)|校对|2| |[我并不讨厌箭头函数](https://juejin.im/post/5e8d58caf265da48062c7a64)|翻译|5| |[如何将 SVG 图标用做 React 组件?](https://juejin.im/post/5df22bf7f265da33ea009225)|翻译|3| |[TypeScript 3.7 Beta 版发布](https://juejin.im/post/5db2537d6fb9a0208b11f94f)|校对|3.5| @@ -9272,7 +9416,7 @@ |[Web 流式文字排版的现状](https://juejin.im/post/5d267d9de51d45773d4686ab)|翻译|7| |[微前端:未来前端开发的新趋势 — 第一部分](https://juejin.im/post/5d0e367b6fb9a07ebf4b781a)|翻译|4| -## 译者:[MarchYuanx](https://github.com/MarchYuanx) 历史贡献积分:49.5 当前积分:49.5 二零二零:14 +## 译者:[MarchYuanx](https://github.com/MarchYuanx) 历史贡献积分:49.5 当前积分:49.5 |文章|类型|积分| |------|-------|-------| @@ -9291,7 +9435,7 @@ |[设计师如何成长为 Leader?](https://juejin.im/post/5d172fca6fb9a07eda032c6f)|校对|2| |[在 npm 上启用现在 JavaScript](https://juejin.im/post/5d15d64be51d4510a5033603)|校对|1.5| -## 译者:[mymmon](https://github.com/mymmon) 历史贡献积分:18 当前积分:18 二零二零:3 +## 译者:[mymmon](https://github.com/mymmon) 历史贡献积分:18 当前积分:18 |文章|类型|积分| |------|-------|-------| @@ -9344,10 +9488,11 @@ |------|-------|-------| |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|20| -## 译者:[scarqin](https://github.com/scarqin) 历史贡献积分:8 当前积分:8 二零二零:2.5 +## 译者:[scarqin](https://github.com/scarqin) 历史贡献积分:13 当前积分:13 |文章|类型|积分| |------|-------|-------| +|[从头开始到最初的 10 个客户:我是如何设计并推出一个 SaaS 产品](https://juejin.im/post/6860850397293232141)|校对|5| |[我并不讨厌箭头函数](https://juejin.im/post/5e8d58caf265da48062c7a64)|校对|2.5| |[如何计划你的一天 —— 这里有一份攻略请查收](https://juejin.im/post/5db16664f265da4d4c201997)|校对|2.5| |[The JavaScript Tutorial 教程](https://github.com/javascript-tutorial/zh.javascript.info)|翻译校对|3| @@ -9413,7 +9558,7 @@ |[作为初级开发人员,我没有学过的 7 个绝对真理](https://juejin.im/post/5d3d25dce51d457756536881)|校对|2| |[喷泉码和动态二维码](https://juejin.im/post/5d391ae1f265da1bb0040352)|校对|1.5| -## 译者:[Pingren](https://github.com/Pingren) 历史贡献积分:45 当前积分:45 二零二零:5 +## 译者:[Pingren](https://github.com/Pingren) 历史贡献积分:45 当前积分:45 |文章|类型|积分| |------|-------|-------| @@ -9427,21 +9572,21 @@ |[Web 端的 SwiftUI:SwiftWebUI](https://juejin.im/post/5d35e0ac5188257dc103e364)|校对|2.5| |[仅使用 HTML 和 CSS 创建多级嵌套弹出式导航菜单](https://juejin.im/post/5d3c2852f265da1bac405fae)|校对|4| -## 译者:[redagavin](https://github.com/redagavin) 历史贡献积分:3.5 当前积分:3.5 二零二零:2 +## 译者:[redagavin](https://github.com/redagavin) 历史贡献积分:3.5 当前积分:3.5 |文章|类型|积分| |------|-------|-------| |[5 个简单步骤为您的网站创建 Sitemap](https://juejin.im/post/5e22fc43f265da3e254c7555)|校对|2| |[敏捷也许是个问题](https://juejin.im/post/5d2dfb4ae51d45775f516b1e)|校对|1.5| -## 译者:[LanceZhu](https://github.com/LanceZhu) 历史贡献积分:3 当前积分:3 二零二零:1 +## 译者:[LanceZhu](https://github.com/LanceZhu) 历史贡献积分:3 当前积分:3 |文章|类型|积分| |------|-------|-------| |2020 年 2 月推荐文章 1 篇|奖励|1| |[npm 的经济风云 —— 下半部分](https://juejin.im/post/5d2d9e7af265da1b8b2b91ca)|校对|2| -## 译者:[imononoke](https://github.com/imononoke) 历史贡献积分:7 当前积分:7 二零二零:1 +## 译者:[imononoke](https://github.com/imononoke) 历史贡献积分:7 当前积分:7 |文章|类型|积分| |------|-------|-------| @@ -9461,10 +9606,13 @@ |------|-------|-------| |推荐前端文章[A Future Without Webpack](https://github.com/xitu/gold-miner/issues/6246)|奖励|1| -## 译者:[todaycoder001](https://github.com/todaycoder001) 历史贡献积分:109.5 当前积分:109.5 二零二零:67.5 +## 译者:[todaycoder001](https://github.com/todaycoder001) 历史贡献积分:112.5 当前积分:69.5 |文章|类型|积分| |------|-------|-------| +|2020 年 1 月 兑换 小米台灯 1 个、掘金笔记本 1 本|减去积分|43| +|[使用合成数据改善机器学习中的极度不平衡数据集](https://juejin.im/post/6872609287802388488)|校对|2| +|[Syslog:系统管理员完整指南](https://juejin.im/post/6858168312388386824)|校对|1| |[贪心算法,你入门了吗?](https://juejin.im/post/5ebc0f626fb9a043383d7c2b)|校对|2| |[如何编写整洁代码?从 Robert C. Martin 的“代码整洁之道”中吸取的教训](https://juejin.im/post/5eb78370f265da7be959ffc2)|翻译|6| |[如何在自己的计算机上模拟 UDP Flood DoS 攻击](https://juejin.im/post/5eb8fb09e51d4540bb6172e1)|校对|2| @@ -9525,7 +9673,7 @@ |------|-------|-------| |[当每个产品设计都是一种意见](https://juejin.im/post/5d5a77676fb9a06b1417e4b3)|校对|3| -## 译者:[TokenJan](https://github.com/TokenJan) 历史贡献积分:43.5 当前积分:43.5 二零二零:9 +## 译者:[TokenJan](https://github.com/TokenJan) 历史贡献积分:43.5 当前积分:43.5 |文章|类型|积分| |------|-------|-------| @@ -9542,14 +9690,15 @@ |[HTTP Security Headers 完整指南](https://juejin.im/post/5d648e766fb9a06b122f4ab4)|校对|1.5| |[我用 Javascript 实现 tic tac toe 游戏](https://juejin.im/post/5d627dc36fb9a06af05cbfdc)|校对|2| -## 译者:[githubmnume](https://github.com/githubmnume) 历史贡献积分:5 当前积分:5 +## 译者:[githubmnume](https://github.com/githubmnume) 历史贡献积分:13 当前积分:13 |文章|类型|积分| |------|-------|-------| +|[Syslog:系统管理员完整指南](https://juejin.im/post/6858168312388386824)|翻译|8| |[如何用 JavaScript 编写扫雷游戏](https://juejin.im/post/5d6276cd6fb9a06ade111bb4)|校对|3| |[重建桌面端的 Slack 而不是重写](https://juejin.im/post/5d624db86fb9a06b2650a262)|校对|2| -## 译者:[hanxiaosss](https://github.com/hanxiaosss) 历史贡献积分:17.5 当前积分:17.5 二零二零:12 +## 译者:[hanxiaosss](https://github.com/hanxiaosss) 历史贡献积分:17.5 当前积分:17.5 |文章|类型|积分| |------|-------|-------| @@ -9587,7 +9736,7 @@ |[TypeScript 3.7 Beta 版发布](https://juejin.im/post/5db2537d6fb9a0208b11f94f)|校对|3| |[如何设计一款讨人喜欢的暗色主题](https://juejin.im/post/5dad4ef1f265da5bb86ad294)|校对|2| -## 译者:[HytonightYX](https://github.com/HytonightYX) 历史贡献积分:9.5 当前积分:9.5 二零二零:6 +## 译者:[HytonightYX](https://github.com/HytonightYX) 历史贡献积分:9.5 当前积分:9.5 |文章|类型|积分| |------|-------|-------| @@ -9602,7 +9751,7 @@ |------|-------|-------| |[现代脚本加载](https://juejin.im/post/5dafdcd45188256b030ad8cf)|翻译|5.5| -## 译者:[quzhen12](https://github.com/quzhen12) 历史贡献积分:7.5 当前积分:7.5 二零二零:3 +## 译者:[quzhen12](https://github.com/quzhen12) 历史贡献积分:7.5 当前积分:7.5 |文章|类型|积分| |------|-------|-------| @@ -9618,10 +9767,15 @@ |[设置 git 别名](https://juejin.im/post/5dafc502f265da5b783f1ae1)|校对|1.5| |[使用 `import()` 执行 JavaScript 代码](https://juejin.im/post/5dafc573e51d4524bb096393)|校对|1| -## 译者:[Alfxjx](https://github.com/Alfxjx) 历史贡献积分:11 当前积分:11 二零二零:3 +## 译者:[Alfxjx](https://github.com/Alfxjx) 历史贡献积分:22 当前积分:22 二零二一:4 |文章|类型|积分| |------|-------|-------| +|[对象展开运算符在 JavaScript 中的 5 大应用](https://juejin.cn/post/6895525536039174151)|翻译|2| +|[使用 clamp() 进行响应式设计](https://juejin.cn/post/6890830054134611976)|翻译|2| +|[TypeScript:一个好泛型的价值](https://juejin.im/post/6878868818836488205)|校对|3| +|[如何处理 JavaScript 比较中的临界情况](https://juejin.im/post/6872682987859738632)|校对|2| +|[React vs. Svelte:虚拟与真实 DOM 间的战争](https://juejin.im/post/6870858079513247758)|校对|2| |[在 Vue 中编写 SVG 图标组件](https://juejin.im/post/5e4fc62de51d4527110a85dd)|校对|2| |[使用 Web Workers 优化事件监听器](https://juejin.im/post/5e241bb9f265da3e46090215)|校对|1| |[设计离线优先的网络应用](https://juejin.im/post/5dd608eef265da47f12cb018)|校对|2.5| @@ -9642,7 +9796,7 @@ |------|-------|-------| |[关于现代应用样式的探讨](https://juejin.im/post/5db93b67f265da4d417648a1)|校对|2| -## 译者:[vitoxli](https://github.com/vitoxli) 历史贡献积分:31.5 当前积分:31.5 二零二零:18 +## 译者:[vitoxli](https://github.com/vitoxli) 历史贡献积分:31.5 当前积分:31.5 |文章|类型|积分| |------|-------|-------| @@ -9663,16 +9817,24 @@ |------|-------|-------| |[让字母“i”的点动起来的秘密](https://juejin.im/post/5dd7fe84e51d4523564243d5)|校对|1| -## 译者:[jiapengwen](https://github.com/jiapengwen) 历史贡献积分:1.5 当前积分:1.5 +## 译者:[jiapengwen](https://github.com/jiapengwen) 历史贡献积分:4.5 当前积分:4.5 二零二一:3 |文章|类型|积分| |------|-------|-------| +|[上手 Python 数据类前需要知道的 6 件事](https://juejin.cn/post/6926815217859559438)|校对|3| |[为什么自己动手写代码能让你成为更好的开发者](https://juejin.im/post/5de88ed16fb9a016470c151a)|校对|1.5| -## 译者:[PingHGao](https://github.com/PingHGao) 历史贡献积分:63 当前积分:63 二零二零:58 +## 译者:[PingHGao](https://github.com/PingHGao) 历史贡献积分:91.5 当前积分:26.5 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 掘金鼠标垫 1 个 + 小米台灯 1 个|减去积分|48| +|2020 年 3 月 兑换 鲁班锁 1 个|减去积分|17| +|[7 种有用的时间复杂度](https://juejin.im/post/6873379647125553159)|翻译|6.5| +|[让神经网络变得更小巧以方便部署](https://juejin.im/post/6873068232505458701)|翻译|11| +|[使用合成数据改善机器学习中的极度不平衡数据集](https://juejin.im/post/6872609287802388488)|翻译|5| +|[知识的极限](https://juejin.im/post/6874475968325484552)|校对|3| +|[异步编程和多线程,我该选择哪个方案?](https://juejin.im/post/6844904168159707150)|校对|3| |[Python 内存管理之垃圾回收](https://juejin.im/post/5ecdcea6f265da77160035c7)|校对|1| |[贪心算法,你入门了吗?](https://juejin.im/post/5ebc0f626fb9a043383d7c2b)|校对|2| |[如何编写整洁代码?从 Robert C. Martin 的“代码整洁之道”中吸取的教训](https://juejin.im/post/5eb78370f265da7be959ffc2)|校对|3| @@ -9695,7 +9857,7 @@ |[为何 Svelte 杀不死 React](https://juejin.im/post/5e12aa81e51d4541162c9a3a)|校对|3.5| |[理解递归、尾调用优化和蹦床函数优化](https://juejin.im/post/5e003a67e51d45583f44d396)|校对|5| -## 译者:[zh1an](https://github.com/zh1an) 历史贡献积分:11 当前积分:11 二零二零:8 +## 译者:[zh1an](https://github.com/zh1an) 历史贡献积分:11 当前积分:11 |文章|类型|积分| |------|-------|-------| @@ -9717,19 +9879,19 @@ |------|-------|-------| |2019 年 12 月推荐文章 1 篇|奖励|1| -## 译者:[Imsiaocong](https://github.com/Imsiaocong) 历史贡献积分:2 当前积分:2 二零二零:2 +## 译者:[Imsiaocong](https://github.com/Imsiaocong) 历史贡献积分:2 当前积分:2 |文章|类型|积分| |------|-------|-------| |[论资历的级别](https://juejin.im/post/5e1549736fb9a0483c632bf8)|校对|2| -## 译者:[impactCn](https://github.com/impactCn) 历史贡献积分:4 当前积分:4 二零二零:4 +## 译者:[impactCn](https://github.com/impactCn) 历史贡献积分:4 当前积分:4 |文章|类型|积分| |------|-------|-------| |[现在就该学习的 7 门现代编程语言](https://juejin.im/post/5e1e00fee51d4577794c04f8)|校对|4| -## 译者:[febrainqu](https://github.com/febrainqu) 历史贡献积分:47 当前积分:47 二零二零:47 +## 译者:[febrainqu](https://github.com/febrainqu) 历史贡献积分:47 当前积分:47 |文章|类型|积分| |------|-------|-------| @@ -9744,7 +9906,7 @@ |[使用 Web Workers 优化事件监听器](https://juejin.im/post/5e241bb9f265da3e46090215)|校对|1| |[再见,整洁的代码](https://juejin.im/post/5e2411e0f265da3e4244e683)|校对|1.5| -## 译者:[ahabhgk](https://github.com/ahabhgk) 历史贡献积分:6 当前积分:6 二零二零:6 +## 译者:[ahabhgk](https://github.com/ahabhgk) 历史贡献积分:6 当前积分:6 |文章|类型|积分| |------|-------|-------| @@ -9754,7 +9916,7 @@ |[在什么时候你需要使用 Web Workers?](https://juejin.im/post/5e290aaee51d451c8836284f)|校对|1.5| |[再见,整洁的代码](https://juejin.im/post/5e2411e0f265da3e4244e683)|校对|1.5| -## 译者:[Starry316](https://github.com/Starry316) 历史贡献积分:10 当前积分:10 二零二零:10 +## 译者:[Starry316](https://github.com/Starry316) 历史贡献积分:10 当前积分:10 |文章|类型|积分| |------|-------|-------| @@ -9762,20 +9924,20 @@ |[如何选择合适的数据库](https://juejin.im/post/5e3c10e6518825494f7de8ff)|校对|2| |[如何写出优雅且有意义的 README.md](https://juejin.im/post/5e3a7363e51d452701795512)|校对|2| -## 译者:[Shuyun6](https://github.com/Shuyun6) 历史贡献积分:1 当前积分:1 二零二零:1 +## 译者:[Shuyun6](https://github.com/Shuyun6) 历史贡献积分:1 当前积分:1 |文章|类型|积分| |------|-------|-------| |[算法不是产品](https://juejin.im/post/5e398e806fb9a07cb52bb462)|校对|1| -## 译者:[RubyJy](https://github.com/RubyJy) 历史贡献积分:6 当前积分:6 二零二零:6 +## 译者:[RubyJy](https://github.com/RubyJy) 历史贡献积分:6 当前积分:6 |文章|类型|积分| |------|-------|-------| |[WebRTC 联手 Node.js:打造实时视频聊天应用](https://juejin.im/post/5e0ae59d5188253a5b3ccf74)|校对|4| |[如何选择合适的数据库](https://juejin.im/post/5e3c10e6518825494f7de8ff)|校对|2| -## 译者:[Amberlin1970](https://github.com/Amberlin1970) 历史贡献积分:14.5 当前积分:14.5 二零二零:14.5 +## 译者:[Amberlin1970](https://github.com/Amberlin1970) 历史贡献积分:14.5 当前积分:14.5 |文章|类型|积分| |------|-------|-------| @@ -9784,20 +9946,21 @@ |[图像修复:人类和 AI 的对决](https://juejin.im/post/5e43b2edf265da576543a0bb)|校对|3| |[使用 Python 进行边缘检测](https://juejin.im/post/5e3d4b53e51d4526c26fadd4)|校对|1.5| -## 译者:[Weirdochr](https://github.com/Weirdochr) 历史贡献积分:7 当前积分:7 二零二零:7 +## 译者:[Weirdochr](https://github.com/Weirdochr) 历史贡献积分:12 当前积分:12 |文章|类型|积分| |------|-------|-------| +|[使用 Node.js 控制树莓派 4 的 GPIO](https://juejin.im/post/6868946182325043207)|翻译|5| |[数学编程  ——  一个为推进数据科学发展而培养的关键习惯](https://zhuanlan.zhihu.com/p/100212596)|翻译|7| -## 译者:[Jiangzhiqi4551](https://github.com/Jiangzhiqi4551) 历史贡献积分:4.5 当前积分:4.5 二零二零:4.5 +## 译者:[Jiangzhiqi4551](https://github.com/Jiangzhiqi4551) 历史贡献积分:4.5 当前积分:4.5 |文章|类型|积分| |------|-------|-------| |[8 个值得了解的树形数据结构](https://juejin.im/post/5e7dfd0551882573b7535f23)|校对|2| |[一份数据科学 A/B 测试的简单指南](https://juejin.im/post/5e61b88cf265da57602c5b95)|校对|2.5| -## 译者:[GJXAIOU](https://github.com/GJXAIOU) 历史贡献积分:10 当前积分:10 二零二零:10 +## 译者:[GJXAIOU](https://github.com/GJXAIOU) 历史贡献积分:10 当前积分:10 |文章|类型|积分| |------|-------|-------| @@ -9807,10 +9970,13 @@ |[密码哈希的方法:PBKDF2,Scrypt,Bcrypt 和 ARGON2](https://juejin.im/post/5e70c152518825491949886e)|校对|1.5| |[2020 年要学习的 7 种编程语言和框架](https://juejin.im/post/5e663cec518825496e786051)|校对|3| -## 译者:[chaingangway](https://github.com/chaingangway) 历史贡献积分:73 当前积分:73 二零二零:73 +## 译者:[chaingangway](https://github.com/chaingangway) 历史贡献积分:87.5 当前积分:87.5 |文章|类型|积分| |------|-------|-------| +|[学习 SwiftUI 框架中 Text 和 Label 控件的用法(iOS 14)](https://juejin.im/post/6881526224934420488)|翻译|4| +|[异步编程和多线程,我该选择哪个方案?](https://juejin.im/post/6844904168159707150)|翻译|6| +|[在 SwiftUI 中构建服务端驱动的 UI 组件](https://juejin.im/post/6844904186862108679)|翻译|4.5| |[在 Swift 中使用 MVVM 架构实现无限滚动和图片加载](https://juejin.im/post/5ecb8115e51d4578540fcacd)|翻译|7| |[在 Swift 使用 User Defaults 的小技巧](https://juejin.im/post/5f0d09605188252e937bef4b)|翻译|4.5| |[Swift 5.3 的新功能,你了解吗?](https://juejin.im/post/5f158ae4e51d453460293edc)|翻译|5| @@ -9828,10 +9994,12 @@ |[掌握 JavaScript 面试:什么是纯函数?](https://juejin.im/post/5e7f3c3df265da7951664547)|校对|4| |4 月推荐 iOS 文章 1 篇|奖励|1| -## 译者:[IAMSHENSH](https://github.com/IAMSHENSH) 历史贡献积分:40.5 当前积分:40.5 二零二零:40.5 +## 译者:[IAMSHENSH](https://github.com/IAMSHENSH) 历史贡献积分:46.5 当前积分:11.5 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 小米台灯 1 个|减去积分|35| +|[前端开发 8 大性能分析工具](https://juejin.im/post/6860664312504320014)|翻译|6| |[5 大 JavaScript 字符串操作库](https://juejin.im/post/5eba6becf265da7bb8773420)|翻译|4.5| |[看我如何把网站性能提升 422%](https://juejin.im/post/5ec793346fb9a0480659d6ef)|校对|2| |[小品 JavaScript Proxy](https://juejin.im/post/5eb8f11de51d454dca710c1f)|校对|1.5| @@ -9847,10 +10015,12 @@ |[2020 年用各大前端框架构建的 RealWorld 应用对比](https://juejin.im/post/5e887c48f265da47f60ea6ce)|校对|2.5| |[掌握 JavaScript 面试:什么是纯函数?](https://juejin.im/post/5e7f3c3df265da7951664547)|校对|4| -## 译者:[QinRoc](https://github.com/QinRoc) 历史贡献积分:58 当前积分:58 二零二零:58 +## 译者:[QinRoc](https://github.com/QinRoc) 历史贡献积分:67 当前积分:67 |文章|类型|积分| |------|-------|-------| +|[知识的极限](https://juejin.im/post/6874475968325484552)|翻译|6| +|[异步编程和多线程,我该选择哪个方案?](https://juejin.im/post/6844904168159707150)|校对|3| |[用户体验案例学习:Mood Talk ——  一个心理健康应用](https://juejin.im/post/5ebbb38ae51d454dca711099)|校对|3| |[什么是无障碍?为什它对于用户体验很重要?](https://juejin.im/post/5ebf96a5f265da7b9754dd7d)|翻译|3| |[创建一个 Settings icon 的五种方法](https://juejin.im/post/5e9e845be51d454709221d1f)|校对|3| @@ -9873,30 +10043,50 @@ |[组合软件:书](https://juejin.im/post/5e88346cf265da47e159366a)|校对|2| |[掌握 JavaScript 面试:什么是函数式编程](https://juejin.im/post/5e9a7394e51d4546d439826b)|校对|5| -## 译者:[colorsakura](https://github.com/colorsakura) 历史贡献积分:3 当前积分:3 二零二零:3 +## 译者:[colorsakura](https://github.com/colorsakura) 历史贡献积分:3 当前积分:3 |文章|类型|积分| |------|-------|-------| |[Go 发布新版 Protobuf API](https://juejin.im/post/5e83e1176fb9a03c80278e6d)|校对|3| -## 译者:[samyu2000](https://github.com/samyu2000) 历史贡献积分:12.5 当前积分:12.5 二零二零:12.5 - -|文章|类型|积分| -|------|-------|-------| +## 译者:[samyu2000](https://github.com/samyu2000) 历史贡献积分:89.5 当前积分:73.5 二零二一:42.5 + +|文章|类型|积分| +|------|-------|-------| +|[数据科学中的 9 种距离度量](https://juejin.cn/post/6935265008045686815)|校对|4| +|2021 年 2 月 兑换 掘金笔记本 2 个|减去积分|16| +|[如何基于已有的 REST API 实现 GraphQL API](https://juejin.cn/post/6931145990599049223)|翻译|5| +|[如何让 JavaScript 中的循环慢下来](https://juejin.cn/post/6924512805135581197)|校对|1| +|[为什么我的数据会漂移?](https://juejin.cn/post/6923824334188314638)|校对|3| +|[Javascript Memoization 入门指南](https://juejin.cn/post/6920460950424256526)|翻译|5| +|[理解 LSM 树:一种适用于频繁写入的数据库的结构](https://juejin.cn/post/6918940339676020743)|翻译|4.5| +|[Node.js 安全编程的最佳实践](https://juejin.cn/post/6918757099782537224)|校对|4| +|[DeepSpeed:所有人都能用的超大规模模型训练工具](https://juejin.cn/post/6916500899577724942)|校对|6| +|[使用 SpringBoot 和 MySQL 构建 GraphQL 服务端应用程序](https://juejin.cn/post/6899241103682502670)|翻译|10| +|[2021 年 Web 开发者应该掌握的 15 个 VSCode 扩展](https://juejin.cn/post/6910570256645914637)|校对|2| +|[为什么如今 Deno 正全面取代 Node.js](https://juejin.cn/post/6897420951592534030)|翻译|5| +|[迪米特法则](https://juejin.cn/post/6890050952049950733)|翻译|3| +|[WebAssembly 及其 JavaScript API 的完整介绍](https://juejin.cn/post/6887953627302854669)|校对|4| +|[Deno 已经死了吗?](https://juejin.cn/post/6899332861414146055)|校对|2| +|[JavaScript ES2021 中激动人心的特性](https://juejin.cn/post/6892246810250477575)|校对|1| +|[Python List 使用注意事项](https://juejin.cn/post/6886633614717485070)|翻译|5| +|[Python logging 使用指南](https://juejin.im/post/6881981250203353095)|翻译|4.5| +|[Python 的优化 — 驻留机制](https://juejin.im/post/6875879902902485005)|翻译|3| +|[让神经网络变得更小巧以方便部署](https://juejin.im/post/6873068232505458701)|校对|5| |[什么是无障碍?为什它对于用户体验很重要?](https://juejin.im/post/5ebf96a5f265da7b9754dd7d)|校对|1| |[你理解数据库死锁发生的原因吗?](https://juejin.im/post/5ed9ac93e51d45783f10fd25)|校对|2| |[开发者应该写博客的各种原因](https://juejin.im/post/5ea7eb586fb9a043867d4763)|校对|2| |[机器学习中的主动学习](https://juejin.im/post/5eaa71435188256d6c594746)|校对|3| |[NestJS 实现基本用户认证和会话](https://juejin.im/post/5e8c829f6fb9a03c4857710d)|校对|4.5| -## 译者:[yvonneit](https://github.com/yvonneit) 历史贡献积分:10 当前积分:10 二零二零:10 +## 译者:[yvonneit](https://github.com/yvonneit) 历史贡献积分:10 当前积分:10 |文章|类型|积分| |------|-------|-------| |[使用 JavaScript ES2020 中所有的 7 个新特性构建 App](https://juejin.im/post/5e9a685951882573834edc9e)|翻译|8| |[云服务如何帮助你提高业务效率?](https://juejin.im/post/5e8d07a96fb9a03c73797cef)|校对|2| -## 译者:[zhanght9527](https://github.com/zhanght9527) 历史贡献积分:21 当前积分:21 二零二零:21 +## 译者:[zhanght9527](https://github.com/zhanght9527) 历史贡献积分:21 当前积分:21 |文章|类型|积分| |------|-------|-------| @@ -9906,10 +10096,13 @@ |[如何成为一名优秀的远程开发者](https://juejin.im/post/5e9f9f64f265da47f0794a6e)|校对|2| |[为什么对象不变性很重要?](https://juejin.im/post/5e96703ef265da47ee3f64bb)|校对|3| -## 译者:[Gesj-yean](https://github.com/Gesj-yean) 历史贡献积分:50.5 当前积分:50.5 二零二零:50.5 +## 译者:[Gesj-yean](https://github.com/Gesj-yean) 历史贡献积分:63 当前积分:27 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 掘金笔记本 3 个 + 纪念水杯 2 个|减去积分|36| +|[VueJS 中更好的组件组合方式](https://juejin.im/post/6875236830984437768)|校对|1.5| +|[给前端开发者的 14 个 JavaScript 代码优化建议](https://juejin.im/post/6859562506721951751)|翻译|11| |[5 大 JavaScript 字符串操作库](https://juejin.im/post/5eba6becf265da7bb8773420)|校对|2| |[用 JavaScript 中的蹦床函数实现安全递归](https://juejin.im/post/5ec3eec2f265da76d318644e)|翻译|2| |[Object.freeze VS Object.seal —— JavaScript 数据不变性](https://juejin.im/post/5ed4b1b86fb9a047ce7c56ca)|翻译|4| @@ -9925,7 +10118,7 @@ |[关于 let 和 const 的对比](https://juejin.im/post/5ed5ec4ae51d457b3e77e37c)|校对|1| |[编写类型安全的多态 React 组件(不会导致 TypeScript 崩溃)](https://juejin.im/post/5eb4327be51d454d980e3fec)|校对|5| -## 译者:[ZiXYu](https://github.com/ZiXYu) 历史贡献积分:12 当前积分:12 二零二零:12 +## 译者:[ZiXYu](https://github.com/ZiXYu) 历史贡献积分:12 当前积分:12 |文章|类型|积分| |------|-------|-------| @@ -9933,30 +10126,49 @@ |[如何且为何要在单页应用中防止跨域资源共享](https://juejin.im/entry/5ec4ab64e51d45788a6d4f92/detail)|翻译|5| |[5 个优化技巧助你提高移动 Web 应用的用户留存率](https://juejin.im/post/5eb2a377f265da7bb563871f)|校对|2| -## 译者:[JohnieXu](https://github.com/JohnieXu) 历史贡献积分:14.5 当前积分:14.5 二零二零:14.5 +## 译者:[JohnieXu](https://github.com/JohnieXu) 历史贡献积分:47 当前积分:47 |文章|类型|积分| |------|-------|-------| +|[用 JavaScript 实现堆](https://juejin.cn/post/6893475005834330126)|校对|4| +|[WebAssembly 及其 JavaScript API 的完整介绍](https://juejin.cn/post/6887953627302854669)|翻译|8| +|[Blitz.js 简介:一个新兴的 React 全栈框架](https://juejin.cn/post/6887201657801670669)|校对|3| +|[分享九个 JavaScript 图片懒加载库](https://juejin.cn/post/6890325820200943629)|校对|3| +|[Web Locks API:跨 Tab 资源同步](https://juejin.cn/post/6895792867080405005)|校对|4| +|[使用原生 CSS 设置响应式字体](https://juejin.cn/post/6888471725080903687)|校对|1| +|[单页应用程序的哈希 URL 与普通 URL](https://juejin.cn/post/6884805346582331399)|校对|1.5| +|[NextJS vs. NuxtJS vs. GatsbyJS](https://juejin.cn/post/6882994530149203981)|校对|3| +|[10 款质量最佳最受欢迎的 Flutter 工具库](https://juejin.cn/post/6883102672044441613)|翻译|5| |[理解 zip 和 gzip 压缩格式背后的压缩算法](https://juejin.im/post/5ecb7f9651882542f4488845)|翻译|6| |[深入了解 React Fiber 内部实现](https://juejin.im/post/5ecb313d6fb9a0479a800294)|校对|7| |[使用 GraphQL 的 6 个月](https://juejin.im/post/5eb63dfae51d454dea6fdd78)|校对|1.5| -## 译者:[mattisonchao](https://github.com/mattisonchao) 历史贡献积分:2 当前积分:2 二零二零:2 +## 译者:[mattisonchao](https://github.com/mattisonchao) 历史贡献积分:2 当前积分:2 |文章|类型|积分| |------|-------|-------| |[简单的谬误](https://juejin.im/post/5eca7e8ee51d45784a354d1c)|校对|2| -## 译者:[HZNU-Qiu](https://github.com/HZNU-Qiu) 历史贡献积分:2 当前积分:2 二零二零:2 +## 译者:[HZNU-Qiu](https://github.com/HZNU-Qiu) 历史贡献积分:2 当前积分:2 |文章|类型|积分| |------|-------|-------| |[你不需要 passport.js — node.js 认证指南](https://juejin.im/post/5e060589f265da33b0718f55)|校对|2| -## 译者:[rachelcdev](https://github.com/rachelcdev) 历史贡献积分:16 当前积分:16 二零二零:16 +## 译者:[rachelcdev](https://github.com/rachelcdev) 历史贡献积分:45 当前积分:45 二零二一:8 |文章|类型|积分| |------|-------|-------| +|[自己写一个 redux](https://juejin.cn/post/6923922875191656462)|校对|8| +|[7 种有用的时间复杂度](https://juejin.im/post/6873379647125553159)|校对|3| +|[如何在悬停时创建菜单图像动画](https://juejin.im/post/6878561756793454599)|校对|3| +|[用户体验案例学习:重新设计 KoinStreet 主页](https://juejin.im/post/6869757477928304654)|校对|1.5| +|[如何实现交互式 WebGL 悬停效果](https://github.com/xitu/gold-miner/blob/master/article/2020/interactive-webgl-hover-effects.md)|校对|2| +|[世界比以往任何时候都更需要 Web 可访问性](https://juejin.im/post/6872684910058930189)|校对|2| +|[JavaScript 生成器:何时用 yield,何时用 yield* ?](https://juejin.im/post/6867036974441005063)|校对|1| +|[前端开发 8 大性能分析工具](https://juejin.im/post/6860664312504320014)|校对|3| +|[给前端开发者的 14 个 JavaScript 代码优化建议](https://juejin.im/post/6859562506721951751)|校对|4| +|[我的 React 组件会渲染两次,我快疯了](https://juejin.im/post/6858508463274885134)|校对|1.5| |[Object.freeze VS Object.seal —— JavaScript 数据不变性](https://juejin.im/post/5ed4b1b86fb9a047ce7c56ca)|校对|2| |[改善 CSS 的 10 个最佳实践](https://juejin.im/post/5ede03a9f265da76fe6cde03)|校对|3| |[CSS Flexbox 中安全/不安全的对齐方式](https://juejin.im/post/5edf0333e51d457859656af0)|校对|1| @@ -9966,10 +10178,14 @@ |[鲜为人知的 GraphQL 特性](https://juejin.im/post/5edbaf2751882543281f73fc)|校对|1| |[关于 let 和 const 的对比](https://juejin.im/post/5ed5ec4ae51d457b3e77e37c)|校对|1| -## 译者:[lhd951220](https://github.com/lhd951220) 历史贡献积分:24.5 当前积分:24.5 二零二零:24.5 +## 译者:[lhd951220](https://github.com/lhd951220) 历史贡献积分:33 当前积分:23 |文章|类型|积分| |------|-------|-------| +|2020 年 8 月 兑换 保温杯 1 个|减去积分|10| +|[写给工程师的《系统性能兵法》](https://juejin.im/post/6858061688386617358)|翻译|5| +|[在 SwiftUI 中构建服务端驱动的 UI 组件](https://juejin.im/post/6844904186862108679)|校对|2| +|[我的 React 组件会渲染两次,我快疯了](https://juejin.im/post/6858508463274885134)|校对|1.5| |[Ubuntu 20.04 会不会偷走更多的 Windows 用户?](https://juejin.im/post/5ec4e7926fb9a0480067b602)|校对|2| |[如何使用 Python 生成随机文本验证码](https://juejin.im/post/5f1567a3f265da22db2c351d)|翻译|5| |[移动端 WebKit 内核浏览器 100vh 问题的 CSS 修复方法](https://juejin.im/post/5ec87ef4e51d4578810b448d)|校对|1| @@ -9981,14 +10197,18 @@ |[鲜为人知的 GraphQL 特性](https://juejin.im/post/5edbaf2751882543281f73fc)|校对|1| |[使用 Deno 和 Oak 构建 CRUD API](https://juejin.im/post/5ed711086fb9a0479a801362)|翻译|1.5| -## 译者:[MangoTsing](https://github.com/MangoTsing) 历史贡献积分:2.5 当前积分:2.5 二零二零:2.5 +## 译者:[MangoTsing](https://github.com/MangoTsing) 历史贡献积分:28.5 当前积分:28.5 二零二一:15 |文章|类型|积分| |------|-------|-------| +|[只使用 CSS 进行用户追踪](https://juejin.cn/post/6887478219662950414)|翻译|5| +|[哪个跨平台框架才是最好的选择?React Native、Flutter 还是 Ionic。](https://juejin.cn/post/6884099570435883022)|翻译|10| +|[加速 vue.js 应用的六种绝技](https://juejin.im/post/6870808442911588365)|翻译|6| +|[如何利用 Polyfill 和转译在所有浏览器中使用最新 JavaScript 特性](https://juejin.im/post/6868513605055643662)|翻译|5| |[可以用来构建 Deno Web 应用程序的 7 个模块](https://juejin.im/post/5ed46435e51d45788619c778)|校对|2| |[使用 Deno 和 Oak 构建 CRUD API](https://juejin.im/post/5ed711086fb9a0479a801362)|校对|0.5| -## 译者:[hansonfang](https://github.com/hansonfang) 历史贡献积分:8 当前积分:8 二零二零:8 +## 译者:[hansonfang](https://github.com/hansonfang) 历史贡献积分:8 当前积分:8 |文章|类型|积分| |------|-------|-------| @@ -9997,16 +10217,27 @@ |[鲜为人知的 GraphQL 特性](https://juejin.im/post/5edbaf2751882543281f73fc)|翻译|2| |[寻找 2020 年最有意义的十大网页设计流行趋势](https://juejin.im/post/5ed74ee0e51d45788a6d686e)|校对|2| -## 译者:[noirlyrik](https://github.com/noirlyrik) 历史贡献积分:2 当前积分:2 二零二零:2 +## 译者:[noirlyrik](https://github.com/noirlyrik) 历史贡献积分:2 当前积分:2 |文章|类型|积分| |------|-------|-------| |[Schema.org:你未曾耳闻的流行网页标准 🤫](https://juejin.im/post/5ee4ce2df265da770c0f08b6)|校对|2| -## 译者:[z0gSh1u](https://github.com/z0gSh1u) 历史贡献积分:16.5 当前积分:16.5 二零二零:16.5 +## 译者:[z0gSh1u](https://github.com/z0gSh1u) 历史贡献积分:62 当前积分:52 二零二一:14 |文章|类型|积分| |------|-------|-------| +|[函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)|翻译|10| +|[Python 定义函数的 5 种参数](https://juejin.cn/post/6927094483200770062)|校对|3| +|[使用 clamp() 进行响应式设计](https://juejin.cn/post/6890830054134611976)|校对|1| +|[用 JavaScript 实现堆](https://juejin.cn/post/6893475005834330126)|校对|4| +|2020 年 8 月 兑换 T 恤 1 件|减去积分|10| +|[MVC,MVP,MVVM 对比](https://juejin.cn/post/6883088734699388941)|校对|2| +|[NextJS vs. NuxtJS vs. GatsbyJS](https://juejin.cn/post/6882994530149203981)|翻译|7| +|[重现:多样化 Mini-Batch 主动学习](https://juejin.cn/post/6890560237091340302)|翻译|8| +|[使用 JSON.stringify 处理 JavaScript 对象](https://juejin.im/post/6871807169562902541)|校对|1| +|[写给工程师的《系统性能兵法》](https://juejin.im/post/6858061688386617358)|校对|2.5| +|[用 Python 写一个俄罗斯方块游戏](https://juejin.im/post/6844904183456350221)|翻译|7| |[用 JavaScript 中的蹦床函数实现安全递归](https://juejin.im/post/5ec3eec2f265da76d318644e)|校对|1| |[Ubuntu 20.04 会不会偷走更多的 Windows 用户?](https://juejin.im/post/5ec4e7926fb9a0480067b602)|翻译|4| |[Deno 会对 Node 造成威胁吗?](https://juejin.im/post/5ecf6f166fb9a047d77cbe35)|校对|2| @@ -10016,10 +10247,21 @@ |[什么是无障碍?为什它对于用户体验很重要?](https://juejin.im/post/5ebf96a5f265da7b9754dd7d)|校对|1| |[我是如何用 20 小时学会 Sass 的以及为什么你也应该这么做](https://juejin.im/post/5ede14f6e51d4578885ca8fc)|翻译|3.5| -## 译者:[nia3y](https://github.com/nia3y) 历史贡献积分:80 当前积分:48 二零二零:80 +## 译者:[nia3y](https://github.com/nia3y) 历史贡献积分:121.5 当前积分:9.5 二零二一:8 |文章|类型|积分| |------|-------|-------| +|[自己写一个 redux](https://juejin.cn/post/6923922875191656462)|校对|8| +|2020 年 5 月 兑换 小黄鸭 6 个 + 纪念水杯 1 个 + 掘金笔记本 1 个|减去积分|32| +|[JavaScript 的面向切面编程](https://juejin.cn/post/6903484050095210509)|校对|2| +|[TypeScript 的 5 个建议](https://juejin.cn/post/6906307187816349703)|校对|2.5| +|[前端应用的性能指标](https://juejin.cn/post/6884055395434758151)|翻译|8.5| +|2020 年 8 月 兑换 掘金桌垫 1 个、台灯 1 个|减去积分|48| +|[NextJS vs. NuxtJS vs. GatsbyJS](https://juejin.cn/post/6882994530149203981)|校对|3| +|[最常用的 4 种 JavaScript 设计模式](https://github.com/xitu/gold-miner/blob/master/article/2020/4-useful-javascript-design-patterns-you-should-know.md)|校对|4| +|[如何处理 JavaScript 比较中的临界情况](https://juejin.im/post/6872682987859738632)|校对|2| +|[React vs. Svelte:虚拟与真实 DOM 间的战争](https://juejin.im/post/6870858079513247758)|翻译|4.5| +|[如何在字符串中隐藏秘密 —— JavaScript 中的现代文本隐藏](https://juejin.im/post/6856737400396349454)|翻译|7| |兑换水杯 1 个,笔记本 1 个|减去积分|14| |兑换小黄鸭 6 个|减去积分|18| |[用户体验案例学习:Mood Talk ——  一个心理健康应用](https://juejin.im/post/5ebbb38ae51d454dca711099)|翻译|6| @@ -10046,33 +10288,701 @@ |[2020 年要学习的 7 种编程语言和框架](https://juejin.im/post/5e663cec518825496e786051)|校对|3| |[关于 icon 设计的 7 大准则](https://juejin.im/post/5e5dbd3e6fb9a07cd323dd2b)|校对|3| -## 译者:[plusmultiply0](https://github.com/plusmultiply0) 历史贡献积分:3 当前积分:3 二零二零:3 - -|文章|类型|积分| -|------|-------|-------| +## 译者:[plusmultiply0](https://github.com/plusmultiply0) 历史贡献积分:62 当前积分:62 二零二一:7 + +|文章|类型|积分| +|------|-------|-------| +|[为什么你应该使用 Picture 标签而不是 Img 标签](https://juejin.cn/post/6923840549170446343)|翻译|5| +|[你应该知道的 3 个罕见的 Bash 技巧](https://juejin.cn/post/6923190362706018318)|校对|2| +|[WebAssembly 及其 JavaScript API 的完整介绍](https://juejin.cn/post/6887953627302854669)|校对|4| +|[Blitz.js 简介:一个新兴的 React 全栈框架](https://juejin.cn/post/6887201657801670669)|翻译|6| +|[前端应用的性能指标](https://juejin.cn/post/6884055395434758151)|校对|4| +|[Web Locks API:跨 Tab 资源同步](https://juejin.cn/post/6895792867080405005)|校对|4| +|[如何在 Nextjs 中使用 cookies 来持久化保存用户信息](https://juejin.cn/post/6896062683263860749)|翻译|4| +|[Github Actions 工作流的创建与跟踪](https://juejin.cn/post/6892248874669309965)|校对|2| +|[在 React 中使用 Service Worker](https://juejin.im/post/6881616183158636552)|翻译|5| +|[掌握 JavaScript ES6 中的 Symbol 类型](https://juejin.im/post/6880485630501978126)|校对|4| +|[使用 React 和 localStorage 实现的简易 Dark Mode 开关](https://juejin.im/post/6875538309934743560)|校对|2.5| +|[给前端开发者的 14 个 JavaScript 代码优化建议](https://juejin.im/post/6859562506721951751)|校对|5| +|[JavaScript 技巧 —— 子代构造函数,文本选择,内联 Workers 等等](https://juejin.im/post/6854573219622420488)|翻译|3| +|[写给工程师的《系统性能兵法》](https://juejin.im/post/6858061688386617358)|校对|2.5| +|[打包用于分发的 UI 库 —— 当你要发布一个 UI 组件库时,你可能需要遵守的指南](https://juejin.im/post/6863091746113323021)|翻译|6| |[Redux 中过时的 props 和僵尸子节点](https://juejin.im/post/5f0c1fd76fb9a07e8e44f2e5)|校对|3| -## 译者:[kanweiwei](https://github.com/kanweiwei) 历史贡献积分:4 当前积分:4 二零二零:4 +## 译者:[kanweiwei](https://github.com/kanweiwei) 历史贡献积分:4 当前积分:4 |文章|类型|积分| |------|-------|-------| |[如何写一份能让你获得面试机会的前端求职简历](https://juejin.im/post/5ef5ef41f265da22ff543630)|校对|4| -## 译者:[x1ny](https://github.com/x1ny) 历史贡献积分:6.5 当前积分:6.5 二零二零:6.5 +## 译者:[x1ny](https://github.com/x1ny) 历史贡献积分:9 当前积分:9 |文章|类型|积分| |------|-------|-------| +|[5 个鲜为人知的 Chrome 开发者工具的特性](https://juejin.im/post/6875240551390642189)|校对|0.5| +|[React vs. Svelte:虚拟与真实 DOM 间的战争](https://juejin.im/post/6870858079513247758)|校对|2| |[如何且为何要在单页应用中防止跨域资源共享](https://juejin.im/entry/5ec4ab64e51d45788a6d4f92/detail)|校对|2.5| |[关于 JavaScript 中 Symbol 数据类型你需要了解的一切](https://juejin.im/post/5ebd353c5188256d9433b103)|校对|4| -## 译者:[Candy-design](https://github.com/Candy-design) 历史贡献积分:2.5 当前积分:2.5 二零二零:2.5 +## 译者:[Candy-design](https://github.com/Candy-design) 历史贡献积分:2.5 当前积分:2.5 |文章|类型|积分| |------|-------|-------| |[Swift 5.3 的新功能,你了解吗?](https://juejin.im/post/5f158ae4e51d453460293edc)|校对|2.5| -## 译者:[lizhenZuo](https://github.com/lizhenZuo) 历史贡献积分:2.5 当前积分:2.5 二零二零:2.5 +## 译者:[lizhenZuo](https://github.com/lizhenZuo) 历史贡献积分:2.5 当前积分:2.5 |文章|类型|积分| |------|-------|-------| |[Swift 5.3 的新功能,你了解吗?](https://juejin.im/post/5f158ae4e51d453460293edc)|校对|2.5| + +## 译者:[zenblo](https://github.com/zenblo) 历史贡献积分:215.5 当前积分:215.5 二零二一:75 + +|文章|类型|积分| +|------|-------|-------| +|[TypeScript 4.2 正式发布:优化了类型和开发者体验](https://juejin.cn/post/6935255387893399560)|校对|2| +|[在 React 中使用 Immer 管理不可变状态](https://juejin.cn/post/6935790852476239886)|翻译|4| +|[自适应 CSS 栅格:自由布局的最终版本](https://juejin.cn/post/6935090806210428959)|校对|1| +|[Deno 将停用 TypeScript 的五个原因](https://juejin.cn/post/6934140963262562312)|翻译|4| +|[Bash 中的 if else 语句](https://juejin.cn/post/6934324540692496392)|校对|2| +|[我后悔没有在自己成为 React 开发者之前做的 6 件事情](https://juejin.cn/post/6934144158332354567)|校对|1| +|[你应该编译你的 JavaScript 代码吗?](https://juejin.cn/post/6926927963636105223)|校对|2| +|[如何在浏览器上使用 NoSQL 数据库 IndexedDB](https://juejin.cn/post/6930883284456964109)|翻译|5| +|[简述 HTTP 请求与跨域资源共享 CORS](https://juejin.cn/post/6927191095470194695)|翻译|5| +|[2021 年 JavaScript 测试框架回顾](https://juejin.cn/post/6927585452253790216)|校对|1| +|[为什么 React Hooks 是错误的抽象](https://juejin.cn/post/6930529765048713229)|校对|3| +|[SwiftUI 2 应用生命周期的终极指导](https://juejin.cn/post/6924119708832628749)|校对|2| +|[揭开图着色算法的神秘面纱](https://juejin.cn/post/6924668410416791566)|翻译|5| +|[掌握这 5 个 TypeScript 高级技巧,成为更好的开发者](https://juejin.cn/post/6924293152907984909)|校对|3| +|[只使用 CSS 进行用户追踪](https://juejin.cn/post/6887478219662950414)|校对|2| +|[Android 中的意料之外的应用崩溃以及解决它们的方法](https://juejin.cn/post/6925336143953133581)|校对|2| +|[在 TypeScript 中引入 JSON 模块](https://juejin.cn/post/6923188659957006343)|校对|0.5| +|[使用 Flutter 的 Container 控件构建优美的用户界面](https://juejin.cn/post/6923854569596256263)|校对|0.5| +|[2021 年 Web 应用开发常用的五个图标库](https://juejin.cn/post/6922416136294252557)|翻译|6| +|[Python 中的列表和元组](https://juejin.cn/post/6923195053754023949)|校对|2| +|[虚拟 DOM 来源于文档片段吗?](https://juejin.cn/post/6902211857244028941)|校对|2| +|[减少 Web 应用程序中 CORS 预检时间的 4 种方法](https://juejin.cn/post/6914561805465419784)|校对|2| +|[如何使用 Node.js 执行多线程](https://juejin.cn/post/6915255619926622222)|翻译|3| +|[如何成为谷歌开发专家(GDE)— 实用指南](https://juejin.cn/post/6918640631317266439)|校对|2| +|[iOS 中的 widget](https://juejin.cn/post/6920017496497979399)|校对|3| +|[GitHub Package Registry 是否值得尝试](https://juejin.cn/post/6915255280959750152)|翻译|5| +|[使用 SpringBoot 和 MySQL 构建 GraphQL 服务端应用程序](https://juejin.cn/post/6899241103682502670)|校对|5| +|12 月推荐前端文章 2 篇|奖励|2| +|[单体应用与微前端开发对比](https://juejin.cn/post/6906021856210321422)|翻译|6| +|[提高开发效率的五个 Chrome 扩展程序](https://juejin.cn/post/6903831004034072589)|翻译|1| +|[继承 vs 组合:哪一个更适合你的 JavaScript 项目?](https://juejin.cn/post/6906288659742654478)|校对|2| +|[增量 DOM 与虚拟 DOM 的对比使用](https://juejin.cn/post/6903765877296988174)|翻译|5| +|[SwiftUI 黑暗模式——最简单的方法](https://juejin.cn/post/6905925634552233998)|校对|1| +|[页面生命周期 API:每一个前端开发者都应该知道的浏览器 API](https://juejin.cn/post/6906779518040539144)|校对|2| +|[四个优秀 Vue.js 静态站点生成器](https://juejin.cn/post/6903309715309068295)|翻译|4| +|[黑暗主题 — 现代 UI 设计](https://juejin.cn/post/6901856999235911688)|翻译|5| +|[你不可错过的 10 个 Xcode 技巧和快捷键](https://juejin.cn/post/6913888065937211399)|校对|2| +|[理解 JavaScript 中模块的导入和导出](https://juejin.cn/post/6904980094998020109)|校对|3| +|[简单介绍就能理解的 React Portals(传送门)](https://juejin.cn/post/6904979968413925384)|校对|2| +|[SwiftUI 中的 PageTabViewStyle](https://juejin.cn/post/6906289114300039182)|校对|1| +|[Blitz.js 简介:一个新兴的 React 全栈框架](https://juejin.cn/post/6887201657801670669)|校对|3| +|[如何使用 useRef 修复 React 性能问题](https://juejin.cn/post/6900510215851114509)|校对|2| +|[在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)|校对|2| +|[从零开始了解 JavaScript 装饰器](https://juejin.cn/post/6898189092652384270)|校对|5| +|[5 分钟内从单体架构迁移到微服务架构](https://juejin.cn/post/6900884077226917901)|校对|2| +|[在几秒钟内为你的开发环境创建一个私有 PostgreSQL 数据库](https://juejin.cn/post/6899674625325105159)|校对|4| +|[四种跨浏览器选项卡实时通信方法](https://juejin.cn/post/6896273264214179848)|翻译|4| +|[如何避免 Android 设备的 WiFi 扫描节流](https://juejin.cn/post/6900807946884612104)|校对|1| +|[分享九个 JavaScript 图片懒加载库](https://juejin.cn/post/6890325820200943629)|翻译|8| +|[JavaScript 颜色处理库 Chroma.js 的应用](https://juejin.cn/post/6886263418907688974)|翻译|1| +|[使用原生 CSS 实现自适应视频](https://juejin.cn/post/6898144070125518856)|翻译|1| +|[使用 JavaScript 解构让代码更优雅](https://juejin.cn/post/6901081096260648974)|翻译|4| +|11 月推荐前端文章 1 篇|奖励|1| +|10 月推荐前端文章 2 篇|奖励|2| +|[使用 Svelte 开发前端应用的五个理由](https://juejin.cn/post/6897010393609142279)|翻译|3| +|[浏览器 Web History API 的应用](https://juejin.cn/post/6891500768973553672)|翻译|1.5| +|[使用原生 CSS 设置响应式字体](https://juejin.cn/post/6888471725080903687)|翻译|3| +|[Github Actions 工作流的创建与跟踪](https://juejin.cn/post/6892248874669309965)|翻译|4| +|[大数据:简述 Lambda 架构](https://juejin.cn/post/6887845604886741006)|校对|2| +|[单页应用程序的哈希 URL 与普通 URL](https://juejin.cn/post/6884805346582331399)|翻译|3| +|[基于内容安全策略增强 JavaScript 安全性](https://juejin.cn/post/6885887317609807886)|翻译|4| +|[在 Swift 中玩转 emoji](https://juejin.cn/post/6887739774254841863)|校对|2| +|[抽象数据类型与软件危机](https://juejin.cn/post/6900761312532529166)|翻译|10| +|推荐前端文章 1 篇|奖励|1| +|[如何在悬停时创建菜单图像动画](https://juejin.im/post/6878561756793454599)|翻译|6| +|[如何实现交互式 WebGL 悬停效果](https://github.com/xitu/gold-miner/blob/master/article/2020/interactive-webgl-hover-effects.md)|翻译|4| +|[分享我喜欢的十五条 JavaScript 编程技巧](https://github.com/xitu/gold-miner/blob/master/article/2020/my-favorite-javascript-tips-and-tricks.md)|翻译|4| +|[你应该了解的八种浏览器 API](https://github.com/xitu/gold-miner/blob/master/article/2020/8-unheard-of-browser-apis-you-should-be-aware-of.md)|翻译|5| +|[如何在字符串中隐藏秘密 —— JavaScript 中的现代文本隐藏](https://juejin.im/post/6856737400396349454)|校对|3| +|[使用 Chrome 的 Shape Detection API 检测人脸,文本甚至条形码](https://juejin.im/post/6864391729693491207)|校对|3| +|[打包用于分发的 UI 库 —— 当你要发布一个 UI 组件库时,你可能需要遵守的指南](https://juejin.im/post/6863091746113323021)|校对|3| +|8 月推荐前端文章 2 篇|奖励|2| +|8 月推荐前端文章 1 篇|奖励|1| + +## 译者:[Zhengjian-L](https://github.com/Zhengjian-L) 历史贡献积分:16 当前积分:16 二零二一:6 + +|文章|类型|积分| +|------|-------|-------| +|[Python 定义函数的 5 种参数](https://juejin.cn/post/6927094483200770062)|翻译|6| +|[知识的极限](https://juejin.im/post/6874475968325484552)|校对|3| +|[用户体验案例学习:重新设计 KoinStreet 主页](https://juejin.im/post/6869757477928304654)|翻译|4| +|[用 Python 写一个俄罗斯方块游戏](https://juejin.im/post/6844904183456350221)|校对|3| + +## 译者:[rocwong-cn](https://github.com/rocwong-cn) 历史贡献积分:21 当前积分:21 + +|文章|类型|积分| +|------|-------|-------| +|[分享九个 JavaScript 图片懒加载库](https://juejin.cn/post/6890325820200943629)|校对|3| +|[让你的 Web 应用和移动应用选择 PWA 的 5 个理由](https://juejin.im/post/6868084125195042823)|翻译|6| +|[TypeScript 4.0 终于发布了我一直在等待的东西](https://juejin.im/post/6864473591770152968)|翻译|3| +|[使用 Chrome 的 Shape Detection API 检测人脸,文本甚至条形码](https://juejin.im/post/6864391729693491207)|翻译|6| +|[打包用于分发的 UI 库 —— 当你要发布一个 UI 组件库时,你可能需要遵守的指南](https://juejin.im/post/6863091746113323021)|校对|3| + +## 译者:[Isildur46](https://github.com/Isildur46) 历史贡献积分:25.5 当前积分:25.5 二零二一:3 + +|文章|类型|积分| +|------|-------|-------| +|[关于 Node.js 中的异步迭代器](https://juejin.cn/post/6934596464639213576)|翻译|3| +|[7 种有用的时间复杂度](https://juejin.im/post/6873379647125553159)|校对|3| +|[JavaScript 函数中一些你不知道的秘密](https://juejin.im/post/6871101056642711559)|翻译|7| +|[JavaScript 引擎概述](https://juejin.im/post/6869976412745367566)|翻译|5| +|[让你的 Web 应用和移动应用选择 PWA 的 5 个理由](https://juejin.im/post/6868084125195042823)|校对|2.5| +|[JavaScript 生成器:何时用 yield,何时用 yield* ?](https://juejin.im/post/6867036974441005063)|翻译|3| +|[如何利用 Polyfill 和转译在所有浏览器中使用最新 JavaScript 特性](https://juejin.im/post/6868513605055643662)|校对|2| + +## 译者:[HeroXiaozheng](https://github.com/HeroXiaozheng) 历史贡献积分:3 当前积分:3 + +|文章|类型|积分| +|------|-------|-------| +|[Javascript 应用中引入 CSS 的几种方式](https://juejin.im/post/6867054761741549576)|校对|3| + +## 译者:[kylinholmes](https://github.com/kylinholmes) 历史贡献积分:2.5 当前积分:2.5 + +|文章|类型|积分| +|------|-------|-------| +|[写给工程师的《系统性能兵法》](https://juejin.im/post/6858061688386617358)|校对|2.5| + +## 译者:[loststar](https://github.com/loststar) 历史贡献积分:11 当前积分:11 二零二一:2.5 + +|文章|类型|积分| +|------|-------|-------| +|[微服务是你的最佳解决方案么?](https://juejin.cn/post/6881415957303001102)|校对|2.5| +|[通过“四不要”掌握 Python 中的 Lambda 函数](https://juejin.cn/post/6883389756269395975)|翻译|3| +|[在 React 中使用 Service Worker](https://juejin.im/post/6881616183158636552)|校对|2| +|[利用映射提高 MongoDB 性能](https://juejin.im/post/6881503834737213454)|校对|2| +|[Python:使用 locals() 和 globals() 巧妙编程](https://github.com/xitu/gold-miner/blob/master/article/2020/python-smart-coding-with-locals-and-global.md)|校对|0.5| +|[JavaScript 技巧 —— 子代构造函数,文本选择,内联 Workers 等等](https://juejin.im/post/6854573219622420488)|校对|1| + +## 译者:[onlinelei](https://github.com/onlinelei) 历史贡献积分:8.5 当前积分:8.5 + +|文章|类型|积分| +|------|-------|-------| +|[MVC,MVP,MVVM 对比](https://juejin.cn/post/6883088734699388941)|校对|2| +|[利用映射提高 MongoDB 性能](https://juejin.im/post/6881503834737213454)|翻译|4| +|[你应该了解的八种浏览器 API](https://github.com/xitu/gold-miner/blob/master/article/2020/8-unheard-of-browser-apis-you-should-be-aware-of.md)|校对|2| +|[8 个有用的 SCSS 最佳实践](https://juejin.im/post/6862499761351163911)|校对|0.5| + +## 译者:[Inchill](https://github.com/Inchill) 历史贡献积分:28 当前积分:28 + +|文章|类型|积分| +|------|-------|-------| +|[为什么如今 Deno 正全面取代 Node.js](https://juejin.cn/post/6897420951592534030)|校对|2| +|[Deno 已经死了吗?](https://juejin.cn/post/6899332861414146055)|翻译|5| +|[我的网站加载时间不到 1 秒,这是我如何做到的!](https://juejin.cn/post/6870329885034807310)|校对|1.5| +|[掌握 JavaScript ES6 中的 Symbol 类型](https://juejin.im/post/6880485630501978126)|翻译|9| +|[使用 React 和 localStorage 实现的简易 Dark Mode 开关](https://juejin.im/post/6875538309934743560)|翻译|5| +|[使用 JSON.stringify 处理 JavaScript 对象](https://juejin.im/post/6871807169562902541)|翻译|2.5| +|[你应该了解的八种浏览器 API](https://github.com/xitu/gold-miner/blob/master/article/2020/8-unheard-of-browser-apis-you-should-be-aware-of.md)|校对|2| +|[TypeScript 4.0 终于发布了我一直在等待的东西](https://juejin.im/post/6864473591770152968)|校对|1| + +## 译者:[Misszhu](https://github.com/Misszhu) 历史贡献积分:2.5 当前积分:2.5 + +|文章|类型|积分| +|------|-------|-------| +|[让你的 Web 应用和移动应用选择 PWA 的 5 个理由](https://juejin.im/post/6868084125195042823)|校对|2.5| + +## 译者:[Amy-Designer](https://github.com/Amy-Designer) 历史贡献积分:6 当前积分:6 + +|文章|类型|积分| +|------|-------|-------| +|[颜色为何成为数据可视化的关键,怎样使用它?](https://juejin.im/post/6872238362233831432)|翻译|6| + +## 译者:[CaptainWang98](https://github.com/CaptainWang98) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[JavaScript 引擎概述](https://juejin.im/post/6869976412745367566)|校对|2| + +## 译者:[actini](https://github.com/actini) 历史贡献积分:6 当前积分:6 + +|文章|类型|积分| +|------|-------|-------| +|[使用 Shpinx 为 Python 项目自动生成文档](https://juejin.cn/post/6882904677373968397)|翻译|5| +|[Python:使用 locals() 和 globals() 巧妙编程](https://github.com/xitu/gold-miner/blob/master/article/2020/python-smart-coding-with-locals-and-global.md)|翻译|1| + +## 译者:[jacob-lcs](https://github.com/jacob-lcs) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[如何实现交互式 WebGL 悬停效果](https://github.com/xitu/gold-miner/blob/master/article/2020/interactive-webgl-hover-effects.md)|校对|2| + +## 译者:[whatwewant](https://github.com/whatwewant) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[如何实现交互式 WebGL 悬停效果](https://github.com/xitu/gold-miner/blob/master/article/2020/interactive-webgl-hover-effects.md)|校对|2| + +## 译者:[CuteSunLee](https://github.com/CuteSunLee) 历史贡献积分:4 当前积分:4 + +|文章|类型|积分| +|------|-------|-------| +|[最常用的 4 种 JavaScript 设计模式](https://github.com/xitu/gold-miner/blob/master/article/2020/4-useful-javascript-design-patterns-you-should-know.md)|校对|4| + +## 译者:[qq1037305420](https://github.com/qq1037305420) 历史贡献积分:3 当前积分:3 + +|文章|类型|积分| +|------|-------|-------| +|[如何在悬停时创建菜单图像动画](https://juejin.im/post/6878561756793454599)|校对|3| + +## 译者:[dupanpan](https://github.com/dupanpan) 历史贡献积分:3 当前积分:3 + +|文章|类型|积分| +|------|-------|-------| +|[ES2017 最佳特性  —  数组中的异步函数以及共享缓冲区](https://juejin.im/post/6878849121269055501)|校对|1.5| +|[VueJS 中更好的组件组合方式](https://juejin.im/post/6875236830984437768)|校对|1.5| + +## 译者:[Shirley-He-Maker](https://github.com/Shirley-He-Maker) 历史贡献积分:6 当前积分:6 二零二一:5 + +|文章|类型|积分| +|------|-------|-------| +|[构建设计系统和组件库](https://juejin.cn/post/6924152501805678606)|校对|5| +|[5 个鲜为人知的 Chrome 开发者工具的特性](https://juejin.im/post/6875240551390642189)|翻译|1| + +## 译者:[calali](https://github.com/calali) 历史贡献积分:0.5 当前积分:0.5 + +|文章|类型|积分| +|------|-------|-------| +|[5 个鲜为人知的 Chrome 开发者工具的特性](https://juejin.im/post/6875240551390642189)|校对|0.5| + +## 译者:[HurryOwen](https://github.com/HurryOwen) 历史贡献积分:30.5 当前积分:30.5 二零二一:6 + +|文章|类型|积分| +|------|-------|-------| +|[哪个跨平台框架才是最好的选择?React Native、Flutter 还是 Ionic。](https://juejin.cn/post/6884099570435883022)|校对|5| +|[使用 clamp() 进行响应式设计](https://juejin.cn/post/6890830054134611976)|校对|1| +|[用 JavaScript 实现堆](https://juejin.cn/post/6893475005834330126)|翻译|8| +|[前端应用的性能指标](https://juejin.cn/post/6884055395434758151)|校对|4| +|[四种跨浏览器选项卡实时通信方法](https://juejin.cn/post/6896273264214179848)|校对|2| +|[如何在 Nextjs 中使用 cookies 来持久化保存用户信息](https://juejin.cn/post/6896062683263860749)|校对|2| +|[JavaScript ES2021 中激动人心的特性](https://juejin.cn/post/6892246810250477575)|校对|1| +|[使用原生 CSS 设置响应式字体](https://juejin.cn/post/6888471725080903687)|校对|1| +|[Github Actions 工作流的创建与跟踪](https://juejin.cn/post/6892248874669309965)|校对|2| +|[基于内容安全策略增强 JavaScript 安全性](https://juejin.cn/post/6885887317609807886)|校对|2| +|[使用 React 和 localStorage 实现的简易 Dark Mode 开关](https://juejin.im/post/6875538309934743560)|校对|2.5| + +## 译者:[caiyundong](https://github.com/caiyundong) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[Python 的优化 — 驻留机制](https://juejin.im/post/6875879902902485005)|校对|2| + +## 译者:[ivileey](https://github.com/ivileey) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[利用映射提高 MongoDB 性能](https://juejin.im/post/6881503834737213454)|校对|2| + +## 译者:[Aurevior](https://github.com/Aurevior) 历史贡献积分:4 当前积分:4 + +|文章|类型|积分| +|------|-------|-------| +|[重现:多样化 Mini-Batch 主动学习](https://juejin.cn/post/6890560237091340302)|校对|4| + +## 译者:[juu574](https://github.com/juu574) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[10 款质量最佳最受欢迎的 Flutter 工具库](https://juejin.cn/post/6883102672044441613)|校对|2| + +## 译者:[wangqinggang](https://github.com/wangqinggang) 历史贡献积分:10.5 当前积分:10.5 二零二一:5 + +|文章|类型|积分| +|------|-------|-------| +|[微服务是你的最佳解决方案么?](https://juejin.cn/post/6881415957303001102)|翻译|5| +|[Python logging 使用指南](https://juejin.im/post/6881981250203353095)|校对|2| +|[我的网站加载时间不到 1 秒,这是我如何做到的!](https://juejin.cn/post/6870329885034807310)|翻译|3.5| + +## 译者:[Eminlin](https://github.com/Eminlin) 历史贡献积分:5 当前积分:5 二零二一:2 + +|文章|类型|积分| +|------|-------|-------| +|[理解 LSM 树:一种适用于频繁写入的数据库的结构](https://juejin.cn/post/6918940339676020743)|校对|2| +|[Golang 切片综合指南](https://juejin.cn/post/6883398632071462919)|校对|3| + +## 译者:[leexgh](https://github.com/leexgh) 历史贡献积分:5 当前积分:5 + +|文章|类型|积分| +|------|-------|-------| +|[抽象数据类型与软件危机](https://juejin.cn/post/6900761312532529166)|校对|5| + +## 译者:[landiy](https://github.com/landiy) 历史贡献积分:5 当前积分:5 + +|文章|类型|积分| +|------|-------|-------| +|[抽象数据类型与软件危机](https://juejin.cn/post/6900761312532529166)|校对|5| + +## 译者:[Godlowd](https://github.com/Godlowd) 历史贡献积分:3 当前积分:3 + +|文章|类型|积分| +|------|-------|-------| +|[在 Swift 中玩转 emoji](https://juejin.cn/post/6887739774254841863)|校对|3| + +## 译者:[jackwener](https://github.com/jackwener) 历史贡献积分:14.5 当前积分:14.5 二零二一:2.5 + +|文章|类型|积分| +|------|-------|-------| +|[微服务是你的最佳解决方案么?](https://juejin.cn/post/6881415957303001102)|校对|2.5| +|[迪米特法则](https://juejin.cn/post/6890050952049950733)|校对|1| +|[酷毙了的算法:日志结构存储](https://juejin.cn/post/6898766259584761864)|翻译|6| +|10 月推荐算法文章 1 篇|奖励|1| +|[大数据:简述 Lambda 架构](https://juejin.cn/post/6887845604886741006)|翻译|4| + +## 译者:[bljessica](https://github.com/bljessica) 历史贡献积分:2 当前积分:2 + +|文章|类型|积分| +|------|-------|-------| +|[大数据:简述 Lambda 架构](https://juejin.cn/post/6887845604886741006)|校对|2| + +## 译者:[Liusq-Cindy](https://github.com/Liusq-Cindy) 历史贡献积分:8 当前积分:8 + +|文章|类型|积分| +|------|-------|-------| +|[JavaScript 的面向切面编程](https://juejin.cn/post/6903484050095210509)|翻译|5| +|[使用 Svelte 开发前端应用的五个理由](https://juejin.cn/post/6897010393609142279)|校对|1| +|[如何在 Nextjs 中使用 cookies 来持久化保存用户信息](https://juejin.cn/post/6896062683263860749)|校对|2| + +## 译者:[regon-cao](https://github.com/regon-cao) 历史贡献积分:99.5 当前积分:99.5 二零二一:46 + +|文章|类型|积分| +|------|-------|-------| +|[函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)|校对|5| +|[简述 HTTP 请求与跨域资源共享 CORS](https://juejin.cn/post/6927191095470194695)|校对|2| +|[我拒绝了 MIT 的 Offer,依然是一个高价值的开发者](https://juejin.cn/post/6924489699641786375)|校对|3| +|[在 TypeScript 中引入 JSON 模块](https://juejin.cn/post/6923188659957006343)|校对|0.5| +|[Node.js 缓冲区的完整指南](https://juejin.cn/post/6917192648424390669)|校对|1| +|[虚拟 DOM 来源于文档片段吗?](https://juejin.cn/post/6902211857244028941)|翻译|5| +|[Javascript Memoization 入门指南](https://juejin.cn/post/6920460950424256526)|校对|2| +|[深入了解 JavaScript 模块](https://juejin.cn/post/6920153306392166413)|翻译|6.5| +|[减少 Web 应用程序中 CORS 预检时间的 4 种方法](https://juejin.cn/post/6914561805465419784)|翻译|5| +|[如何使用 Node.js 执行多线程](https://juejin.cn/post/6915255619926622222)|校对|1.5| +|[Web 应用缓存的基础知识](https://juejin.cn/post/6913898149740281870)|翻译|4| +|[使用 CSS 提升页面渲染速度](https://juejin.cn/post/6911689122759475208)|校对|3| +|[在 Node.js 中避免内存泄漏:性能最佳实践](https://juejin.cn/post/6911488842079928327)|校对|2.5| +|[使用 SpringBoot 和 MySQL 构建 GraphQL 服务端应用程序](https://juejin.cn/post/6899241103682502670)|校对|5| +|[2021 年 Web 开发者应该掌握的 15 个 VSCode 扩展](https://juejin.cn/post/6910570256645914637)|翻译|4| +|[单体应用与微前端开发对比](https://juejin.cn/post/6906021856210321422)|校对|3| +|[继承 vs 组合:哪一个更适合你的 JavaScript 项目?](https://juejin.cn/post/6906288659742654478)|翻译|5| +|[增量 DOM 与虚拟 DOM 的对比使用](https://juejin.cn/post/6903765877296988174)|校对|2| +|[TypeScript 的 5 个建议](https://juejin.cn/post/6906307187816349703)|校对|2.5| +|[黑暗主题 — 现代 UI 设计](https://juejin.cn/post/6901856999235911688)|校对|2| +|[寻找最优化 AutoML 库](https://juejin.cn/post/6906859687682965517)|校对|4| +|[为什么如今 Deno 正全面取代 Node.js](https://juejin.cn/post/6897420951592534030)|校对|2| +|[爱 GraphQL 胜过 REST](https://juejin.cn/post/6914306976294338567)|校对|2| +|[探索 Android 中的 ConstraintLayout 2.0](https://juejin.cn/post/6906770827228741646)|校对|1.5| +|[如何使用 useRef 修复 React 性能问题](https://juejin.cn/post/6900510215851114509)|校对|2| +|[在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)|翻译|5| +|[从零开始了解 JavaScript 装饰器](https://juejin.cn/post/6898189092652384270)|翻译|10| +|[Deno 已经死了吗?](https://juejin.cn/post/6899332861414146055)|校对|2| +|[如何避免 Android 设备的 WiFi 扫描节流](https://juejin.cn/post/6900807946884612104)|翻译|3| +|[使用原生 CSS 实现自适应视频](https://juejin.cn/post/6898144070125518856)|校对|0.5| +|[使用 JavaScript 解构让代码更优雅](https://juejin.cn/post/6901081096260648974)|校对|2| +|[使用 Svelte 开发前端应用的五个理由](https://juejin.cn/post/6897010393609142279)|校对|1| + +## 译者:[NieZhuZhu](https://github.com/NieZhuZhu) 历史贡献积分:52 当前积分:52 二零二一:15 + +|文章|类型|积分| +|------|-------|-------| +|[函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)|校对|5| +|[解构标志性的 Apple Watch Bubble UI](https://juejin.cn/post/6919630087843217416)|翻译|7| +|[使用 CSS 提升页面渲染速度](https://juejin.cn/post/6911689122759475208)|校对|3| +|[四个优秀 Vue.js 静态站点生成器](https://juejin.cn/post/6903309715309068295)|校对|1.5| +|[你不可错过的 10 个 Xcode 技巧和快捷键](https://juejin.cn/post/6913888065937211399)|校对|2| +|[理解 JavaScript 中模块的导入和导出](https://juejin.cn/post/6904980094998020109)|翻译|7| +|[简单介绍就能理解的 React Portals(传送门)](https://juejin.cn/post/6904979968413925384)|翻译|4| +|[为什么要让你的代码尽可能简单](https://juejin.cn/post/6914669681500487687)|翻译|8| +|[爱 GraphQL 胜过 REST](https://juejin.cn/post/6914306976294338567)|翻译|4| +|[如何使用 useRef 修复 React 性能问题](https://juejin.cn/post/6900510215851114509)|翻译|4.5| +|[在浏览器中处理自然语言](https://juejin.cn/post/6899707995828174861)|校对|1| +|[5 分钟内从单体架构迁移到微服务架构](https://juejin.cn/post/6900884077226917901)|校对|2| +|[如何避免 Android 设备的 WiFi 扫描节流](https://juejin.cn/post/6900807946884612104)|校对|1| +|[使用 JavaScript 解构让代码更优雅](https://juejin.cn/post/6901081096260648974)|校对|2| + +## 译者:[ousheobin](https://github.com/ousheobin) 历史贡献积分:3 当前积分:3 + +|文章|类型|积分| +|------|-------|-------| +|[酷毙了的算法:日志结构存储](https://juejin.cn/post/6898766259584761864)|校对|3| + +## 译者:[chzh9311](https://github.com/chzh9311) 历史贡献积分:26 当前积分:26 二零二一:23 + +|文章|类型|积分| +|------|-------|-------| +|[代码可视化 - 使用图技术为 Python 项目绘制结构图](https://juejin.cn/post/6935232492299354120)|校对|3| +|[数据科学中的 9 种距离度量](https://juejin.cn/post/6935265008045686815)|翻译|9| +|[上手 Python 数据类前需要知道的 6 件事](https://juejin.cn/post/6926815217859559438)|校对|3| +|[为什么我的数据会漂移?](https://juejin.cn/post/6923824334188314638)|翻译|6| +|[理解 LSM 树:一种适用于频繁写入的数据库的结构](https://juejin.cn/post/6918940339676020743)|校对|2| +|[酷毙了的算法:日志结构存储](https://juejin.cn/post/6898766259584761864)|校对|3| + +## 译者:[hncboy](https://github.com/hncboy) 历史贡献积分:4.5 当前积分:4.5 + +|文章|类型|积分| +|------|-------|-------| +|[在几秒钟内为你的开发环境创建一个私有 PostgreSQL 数据库](https://juejin.cn/post/6899674625325105159)|校对|4.5| + +## 译者:[keepmovingljzy](https://github.com/keepmovingljzy) 历史贡献积分:24 当前积分:24 二零二一:20 + +|文章|类型|积分| +|------|-------|-------| +|[使用 Android 11 进行机器学习:新功能](https://juejin.cn/post/6933208209259757581)|校对|3| +|[构建像 `Messenger` 短信软件那样的 ImageView](https://juejin.cn/post/6933957885642670093)|校对|3| +|[我拒绝了 MIT 的 Offer,依然是一个高价值的开发者](https://juejin.cn/post/6924489699641786375)|翻译|7| +|1 月推荐安卓文章 1 篇、其他文章 1 篇|奖励|2| +|[Flutter 可能是下一个大事件,但 Kotlin Multiplatform 一直都是大事件](https://juejin.cn/post/6916418157641105421)|翻译|5| +|[SwiftUI 黑暗模式——最简单的方法](https://juejin.cn/post/6905925634552233998)|校对|1| +|[探索 Android 中的 ConstraintLayout 2.0](https://juejin.cn/post/6906770827228741646)|翻译|3| + +## 译者:[happySteveQi](https://github.com/happySteveQi) 历史贡献积分:1.5 当前积分:1.5 + +|文章|类型|积分| +|------|-------|-------| +|[探索 Android 中的 ConstraintLayout 2.0](https://juejin.cn/post/6906770827228741646)|校对|1.5| + +## 译者:[stuchilde](https://github.com/stuchilde) 历史贡献积分:15 当前积分:15 二零二一:13 + +|文章|类型|积分| +|------|-------|-------| +|[每个人都可以理解的授权访问和身份认证](https://juejin.cn/post/6935230984619032589)|校对|5| +|[如何利用隐语义模型在图数据库中构建推荐系统](https://juejin.cn/post/6925019556108828685)|翻译|8| +|[爱 GraphQL 胜过 REST](https://juejin.cn/post/6914306976294338567)|校对|2| + +## 译者:[Yuxiao-Shi](https://github.com/Yuxiao-Shi) 历史贡献积分:4 当前积分:4 + +|文章|类型|积分| +|------|-------|-------| +|[为什么要让你的代码尽可能简单](https://juejin.cn/post/6914669681500487687)|校对|4| + +## 译者:[flashhu](https://github.com/flashhu) 历史贡献积分:16.5 当前积分:16.5 二零二一:12.5 + +|文章|类型|积分| +|------|-------|-------| +|1 月推荐前端文章 1 篇|奖励|1| +|[揭开图着色算法的神秘面纱](https://juejin.cn/post/6924668410416791566)|校对|2| +|[你应该知道的 3 个罕见的 Bash 技巧](https://juejin.cn/post/6923190362706018318)|校对|2| +|[Node.js 缓冲区的完整指南](https://juejin.cn/post/6917192648424390669)|校对|1| +|[不同类型的浏览器存储](https://juejin.cn/post/6915263201882046472)|翻译|5| +|[如何使用 Node.js 执行多线程](https://juejin.cn/post/6915255619926622222)|校对|1.5| +|[为什么要让你的代码尽可能简单](https://juejin.cn/post/6914669681500487687)|校对|4| + +## 译者:[kaikanwu](https://github.com/kaikanwu) 历史贡献积分:1 当前积分:1 + +|文章|类型|积分| +|------|-------|-------| +|[迪米特法则](https://juejin.cn/post/6890050952049950733)|校对|1| + +## 译者:[Franz-Wang](https://github.com/Franz-Wang) 历史贡献积分:7 当前积分:7 + +|文章|类型|积分| +|------|-------|-------| +|[你不可错过的 10 个 Xcode 技巧和快捷键](https://juejin.cn/post/6913888065937211399)|翻译|5| +|[SwiftUI 中的 PageTabViewStyle](https://juejin.cn/post/6906289114300039182)|翻译|2| + +## 译者:[Usualminds](https://github.com/Usualminds) 历史贡献积分:50.5 当前积分:50.5 二零二一:38.5 + +|文章|类型|积分| +|------|-------|-------| +|3 月推荐前端文章 1 篇|奖励|1| +|[CSS3 会替代 SCSS 吗?](https://juejin.cn/post/6934326962450071559)|校对|2| +|[3 个最棒的最值得你去在产品中使用的 CSS Grid 功能](https://juejin.cn/post/6931372123441233927)|校对|2| +|[基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)|翻译|7| +|[如何让 JavaScript 中的循环慢下来](https://juejin.cn/post/6924512805135581197)|校对|1| +|[掌握这 5 个 TypeScript 高级技巧,成为更好的开发者](https://juejin.cn/post/6924293152907984909)|翻译|6| +|[为什么你应该使用 Picture 标签而不是 Img 标签](https://juejin.cn/post/6923840549170446343)|校对|2| +|[虚拟 DOM 来源于文档片段吗?](https://juejin.cn/post/6902211857244028941)|校对|2| +|[如何成为谷歌开发专家(GDE)— 实用指南](https://juejin.cn/post/6918640631317266439)|翻译|4| +|[Web 应用缓存的基础知识](https://juejin.cn/post/6913898149740281870)|校对|2| +|[使用 CSS 提升页面渲染速度](https://juejin.cn/post/6911689122759475208)|翻译|6.5| +|[在 Node.js 中避免内存泄漏:性能最佳实践](https://juejin.cn/post/6911488842079928327)|校对|3| +|[WebTransport 会在不久的将来取代 WebRTC 吗?](https://juejin.cn/post/6910186017190313991)|翻译|4| +|[单体应用与微前端开发对比](https://juejin.cn/post/6906021856210321422)|校对|3| +|[增量 DOM 与虚拟 DOM 的对比使用](https://juejin.cn/post/6903765877296988174)|校对|2| +|[理解 JavaScript 中模块的导入和导出](https://juejin.cn/post/6904980094998020109)|校对|3| + +## 译者:[zhuzilin](https://github.com/zhuzilin) 历史贡献积分:48.5 当前积分:48.5 二零二一:41.5 + +|文章|类型|积分| +|------|-------|-------| +|[我后悔没有在自己成为 React 开发者之前做的 6 件事情](https://juejin.cn/post/6934144158332354567)|校对|1| +|[你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)|校对|5| +|[SwiftUI 2 应用生命周期的终极指导](https://juejin.cn/post/6924119708832628749)|翻译|5| +|1 月推荐 iOS 文章 1 篇|奖励|1| +|[UIKit 和 SwiftUI:我该选择哪一个运用在实际产品开发中?](https://juejin.cn/post/6923197105422991367)|校对|4| +|1 月推荐 iOS 文章 1 篇|奖励|1| +|[我们应该在什么时候使用 @State、@Binding、@ObservedObject、@EnvironmentObject 和 @Environment?](https://juejin.cn/post/6920881116043968520)|校对|2.5| +|[iOS 中的 widget](https://juejin.cn/post/6920017496497979399)|翻译|7| +|[DeepSpeed:所有人都能用的超大规模模型训练工具](https://juejin.cn/post/6916500899577724942)|翻译|12| +|[Flutter 可能是下一个大事件,但 Kotlin Multiplatform 一直都是大事件](https://juejin.cn/post/6916418157641105421)|校对|3| +|12 月推荐 AI 文章 1 篇|奖励|1| +|[WebTransport 会在不久的将来取代 WebRTC 吗?](https://juejin.cn/post/6910186017190313991)|校对|2| +|[SwiftUI 黑暗模式——最简单的方法](https://juejin.cn/post/6905925634552233998)|翻译|2| +|[黑暗主题 — 现代 UI 设计](https://juejin.cn/post/6901856999235911688)|校对|2| + +## 译者:[wynn-w](https://github.com/wynn-w) 历史贡献积分:1.5 当前积分:1.5 + +|文章|类型|积分| +|------|-------|-------| +|[四个优秀 Vue.js 静态站点生成器](https://juejin.cn/post/6903309715309068295)|校对|1.5| + +## 译者:[PassionPenguin](https://github.com/PassionPenguin) 历史贡献积分:185 当前积分:185 二零二一:185 + +|文章|类型|积分| +|------|-------|-------| +|3 月推荐前端文章 1 篇|奖励|1| +|[为什么我对 TypeScript 黑转粉?一个 JS 开发者的深情自白](https://juejin.cn/post/6935629277870161957)|翻译|5| +|[TypeScript 4.2 正式发布:优化了类型和开发者体验](https://juejin.cn/post/6935255387893399560)|翻译|3| +|[在 React 中使用 Immer 管理不可变状态](https://juejin.cn/post/6935790852476239886)|校对|1.5| +|[自适应 CSS 栅格:自由布局的最终版本](https://juejin.cn/post/6935090806210428959)|翻译|2.5| +|[Deno 将停用 TypeScript 的五个原因](https://juejin.cn/post/6934140963262562312)|校对|2| +|[关于 Node.js 中的异步迭代器](https://juejin.cn/post/6934596464639213576)|校对|1| +|[Bash 中的 if else 语句](https://juejin.cn/post/6934324540692496392)|翻译|5| +|[使用 Android 11 进行机器学习:新功能](https://juejin.cn/post/6933208209259757581)|翻译|7| +|[CSS3 会替代 SCSS 吗?](https://juejin.cn/post/6934326962450071559)|翻译|4| +|[代码可视化 - 使用图技术为 Python 项目绘制结构图](https://juejin.cn/post/6935232492299354120)|校对|3| +|[我后悔没有在自己成为 React 开发者之前做的 6 件事情](https://juejin.cn/post/6934144158332354567)|翻译|3| +|[数据科学中的 9 种距离度量](https://juejin.cn/post/6935265008045686815)|校对|4| +|[每个人都可以理解的授权访问和身份认证](https://juejin.cn/post/6935230984619032589)|校对|5| +|[构建像 `Messenger` 短信软件那样的 ImageView](https://juejin.cn/post/6933957885642670093)|翻译|6.5| +|[你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)|翻译|10| +|2 月推荐前端文章 1 篇|奖励|1| +|2 月推荐 Android 文章 1 篇|奖励|1| +|[JavaScript 中哪一种循环更快呢?](https://juejin.cn/post/6930973929452339213)|翻译|3| +|[3 个最棒的最值得你去在产品中使用的 CSS Grid 功能](https://juejin.cn/post/6931372123441233927)|翻译|5| +|[恭喜 Safari 荣获「第二个 Internet Explorer」的美誉](https://juejin.cn/post/6929754875001569294)|翻译|4| +|[基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)|校对|3| +|[如何基于已有的 REST API 实现 GraphQL API](https://juejin.cn/post/6931145990599049223)|校对|2| +|[你应该编译你的 JavaScript 代码吗?](https://juejin.cn/post/6926927963636105223)|翻译|5| +|[如何在浏览器上使用 NoSQL 数据库 IndexedDB](https://juejin.cn/post/6930883284456964109)|校对|2| +|[简述 HTTP 请求与跨域资源共享 CORS](https://juejin.cn/post/6927191095470194695)|校对|2| +|[2021 年 JavaScript 测试框架回顾](https://juejin.cn/post/6927585452253790216)|翻译|2.5| +|[为什么 React Hooks 是错误的抽象](https://juejin.cn/post/6930529765048713229)|校对|3| +|1 月推荐 Flutter 文章 1 篇|奖励|1| +|1 月推荐 Kotlin 文章 1 篇|奖励|1| +|[SwiftUI 2 应用生命周期的终极指导](https://juejin.cn/post/6924119708832628749)|校对|2| +|[揭开图着色算法的神秘面纱](https://juejin.cn/post/6924668410416791566)|校对|2| +|[如何让 JavaScript 中的循环慢下来](https://juejin.cn/post/6924512805135581197)|翻译|2| +|[我拒绝了 MIT 的 Offer,依然是一个高价值的开发者](https://juejin.cn/post/6924489699641786375)|校对|3| +|[掌握这 5 个 TypeScript 高级技巧,成为更好的开发者](https://juejin.cn/post/6924293152907984909)|校对|3| +|[Android 中的意料之外的应用崩溃以及解决它们的方法](https://juejin.cn/post/6925336143953133581)|翻译|5| +|[在 TypeScript 中引入 JSON 模块](https://juejin.cn/post/6923188659957006343)|翻译|1| +|[为什么你应该使用 Picture 标签而不是 Img 标签](https://juejin.cn/post/6923840549170446343)|校对|2| +|[使用 Flutter 的 Container 控件构建优美的用户界面](https://juejin.cn/post/6923854569596256263)|翻译|1.5| +|[你应该知道的 3 个罕见的 Bash 技巧](https://juejin.cn/post/6923190362706018318)|翻译|3.5| +|[2021 年 Web 应用开发常用的五个图标库](https://juejin.cn/post/6922416136294252557)|校对|3| +|[Node.js 缓冲区的完整指南](https://juejin.cn/post/6917192648424390669)|翻译|3| +|[Python 中的列表和元组](https://juejin.cn/post/6923195053754023949)|翻译|4| +|[UIKit 和 SwiftUI:我该选择哪一个运用在实际产品开发中?](https://juejin.cn/post/6923197105422991367)|翻译|9| +|[10 个你应该现在启用的绝佳的 Chrome Flags](https://juejin.cn/post/6923198038894706701)|翻译|2| +|1 月推荐安卓(Kotlin)文章 1 篇|奖励|1| +|1 月推荐 Flutter 文章 2 篇|奖励|2| +|1 月推荐设计文章 3 篇|奖励|3| +|[Javascript Memoization 入门指南](https://juejin.cn/post/6920460950424256526)|校对|2| +|[深入了解 JavaScript 模块](https://juejin.cn/post/6920153306392166413)|校对|3| +|[Flutter 中内置的显式动画](https://juejin.cn/post/6918698096109191175)|翻译|5.5| +|[Flutter 中的交织动画](https://juejin.cn/post/6918693294083932173)|翻译|3| +|[解构标志性的 Apple Watch Bubble UI](https://juejin.cn/post/6919630087843217416)|校对|3| +|[不同类型的浏览器存储](https://juejin.cn/post/6915263201882046472)|校对|2| +|[我们应该在什么时候使用 @State、@Binding、@ObservedObject、@EnvironmentObject 和 @Environment?](https://juejin.cn/post/6920881116043968520)|校对|2.5| +|[如何成为谷歌开发专家(GDE)— 实用指南](https://juejin.cn/post/6918640631317266439)|校对|2| +|[Node.js 安全编程的最佳实践](https://juejin.cn/post/6918757099782537224)|校对|4| +|[iOS 中的 widget](https://juejin.cn/post/6920017496497979399)|校对|3| +|[GitHub Package Registry 是否值得尝试](https://juejin.cn/post/6915255280959750152)|校对|2| +|[Flutter 可能是下一个大事件,但 Kotlin Multiplatform 一直都是大事件](https://juejin.cn/post/6916418157641105421)|校对|2| + +## 译者:[Ashira97](https://github.com/Ashira97) 历史贡献积分:37 当前积分:37 二零二一:37 + +|文章|类型|积分| +|------|-------|-------| +|[代码可视化 - 使用图技术为 Python 项目绘制结构图](https://juejin.cn/post/6935232492299354120)|翻译|8| +|[每个人都可以理解的授权访问和身份认证](https://juejin.cn/post/6935230984619032589)|翻译|11| +|[你应该编译你的 JavaScript 代码吗?](https://juejin.cn/post/6926927963636105223)|校对|2| +|[2021 年 JavaScript 测试框架回顾](https://juejin.cn/post/6927585452253790216)|校对|1| +|[Javascript Memoization 入门指南](https://juejin.cn/post/6920460950424256526)|校对|2| +|[深入了解 JavaScript 模块](https://juejin.cn/post/6920153306392166413)|校对|3| +|[减少 Web 应用程序中 CORS 预检时间的 4 种方法](https://juejin.cn/post/6914561805465419784)|校对|2| +|[Node.js 安全编程的最佳实践](https://juejin.cn/post/6918757099782537224)|翻译|8| + +## 译者:[LoneyIsError](https://github.com/LoneyIsError) 历史贡献积分:5 当前积分:5 二零二一:5 + +|文章|类型|积分| +|------|-------|-------| +|[我们应该在什么时候使用 @State、@Binding、@ObservedObject、@EnvironmentObject 和 @Environment?](https://juejin.cn/post/6920881116043968520)|翻译|5| + +## 译者:[k8scat](https://github.com/k8scat) 历史贡献积分:4 当前积分:4 二零二一:4 + +|文章|类型|积分| +|------|-------|-------| +|[如何基于已有的 REST API 实现 GraphQL API](https://juejin.cn/post/6931145990599049223)|校对|2| +|[不同类型的浏览器存储](https://juejin.cn/post/6915263201882046472)|校对|2| + +## 译者:[HayleyLL](https://github.com/HayleyLL) 历史贡献积分:1 当前积分:1 二零二一:1 + +|文章|类型|积分| +|------|-------|-------| +|[对象展开运算符在 JavaScript 中的 5 大应用](https://juejin.cn/post/6895525536039174151)|校对|1| + +## 译者:[HumanBeingXenon](https://github.com/HumanBeingXenon) 历史贡献积分:14 当前积分:14 二零二一:14 + +|文章|类型|积分| +|------|-------|-------| +|[使用 Android 11 进行机器学习:新功能](https://juejin.cn/post/6933208209259757581)|校对|3| +|[构建像 `Messenger` 短信软件那样的 ImageView](https://juejin.cn/post/6933957885642670093)|校对|3| +|[你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)|校对|5| +|[JavaScript 中哪一种循环更快呢?](https://juejin.cn/post/6930973929452339213)|校对|1| +|[Android 中的意料之外的应用崩溃以及解决它们的方法](https://juejin.cn/post/6925336143953133581)|校对|2| + +## 译者:[fltenwall](https://github.com/fltenwall) 历史贡献积分:6 当前积分:6 二零二一:6 + +|文章|类型|积分| +|------|-------|-------| +|[为什么 React Hooks 是错误的抽象](https://juejin.cn/post/6930529765048713229)|翻译|6| + +## 译者:[zqp1226358](https://github.com/zqp1226358) 历史贡献积分:2 当前积分:2 二零二一:2 + +|文章|类型|积分| +|------|-------|-------| +|[3 个最棒的最值得你去在产品中使用的 CSS Grid 功能](https://juejin.cn/post/6931372123441233927)|校对|2| + +## 译者:[icicle198514](https://github.com/icicle198514) 历史贡献积分:5 当前积分:5 二零二一:5 + +|文章|类型|积分| +|------|-------|-------| +|[函数式编程 —— 使用 Python、JavaScript 和 Java 描述](https://juejin.cn/post/6930638275241574407)|校对|5| + +## 译者:[flying-yogurt](https://github.com/flying-yogurt) 历史贡献积分:2 当前积分:2 二零二一:2 + +|文章|类型|积分| +|------|-------|-------| +|[Bash 中的 if else 语句](https://juejin.cn/post/6934324540692496392)|校对|2| + +## 译者:[felixliao](https://github.com/felixliao) 历史贡献积分:1.5 当前积分:1.5 二零二一:1.5 + +|文章|类型|积分| +|------|-------|-------| +|[在 React 中使用 Immer 管理不可变状态](https://juejin.cn/post/6935790852476239886)|校对|1.5| + +## 译者:[itcodes](https://github.com/itcodes) 历史贡献积分:2 当前积分:2 二零二一:2 + +|文章|类型|积分| +|------|-------|-------| +|[为什么我对 TypeScript 黑转粉?一个 JS 开发者的深情自白](https://juejin.cn/post/6935629277870161957)|校对|2| + +## 译者:[husiyu](https://github.com/husiyu) 历史贡献积分:1.5 当前积分:1.5 二零二一:1.5 + +|文章|类型|积分| +|------|-------|-------| +|[为什么我对 TypeScript 黑转粉?一个 JS 开发者的深情自白](https://juejin.cn/post/6935629277870161957)|校对|1.5| diff --git a/ios.md b/ios.md index 80355849b12..663b4eda703 100644 --- a/ios.md +++ b/ios.md @@ -1,188 +1,210 @@ -* [Web 端的 SwiftUI:SwiftWebUI](https://juejin.im/post/5d35e0ac5188257dc103e364) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Xcode 和 LLDB 高级调试教程:第 3 部分](https://juejin.im/post/5d383c7d5188257dab043145) ([kirinzer](https://github.com/kirinzer) 翻译) -* [贫困线下的软件 — 开源项目的可持续发展问题探讨](https://juejin.im/post/5d215da2e51d4556be5b3acb) ([Charlo-O](https://github.com/Charlo-O) 翻译) -* [Git:透过命令学概念 —— 第二部分](https://juejin.im/post/5d2da05ae51d45106b15ffca) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [使用 Swift 5 构建一个 iOS 移动端群聊应用程序](https://juejin.im/post/5d2c6e846fb9a07ebb0564ae) ([LucaslEliane](https://github.com/LucaslEliane) 翻译) -* [Xcode 和 LLDB 高级调试教程:第 2 部分](https://juejin.im/post/5d2321eee51d454f71439d64) ([kirinzer](https://github.com/kirinzer) 翻译) -* [Xcode 和 LLDB 高级调试教程:第 1 部分](https://juejin.im/post/5d0b246be51d4555e372a60b) ([kirinzer](https://github.com/kirinzer) 翻译) -* [iOS 中的 File Provider 拓展](https://juejin.im/post/5cff5b0af265da1b8b2b54c7) ([iWeslie](https://github.com/iWeslie) 翻译) -* [用于 iOS 的 ML Kit 教程:识别图像中的文字](https://juejin.im/post/5cfe23af6fb9a07ee742d401) ([portandbridge](https://github.com/portandbridge) 翻译) -* [Swift 5 中的枚举冻结](https://juejin.im/post/5cea9597e51d45775f5169f2) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 里的强制 @inline 注解](https://juejin.im/post/5cd67d64518825686244635a) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 代码格式化](https://juejin.im/post/5ccea148f265da038e54bbf2) ([iWeslie](https://github.com/iWeslie) 翻译) -* [为你的 iOS App 构建分离测试](https://juejin.im/post/5ccd6b55f265da037d4fbc41) ([iWeslie](https://github.com/iWeslie) 翻译) -* [iOS 里的 MVVM 和 RxSwift](https://juejin.im/post/5cb833abf265da03ac0d04d1) ([iWeslie](https://github.com/iWeslie) 翻译) -* [实用的 MVVM 和 RxSwift](https://juejin.im/post/5cb80f9c6fb9a06876103744) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 模块中的 API 污染](https://juejin.im/post/5cb80f1f6fb9a0686a224a18) ([iWeslie](https://github.com/iWeslie) 翻译) -* [懒加载变量在 iOS Swift](https://juejin.im/post/5ca775b26fb9a05e3527db37) ([kirinzer](https://github.com/kirinzer) 翻译) -* [Swift 5.0 新特性](https://juejin.im/post/5ca41d766fb9a05e6d61ad2b) ([iWeslie](https://github.com/iWeslie) 翻译) -* [在 swift 中使用 errors 作为控制流](https://juejin.im/post/5c90c0d9f265da612d6335cb) ([swants](https://github.com/swants) 翻译) -* [iOS:如何构建具有多种 Cell 类型的表视图](https://juejin.im/post/5c89a917e51d457efe07f4f9) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [如何在 Swift 5 中使用 Result](https://juejin.im/post/5c9586eee51d4536e85c3d60) ([Bruce-pac](https://github.com/Bruce-pac) 翻译) -* [iOS 响应者链 UIResponder,UIEvent,UIControl 的使用](https://juejin.im/post/5c9f652ae51d4519eb1ff426) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 5 强制独占性原则](https://juejin.im/post/5c778b5e6fb9a049c64487e0) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [React Native 中那些令我收获颇丰的痛点](https://juejin.im/post/5c74d6a16fb9a049f06ae907) ([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) -* [React Native 与 iOS 和 Android 通信](https://juejin.im/post/5c6ca781f265da2da8356c81) ([MeandNi](https://github.com/MeandNi) 翻译) -* [Swift:通过示例避免内存泄漏](https://juejin.im/post/5c6a0abaf265da2dc675a9b2) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [用这些 iOS 技巧让你的 APP 性能更佳](https://juejin.im/post/5c6a0b6ef265da2de660f83f) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [iOS 设计模式进阶](https://juejin.im/post/5c51b959f265da6115112e3e) ([iWeslie](https://github.com/iWeslie) 翻译) -* [iOS 中赏心悦目的动画](https://juejin.im/post/5c4f05bce51d4552411b1e13) ([iWeslie](https://github.com/iWeslie) 翻译) -* [在 iOS 上使用 Carthage 建立依赖](https://juejin.im/post/5c4f04ef51882525eb3663be) ([iWeslie](https://github.com/iWeslie) 翻译) -* [状态恢复入门教程](https://juejin.im/post/5c330d0ce51d45518e147fd2) ([nanjingboy](https://github.com/nanjingboy) 翻译) -* [值类型导向编程](https://juejin.im/post/5c2c3f8d518825480635db8b) ([nanjingboy](https://github.com/nanjingboy) 翻译) -* [使用 Swift 的 iOS 设计模式(第二部分)](https://juejin.im/post/5c1786576fb9a049f06a2c4a) ([iWeslie](https://github.com/iWeslie) 翻译) -* [使用 Swift 的 iOS 设计模式(第一部分)](https://juejin.im/post/5c05d4ee5188250ab14e62d6) ([iWeslie](https://github.com/iWeslie) 翻译) -* [使用 Kotlin 将你的 iOS 应用程序转换为 Android](https://juejin.im/post/5c03f64ce51d454af013d076) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 中的动态特性](https://juejin.im/post/5bfd087be51d457a013940e8) ([iWeslie](https://github.com/iWeslie) 翻译) -* [介绍适用于 iOS 的 AloeStackView](https://juejin.im/post/5bf22a05f265da61783106de) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [iOS 12 占有率超过 50%,超过了 iOS 11](https://juejin.im/post/5bf64ad851882579117f74ae) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [从现有的代码库创建 Swift 包管理器](https://juejin.im/post/5bec2b735188253b6e5c132a) ([iWeslie](https://github.com/iWeslie) 翻译) -* [Swift 中的惰性序列及其原理](https://juejin.im/post/5bc13f036fb9a05d28736f79) ([RickeyBoy](https://github.com/RickeyBoy) 翻译) -* [Swift 中强大的模式匹配](https://juejin.im/post/5bbc096ce51d450e9162fd9d) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [在 iOS 中使用 UITests 测试 Facebook 登录功能](https://juejin.im/post/5b90e3ae6fb9a05d00458ad8) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [构建流畅的交互界面](https://juejin.im/post/5b7e2b34e51d4538843612cc) ([rydensun](https://github.com/rydensun) 翻译) -* [2018 年 iOS 开发找工作完全指南](https://juejin.im/post/5b7eca206fb9a019ff713277) ([melon8](https://github.com/melon8) 翻译) -* [你 Ladar 中该珍藏的:iOS 布局语言](https://juejin.im/post/5b84fe97f265da437c43422f) ([pmwangyang](https://github.com/pmwangyang) 翻译) -* [重写 loadView() 方法使 Swift 视图代码更加简洁](https://juejin.im/post/5b68fe5b6fb9a04fd16039c0) ([RickeyBoy](https://github.com/RickeyBoy) 翻译) -* [React Native 中使用转场动画!](https://juejin.im/post/5b69467e5188251b3c3b4e4e) ([talisk](https://github.com/talisk) 翻译) -* [一份在你的 iPhone 上平衡实用和美观的指南](https://juejin.im/post/5b4c0d0ce51d4519503b1e67) ([94haox](https://github.com/94haox) 翻译) -* [Tab Bar 就是新的汉堡菜单](https://juejin.im/post/5b61684fe51d451986517e31) ([rydensun](https://github.com/rydensun) 翻译) -* [Airbnb 中的 React Native 上下的赌注(五 — 完):Airbnb 移动端路在何方?](https://juejin.im/post/5b46f92de51d45198e721cd7) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [Airbnb 中的 React Native 上下的赌注(四):React Native 退役](https://juejin.im/post/5b447b1e6fb9a04fd3437dad) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [Airbnb 中的 React Native 上下的赌注(三):建立一个跨平台的移动端团队](https://juejin.im/post/5b446177f265da0f7c4faec8) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [Airbnb 在 React Native 上下的赌注(二):技术细节](https://juejin.im/post/5b3b40a26fb9a04fab44e797) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [Airbnb 在 React Native 上下的赌注(一):概述](https://juejin.im/post/5b2c924ff265da59a401f050) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [苹果公司如何修复 3D Touch](https://juejin.im/post/5b35e5886fb9a00e3642724f) ([Wangalan30](https://github.com/Wangalan30) 翻译) -* [不越狱探索 App](https://juejin.im/post/5b0e7eec518825155a048dc4) ([melon8](https://github.com/melon8) 翻译) -* [Swift 中的 Playground 驱动开发](https://juejin.im/post/5b07665c6fb9a07ac5608d8a) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [Swift 中的内存泄漏](https://juejin.im/post/5b07a1c251882538914a5d3e) ([RickeyBoy](https://github.com/RickeyBoy) 翻译) -* [使用 iPhone X 与 Maya 实现快速面部捕捉](https://juejin.im/post/5af40eba6fb9a07ac76ed7d1) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [轻松管理 Swift 项目中的不同环境](https://juejin.im/post/5af264a4f265da0b967233ff) ([melon8](https://github.com/melon8) 翻译) -* [构建、测试、分发!运用 Fastlane 与 Jenkins,完整的 iOS 持交付指南。](https://juejin.im/post/5af430f0f265da0b8262d1ea) ([talisk](https://github.com/talisk) 翻译) -* [Story 中 Type Mode 在 iOS 和 Android 上的实现](https://juejin.im/post/5ae7e1596fb9a07ab9794332) ([melon8](https://github.com/melon8) 翻译) -* [Swift 写网络层:用面向协议的方式](https://juejin.im/post/5af432385188256737066c04) ([talisk](https://github.com/talisk) 翻译) -* [使用 Swift 实现原型动画](https://juejin.im/post/5ae28a9b6fb9a07aaa10fa1e) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [不使用 fastlane 实现持续交付的 5 种选项](https://juejin.im/post/5acf47cb6fb9a028c523944c) ([melon8](https://github.com/melon8) 翻译) -* [没有 Interface Builder 的生活](https://juejin.im/post/5ab88ac0518825558a069c91) ([rydensun](https://github.com/rydensun) 翻译) -* [让我们来简化 UserDefaults 的使用](https://juejin.im/post/5abde324f265da23826e1723) ([talisk](https://github.com/talisk) 翻译) -* [避免 Swift 单元测试中的强制解析](https://juejin.im/post/5a9ce4ac6fb9a028b547602e) ([RickeyBoy](https://github.com/RickeyBoy) 翻译) -* [iOS App 上一种灵活的路由方式](https://juejin.im/post/5aafc278f265da23805973e3) ([YinTokey](https://github.com/YinTokey) 翻译) -* [通过 Quick 和 Nimble 在 Swift 中进行测试驱动开发](https://juejin.im/post/5a93635d5188257a7924c5d5) ([94haox](https://github.com/94haox) 翻译) -* [为什么你的 APP 在 Sketch 上看起来更好:探索 Sketch 和 iOS 的渲染差异](https://juejin.im/post/5a9572575188257a61326630) ([rydensun](https://github.com/rydensun) 翻译) -* [在 Swift playground 中编写单元测试](https://juejin.im/post/5a8e66276fb9a0633c661f3f) ([lsvih](https://github.com/lsvih) 翻译) -* [swift 网络单元测试完全手册](https://juejin.im/post/5a784e87f265da4e8a31ca7a) ([swants](https://github.com/swants) 翻译) -* [用 LLDB 调试 Swift 代码](https://juejin.im/post/5a7948d35188257a7349a882) ([VernonVan](https://github.com/VernonVan) 翻译) -* [不再对 MVVM 感到绝望](https://juejin.im/post/5a782d0d5188257a856f1dd7) ([JayZhaoBoy](https://github.com/JayZhaoBoy) 翻译) -* [断点:像专家一样调试代码](https://juejin.im/post/5a72be42518825733b0f374e) ([pthtc](https://github.com/pthtc) 翻译) -* [17 个 Xcode 小技巧,每个 iOS 开发者都该知道](https://juejin.im/post/5a7198ac51882573505189c8) ([pthtc](https://github.com/pthtc) 翻译) -* [Swift 中的值类型与引用类型使用指北](https://juejin.im/post/5a5c2c046fb9a01cbe654b48) ([DeepMissea](https://github.com/DeepMissea) 翻译) -* [Xcode 环境配置最佳实践](https://juejin.im/post/5a4f120cf265da3e3d48f1f6) ([swants](https://github.com/swants) 翻译) -* [基于 Metal 的 ARKit 使用指南(上)](https://juejin.im/post/5a225ffcf265da432153daa4) ([RichardLeeH](https://github.com/RichardLeeH) 翻译) -* [处理 iOS 中复杂的 Table Views 并保持优雅](https://juejin.im/post/5a078ec3f265da431955c0d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangqippp](https://github.com/zhangqippp) 翻译) -* [Swift 上的高性能数组](https://juejin.im/post/59e84129f265da43128005ed?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jingzhilehuakai](https://github.com/jingzhilehuakai) 翻译) -* [通过 Metal 来使用 ARKit (下)](https://juejin.im/post/59bb2a99f265da0650750e56?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([swants](https://github.com/swants) 翻译) -* [如何在 iOS 上实现类似 Airbnb 中的可展开式菜单](https://juejin.im/post/59acdf2b6fb9a024763806cf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([RichardLeeH](https://github.com/RichardLeeH) 翻译) -* [结构体指针](https://juejin.im/post/59a60cc1f265da249a201ae9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([swants](https://github.com/swants) 翻译) -* [MVVM, Coordinators 和 RxSwift 的抽丝剥茧](https://juejin.im/post/59acf7dcf265da24722fe6a1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jingzhilehuakai](https://github.com/jingzhilehuakai) 翻译) -* [探究 Swift 中的 Futures & Promises](https://juejin.im/post/59afcf5d51882524434163dd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([atuooo](https://github.com/atuooo) 翻译) -* [iOS 响应式编程:Swift 中的轻量级状态容器](https://juejin.im/post/599652ee6fb9a024903a8d59?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([atuooo](https://github.com/atuooo) 翻译) -* [Swift 中的通用数据源](https://juejin.im/post/5990fd7b51882548bc7cabd8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([swants](https://github.com/swants) 翻译) -* [模块化 Swift 中的状态](https://juejin.im/post/597962875188253dda0f05a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea) 翻译) -* [Xcode 中的用户断点](https://juejin.im/post/597934335188253dfb7b0db7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([atuooo](https://github.com/atuooo) 翻译) -* [语句,消息和归约器](https://juejin.im/post/596f17366fb9a06bc17c53db?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangqippp](https://github.com/zhangqippp) 翻译) -* [开发者眼中 iOS 11 都更新了什么?](https://juejin.im/post/595f1f2c5188250d8a605d69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([swants](https://github.com/swants) 翻译) -* [把 UUID 或者 GUID 作为主键?你得小心啦!](https://juejin.im/post/59561e5b6fb9a06bbf6fdf16?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zaraguo](https://github.com/zaraguo) 翻译) -* [iOS 11:机器学习人人有份](https://juejin.im/post/59533049f265da6c3a54b739?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([changkun](https://github.com/changkun) 翻译) -* [Swift 中关于并发的一切:第一部分 — 当前](https://juejin.im/post/5954571af265da6c4c4fc3f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea) 翻译) -* [iOS 11:UIKit 中值得注意的新能力](https://juejin.im/post/5944adfffe88c2006a6f6f3a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangqippp](https://github.com/zhangqippp) 翻译) -* [深度学习在 iOS 上的实践 —— 通过 YOLO 在 iOS 上实现实时物体检测](https://juejin.im/post/59433498da2f600067604218?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny1451](https://github.com/Danny1451) 翻译) -* [消息同步 —— 在 Airbnb 我们是怎样扩展移动消息的](https://juejin.im/post/593a7647128fe1006acafaf9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay) 翻译) -* [对元素持有弱引用的 Swift 数组](https://juejin.im/post/5927a34c0ce46300575a81e1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([zhangqippp](https://github.com/zhangqippp) 翻译) -* [在 Swift 中使用闭包实现懒加载](https://juejin.im/post/590a9eeab123db00549776ee/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih)) 翻译) -* [掌握 Swift 的字符串细节](https://juejin.im/post/58f822ff5c497d0058e0e427/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay(洪朔)](https://github.com/Tuccuay)) 翻译) -* [MVVM-C 与 Swift](https://juejin.im/post/58ef16b8da2f60005d180666/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译) -* [Swift 闭包和代理中的保留周期](https://juejin.im/post/58e4ac5d44d904006d2a9a19/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([oOatuo](http://atuo.xyz/)) 翻译) -* [一名 iOS 开发者的 React Native 开发经历](https://juejin.im/post/58df4c3fa0bb9f0069e2f2bd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih)) 翻译) -* [优化 Swift 的编译时间](https://juejin.im/post/58df1d75570c35005796966b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译) -* [看!Swift 里竟然有红绿灯 🚦!](https://juejin.im/post/58ddbc612f301e0062fed742/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译) -* [原生 iOS(Swift) 和 React-Native 的性能比较](https://juejin.im/post/58ca6d5f44d90400682a215c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译) -* [如果只有一个月入门 iOS:我该如何学习呢?](https://juejin.im/post/58c9f436a22b9d0064187e39/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015(Gocy)](https://github.com/Gocy015) 翻译) -* [在 Xcode 项目中使用 swift package fetch](https://juejin.im/post/58c7a4cb1b69e6006bec354c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015(Gocy)](https://github.com/Gocy015)翻译) -* [Bob,函数式编程是什么鬼?](https://juejin.im/post/58c24c35a22b9d00589a56d4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)翻译) -* [Swift + 关键字](https://juejin.im/post/58bf76aaa22b9d0058896bff/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)翻译) -* [重构 Swift 中单例的用法](https://gold.xitu.io/entry/58b81150570c3500598fc567/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Karthus1110](https://github.com/Karthus1110)翻译) -* [Bob,我要怎样才能成为一名 iOS 开发者](https://gold.xitu.io/entry/58b153c38fd9c50063d38068/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([thanksdanny](https://github.com/thanksdanny)翻译) -* [步入 Swift 3](https://gold.xitu.io/entry/58aa701fda2f60006fa9978f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)翻译) -* [iOS 开发中使用 Swift 进行 iBeacons 交互指南](https://gold.xitu.io/entry/58a6f4091b69e6006d275610/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lovelyCiTY](https://github.com/lovelyCiTY) 翻译) -* [[译] iOS 开发者一定要知道的 14 个知识点](https://gold.xitu.io/entry/58a5727261ff4b006c432a7f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Deepmissea](http://deepmissea.blue) 翻译) -* [iOS 应用测试](https://gold.xitu.io/entry/58a16cc161ff4b006b51d882/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([thanksdanny](https://github.com/thanksdanny) 翻译) -* [老司机手把手带你在 Swift 中应用代理(Delegate)](https://gold.xitu.io/entry/58a11b7c61ff4b006b4f7f69/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015](https://github.com/Gocy015) 翻译) -* [在 Swift 3 上对视图控件实践面向协议编程](https://gold.xitu.io/entry/589b42692f301e00699b8011/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay) 翻译) -* [让内存管理重振雄风](https://gold.xitu.io/entry/589afeb78d6d81006c78132a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea) 翻译) -* [Swift 面向协议编程入门](https://gold.xitu.io/entry/589439622f301e00693567e5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny Lau](https://github.com/Danny1451) 翻译) -* [如何在 Swift 3 中用 SpriteKit 框架编写游戏 (Part 3)](https://gold.xitu.io/entry/586d359a128fe1006661e361?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea) 翻译) -* [如何在 Swift 3 中用 SpriteKit 框架编写游戏 (Part 2)](https://gold.xitu.io/entry/5860d2e4128fe1006dfbb962?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZiXYu](https://github.com/ZiXYu) 翻译) -* [如何在 Swift 3 中用 Spirit Kit 框架编写游戏 (Part 1)](https://gold.xitu.io/entry/585b7cc18d6d810065d2905e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy015](https://github.com/Gocy015) 翻译) -* [macOS Security and Privacy Guide](https://gold.xitu.io/entry/585501e2b123db00656a6947?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09)   [MAYDAY1993](https://github.com/MAYDAY1993)   [DeadLion](https://github.com/DeadLion) 翻译) -* [Yammer iOS 版移植到 Swift3](https://gold.xitu.io/entry/5848b88ab123db006601f750?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny Lau](https://github.com/Danny1451) 翻译) -* [Swift 面向协议编程,灵丹妙药或是饮鸩止渴?](https://gold.xitu.io/entry/584781e161ff4b006bac77ba?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [如何避免应用崩溃](http://gold.xitu.io/entry/58423231a22b9d006c1959ee?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Gocy](https://github.com/Gocy) 翻译) -* [理解 iOS 应用程序的代码签名 (CODE SIGN) 机制](http://gold.xitu.io/entry/5826ef85570c3500586b241d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [给 iOS App 开发者的 39 个开源的 Swift UI 库](http://gold.xitu.io/entry/58209322570c350060b73588?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [Swift 3 语言中的全模块优化](http://gold.xitu.io/entry/5818b6f52f301e005cf0ef8e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Edison-Hsu](https://github.com/Edison-Hsu) 翻译) -* [UserNotifications Framework 入门介绍](http://gold.xitu.io/entry/5816a28f128fe10055912398?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny Lau](https://github.com/Danny1451) 翻译) -* [Swift 声明式程序设计](http://gold.xitu.io/entry/58105d1e128fe1005feca8dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [如何使用 UIFeedbackGenerator 让应用支持 iOS 10 的触觉反馈](http://gold.xitu.io/entry/5810433ac4c9710058a74100?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([owenlyn](https://github.com/owenlyn) 翻译) -* [让 iOS 10 今日控件向后兼容的几个技巧](http://gold.xitu.io/entry/580eec1b8ac247005b620267?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Edison.Hsu](https://github.com/edison-hsu) 翻译) -* [Swfit 代码的可测试性](http://gold.xitu.io/entry/58086fe52f301e005c27221f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([steinliber](https://github.com/steinliber) 翻译) -* [iOS 10 中的 NSPersistentContainer](http://gold.xitu.io/entry/580444efa34131005fe77197?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [Swift 中的面向协议编程是如何点亮我的人生的](http://gold.xitu.io/entry/58044fc5a22b9d005b4f56b2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Danny Lau](https://github.com/Danny1451) 翻译) -* [Swift 3 中的函数参数命名规范指北](http://gold.xitu.io/entry/57fa593b2e958a00558b2d17?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [迁移到 Swift 3,这些陷阱在等你](http://gold.xitu.io/entry/57f6fa03816dfa0056a4d782?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shliujing](https://github.com/shliujing) 翻译) -* [让你的应用支持 iOS 10 系统扩展](http://gold.xitu.io/entry/57eb20592e958a005457e038?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiakeqi](https://github.com/jiakeqi) 翻译) -* [顶级 Swift 服务端框架对决 Node.js](http://gold.xitu.io/entry/57e296af0bd1d000570ee3b4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay) 翻译) -* [实现二叉树以及二叉树遍历数据结构](http://gold.xitu.io/entry/57cd6b028ac24700645a789c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cbangchen](https://github.com/cbangchen) 翻译) -* [关于 Swift,我不喜欢的几点](http://gold.xitu.io/entry/57cd6863128fe100697f1fed?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cbangchen](https://github.com/cbangchen) 翻译) -* [iOS APP 中的不可变模型以及一致性数据](http://gold.xitu.io/entry/57caeb8a79bc440063fb7ef0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/kulbear) 翻译) -* [「最简单」的 Core Data 上手指南](http://gold.xitu.io/entry/57c8f62f67f3560057aea07f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [用 RxSwift 实现通用的响应式转场](http://gold.xitu.io/entry/57c91b355bbb500074df6d19?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mypchas6fans](https://github.com/mypchas6fans) 翻译) -* [一些 NSFetchedResultsController 使用报错解决方案](http://gold.xitu.io/entry/57c796a6128fe1006958becc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Siegen](https://github.com/siegeout) 翻译) -* [用 Swift 枚举完美实现 3D touch 快捷操作](http://gold.xitu.io/entry/57c6b223efa631005ad6e7d1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeadLion](https://github.com/DeadLion) 翻译) -* [用 Swift 开发我的第一个 iOS 应用前,我想要知道这些内容](http://gold.xitu.io/entry/57c66667c4c9710061a57b3f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [安全的计时器设计模式](http://gold.xitu.io/entry/57b279f0128fe10055cda9fd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mypchas6fans](https://github.com/mypchas6fans) 翻译) -* [Swift + 闭包初始化](http://gold.xitu.io/entry/57bd72a3a633bd005d49fa32?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [有关用 Swift 访问后端服务器的 API 文档](http://gold.xitu.io/entry/57bd2d42efa631005a8ea10a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [等不及集成 iOS 10 新特性?如何在应用维护与新特性集成之间找到平衡点](http://gold.xitu.io/entry/57ad9e0e7db2a200540fe491?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [详解 Swift 的类型检查器](http://gold.xitu.io/entry/57a86c25d342d30057701fe1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [深入理解 Swift 中闭包的捕捉语义(一)](http://gold.xitu.io/entry/57a4b3d37db2a2005a992f67?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [使用流动控制器(Flow Controller )实现 MVVM 协议模型](http://gold.xitu.io/entry/57a037902e958a0066667ff4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shixinzhang](https://github.com/shixinzhang) 翻译) -* [在 Swift Playgrounds 中使用 Core Data 模型](http://gold.xitu.io/entry/579f1d9a5bbb500064ea3b20?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) -* [用 Xamarin 和 Visual Studio 构建 iOS 应用](http://gold.xitu.io/entry/579cb8f58ac247005fdb2a8c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [Swift 2 中为实存类型和泛型搭桥牵线](http://gold.xitu.io/entry/579cba75165abd006104d65c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([yifili09](https://github.com/yifili09) 翻译) -* [iOS 开发,该如何解决弹窗的设计问题?](http://gold.xitu.io/entry/5798724da633bd006a6c8652?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [iOS 开发中的 Flux 架构模式](http://gold.xitu.io/entry/57972cdcc4c97100542c2ed4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [高效的 iOS 应用版本支持方法](https://gold.xitu.io/entry/57957d892e958a006514bdbb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeadLion](https://github.com/DeadLion) 翻译) -* [iOS 开源图形库 Core Plot 使用教程](http://gold.xitu.io/entry/578f393ad342d30058e54bc0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([llp0574](https://github.com/llp0574) 翻译) -* [用 Swift 语言和 SpriteKit 创建有人工智能的井字游戏](http://gold.xitu.io/entry/578ef0bb8ac2470060b3da76?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [WWDC 2016:更加安全的 Swift 3.0](http://gold.xitu.io/entry/5788f7467db2a2005ce4f4fe?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [好的与坏的,Swift 语言面面观(二)](http://gold.xitu.io/entry/578dc9db79bc44005ff580d4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [好的与坏的,Swift 语言面面观(一)](http://gold.xitu.io/entry/578c647a6be3ff006ce49e91?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([达仔](https://github.com/zhangjd) 翻译) -* [假如 Mac 上也有 iOS 应用?](http://gold.xitu.io/entry/577b87d27db2a20054e47ecc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([wildflame](https://github.com/wildflame) 翻译) -* [iOS 开发者在 Swift 中应避免过度使用 @objc](https://gold.xitu.io/entry/57712f605bbb50005970dc0e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Dwight](https://github.com/ldhlfzysys) 翻译) -* [深度剖析 Swift 编译与运行时的类型检查](http://gold.xitu.io/entry/5767a62a80dda4005f9e97ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Jack](https://github.com/Jack-Kingdom) 翻译) -* [利用 Swift 在 APP 中实现撤销操作的功能](http://gold.xitu.io/entry/575fab19207703006bea9d27?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [关于 Swift 编译时性能优化的一些思考](http://gold.xitu.io/entry/5757f29279bc440061f5822c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([杨龙龙](https://github.com/yllziv) 翻译) -* [抢先看 Swift 3.0](http://gold.xitu.io/entry/57558db97db2a2006995ed53?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay)翻译) -* [如何检测 iPhone 是否处于低电量模式](http://gold.xitu.io/entry/574ff27d7db2a20055c7aec3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zheaoli](https://github.com/Zheaoli) 翻译) -* [给 iOS 开发者的 GCD 用户手册](http://gold.xitu.io/entry/574e544971cfe4006bffa552?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([LoneyIsError](https://github.com/LoneyIsError) 翻译) -* [使用 webP 减少图片的大小](http://gold.xitu.io/entry/57383657c4c97100601212d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([circlelove](https://github.com/circlelove) 翻译) -* [打破 Swift 结构体中的循环引用](http://gold.xitu.io/entry/572acc852e958a0069518605?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay)翻译) -* [使用 Xcode 的 Scheme 来跑不同的测试集合](http://gold.xitu.io/entry/5723223f71cfe400575f4528?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Tuccuay](https://github.com/Tuccuay)翻译) -* [UIScrollView 新手教程](http://gold.xitu.io/entry/570c71a81ea4930068dcbc5e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhongyi Tong](https://github.com/geeeeeeeeek)翻译) -* [RxSwift 的第一印象](http://gold.xitu.io/entry/56d5528a1532bc004c6e913a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SatanWoo](https://github.com/SatanWoo)翻译) -* [Facebook iOS 应用是如何加速图片显示的?](http://gold.xitu.io/entry/56de9bc7731956005e1b5b2e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([bobmayuze](https://github.com/bobmayuze) 翻译) -* [编写高质量的 Swift 代码](http://gold.xitu.io/entry/56b60c97816dfa005ae0c0d4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iThreeKing](https://github.com/iThreeKing) 翻译) -* [Artsy 工程师总结的一些 Cocoa 开发设计误区](http://gold.xitu.io/entry/56cbd1338ac2470053b55ce5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([nathanwhy](https://github.com/nathanwhy) 翻译) -* [UIKit 里如何面向协议编程](https://github.com/xitu/gold-miner/blob/master/TODO/ios-9-tutorial-series-protocol-oriented-programming-with-uikit.md) ([walkingway](https://github.com/walkingway) 翻译) -* [3D Force Touch 的新玩儿法](http://gold.xitu.io/entry/56cbd3ec1532bc00535cb0e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([shiguol](https://github.com/shiguol) 翻译) -* [Swift 新手指南](http://gold.xitu.io/entry/56cbd7e3128fe10058092760?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([cdpath](https://github.com/cdpath) 翻译) +* [SwiftUI 2 应用生命周期的终极指导](https://juejin.cn/post/6924119708832628749)([zhuzilin](https://github.com/zhuzilin) 翻译) +* [UIKit 和 SwiftUI:我该选择哪一个运用在实际产品开发中?](https://juejin.cn/post/6923197105422991367)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [我们应该在什么时候使用 @State、@Binding、@ObservedObject、@EnvironmentObject 和 @Environment?](https://juejin.cn/post/6920881116043968520)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [iOS 中的 widget](https://juejin.cn/post/6920017496497979399)([zhuzilin](https://github.com/zhuzilin) 翻译) +* [Flutter 可能是下一个大事件,但 Kotlin Multiplatform 一直都是大事件](https://juejin.cn/post/6916418157641105421)([keepmovingljzy](https://github.com/keepmovingljzy) 翻译) +* [SwiftUI 黑暗模式——最简单的方法](https://juejin.cn/post/6905925634552233998)([zhuzilin](https://github.com/zhuzilin) 翻译) +* [你不可错过的 10 个 Xcode 技巧和快捷键](https://juejin.cn/post/6913888065937211399)([Franz-Wang](https://github.com/Franz-Wang) 翻译) +* [SwiftUI 中的 PageTabViewStyle](https://juejin.cn/post/6906289114300039182)([Franz-Wang](https://github.com/Franz-Wang) 翻译) +* [在 Swift 中玩转 emoji](https://juejin.cn/post/6887739774254841863)([lcx-seima](https://github.com/lcx-seima) 翻译) +* [学习 SwiftUI 框架中 Text 和 Label 控件的用法(iOS 14)](https://juejin.im/post/6881526224934420488)([chaingangway](https://github.com/chaingangway) 翻译) +* [在 Swift 使用 User Defaults 的小技巧](https://juejin.im/post/5f0d09605188252e937bef4b)([chaingangway](https://github.com/chaingangway) 翻译) +* [Swift 5.3 的新功能,你了解吗?](https://juejin.im/post/5f158ae4e51d453460293edc)([chaingangway](https://github.com/chaingangway) 翻译) +* [在 SwiftUI 中构建服务端驱动的 UI 组件](https://juejin.im/post/6844904186862108679)([chaingangway](https://github.com/chaingangway) 翻译) +* [在 Swift 中使用 MVVM 架构实现无限滚动和图片加载](https://juejin.im/post/5ecb8115e51d4578540fcacd)([chaingangway](https://github.com/chaingangway) 翻译) +* [如何运用 Swift 的属性包装器实现应用本地化](https://juejin.im/post/5eb8d4b2e51d454db809ea31)([chaingangway](https://github.com/chaingangway) 翻译) +* [用 SwiftUI 实现酷炫的颜色切换动画](https://juejin.im/post/5eb39472e51d454dae5575cd)([chaingangway](https://github.com/chaingangway) 翻译) +* [在 Swift 中对 JSON 进行自定义编码和解码的小技巧](https://juejin.im/post/5eaae0216fb9a043282a4800)([chaingangway](https://github.com/chaingangway) 翻译) +* [0202 年了,是时候学习 Combine 了](https://juejin.im/post/5ec0d8946fb9a0433a19101f)([chaingangway](https://github.com/chaingangway) 翻译) +* [用 SwiftUI 实现 3D Scroll 效果](https://juejin.im/post/5e9feb21e51d45470b4ff99b)([chaingangway](https://github.com/chaingangway) 翻译) +* [用 SwiftUI 的 Paths 创建折线图](https://juejin.im/post/5e957bc8518825739a1b06d3)([chaingangway](https://github.com/chaingangway) 翻译) +* [巧用 ARKit 和 SpriteKit 从零开始做 AR 游戏](https://juejin.im/post/599aaf746fb9a02477072380)([danny1451](https://github.com/Danny1451) 翻译) +* [iOS 开发者一定要知道的 14 个知识点](https://gold.xitu.io/entry/58a5727261ff4b006c432a7f/)([deepmissea](https://github.com/DeepMissea) 翻译) +* [Web 端的 SwiftUI:SwiftWebUI](https://juejin.im/post/5d35e0ac5188257dc103e364)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Xcode 和 LLDB 高级调试教程:第 3 部分](https://juejin.im/post/5d383c7d5188257dab043145)([kirinzer](https://github.com/kirinzer) 翻译) +* [贫困线下的软件 — 开源项目的可持续发展问题探讨](https://juejin.im/post/5d215da2e51d4556be5b3acb)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [Git:透过命令学概念 —— 第二部分](https://juejin.im/post/5d2da05ae51d45106b15ffca)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [使用 Swift 5 构建一个 iOS 移动端群聊应用程序](https://juejin.im/post/5d2c6e846fb9a07ebb0564ae)([LucaslEliane](https://github.com/LucaslEliane) 翻译) +* [Xcode 和 LLDB 高级调试教程:第 2 部分](https://juejin.im/post/5d2321eee51d454f71439d64)([kirinzer](https://github.com/kirinzer) 翻译) +* [Xcode 和 LLDB 高级调试教程:第 1 部分](https://juejin.im/post/5d0b246be51d4555e372a60b)([kirinzer](https://github.com/kirinzer) 翻译) +* [iOS 中的 File Provider 拓展](https://juejin.im/post/5cff5b0af265da1b8b2b54c7)([iWeslie](https://github.com/iWeslie) 翻译) +* [用于 iOS 的 ML Kit 教程:识别图像中的文字](https://juejin.im/post/5cfe23af6fb9a07ee742d401)([portandbridge](https://github.com/portandbridge) 翻译) +* [Swift 5 中的枚举冻结](https://juejin.im/post/5cea9597e51d45775f5169f2)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 里的强制 @inline 注解](https://juejin.im/post/5cd67d64518825686244635a)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 代码格式化](https://juejin.im/post/5ccea148f265da038e54bbf2)([iWeslie](https://github.com/iWeslie) 翻译) +* [为你的 iOS App 构建分离测试](https://juejin.im/post/5ccd6b55f265da037d4fbc41)([iWeslie](https://github.com/iWeslie) 翻译) +* [iOS 里的 MVVM 和 RxSwift](https://juejin.im/post/5cb833abf265da03ac0d04d1)([iWeslie](https://github.com/iWeslie) 翻译) +* [实用的 MVVM 和 RxSwift](https://juejin.im/post/5cb80f9c6fb9a06876103744)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 模块中的 API 污染](https://juejin.im/post/5cb80f1f6fb9a0686a224a18)([iWeslie](https://github.com/iWeslie) 翻译) +* [懒加载变量在 iOS Swift](https://juejin.im/post/5ca775b26fb9a05e3527db37)([kirinzer](https://github.com/kirinzer) 翻译) +* [Swift 5.0 新特性](https://juejin.im/post/5ca41d766fb9a05e6d61ad2b)([iWeslie](https://github.com/iWeslie) 翻译) +* [在 swift 中使用 errors 作为控制流](https://juejin.im/post/5c90c0d9f265da612d6335cb)([swants](https://github.com/swants) 翻译) +* [iOS:如何构建具有多种 Cell 类型的表视图](https://juejin.im/post/5c89a917e51d457efe07f4f9)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [如何在 Swift 5 中使用 Result](https://juejin.im/post/5c9586eee51d4536e85c3d60)([Bruce-pac](https://github.com/Bruce-pac) 翻译) +* [iOS 响应者链 UIResponder,UIEvent,UIControl 的使用](https://juejin.im/post/5c9f652ae51d4519eb1ff426)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 5 强制独占性原则](https://juejin.im/post/5c778b5e6fb9a049c64487e0)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [React Native 中那些令我收获颇丰的痛点](https://juejin.im/post/5c74d6a16fb9a049f06ae907)([jerryOnlyZRJ](https://github.com/jerryOnlyZRJ) 翻译) +* [React Native 与 iOS 和 Android 通信](https://juejin.im/post/5c6ca781f265da2da8356c81)([MeandNi](https://github.com/MeandNi) 翻译) +* [Swift:通过示例避免内存泄漏](https://juejin.im/post/5c6a0abaf265da2dc675a9b2)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [用这些 iOS 技巧让你的 APP 性能更佳](https://juejin.im/post/5c6a0b6ef265da2de660f83f)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [iOS 设计模式进阶](https://juejin.im/post/5c51b959f265da6115112e3e)([iWeslie](https://github.com/iWeslie) 翻译) +* [iOS 中赏心悦目的动画](https://juejin.im/post/5c4f05bce51d4552411b1e13)([iWeslie](https://github.com/iWeslie) 翻译) +* [在 iOS 上使用 Carthage 建立依赖](https://juejin.im/post/5c4f04ef51882525eb3663be)([iWeslie](https://github.com/iWeslie) 翻译) +* [状态恢复入门教程](https://juejin.im/post/5c330d0ce51d45518e147fd2)([nanjingboy](https://github.com/nanjingboy) 翻译) +* [值类型导向编程](https://juejin.im/post/5c2c3f8d518825480635db8b)([nanjingboy](https://github.com/nanjingboy) 翻译) +* [使用 Swift 的 iOS 设计模式(第二部分)](https://juejin.im/post/5c1786576fb9a049f06a2c4a)([iWeslie](https://github.com/iWeslie) 翻译) +* [使用 Swift 的 iOS 设计模式(第一部分)](https://juejin.im/post/5c05d4ee5188250ab14e62d6)([iWeslie](https://github.com/iWeslie) 翻译) +* [使用 Kotlin 将你的 iOS 应用程序转换为 Android](https://juejin.im/post/5c03f64ce51d454af013d076)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 中的动态特性](https://juejin.im/post/5bfd087be51d457a013940e8)([iWeslie](https://github.com/iWeslie) 翻译) +* [介绍适用于 iOS 的 AloeStackView](https://juejin.im/post/5bf22a05f265da61783106de)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [iOS 12 占有率超过 50%,超过了 iOS 11](https://juejin.im/post/5bf64ad851882579117f74ae)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [从现有的代码库创建 Swift 包管理器](https://juejin.im/post/5bec2b735188253b6e5c132a)([iWeslie](https://github.com/iWeslie) 翻译) +* [Swift 中的惰性序列及其原理](https://juejin.im/post/5bc13f036fb9a05d28736f79)([RickeyBoy](https://github.com/RickeyBoy) 翻译) +* [Swift 中强大的模式匹配](https://juejin.im/post/5bbc096ce51d450e9162fd9d)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [在 iOS 中使用 UITests 测试 Facebook 登录功能](https://juejin.im/post/5b90e3ae6fb9a05d00458ad8)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [构建流畅的交互界面](https://juejin.im/post/5b7e2b34e51d4538843612cc)([rydensun](https://github.com/rydensun) 翻译) +* [2018 年 iOS 开发找工作完全指南](https://juejin.im/post/5b7eca206fb9a019ff713277)([melon8](https://github.com/melon8) 翻译) +* [你 Ladar 中该珍藏的:iOS 布局语言](https://juejin.im/post/5b84fe97f265da437c43422f)([pmwangyang](https://github.com/pmwangyang) 翻译) +* [重写 loadView() 方法使 Swift 视图代码更加简洁](https://juejin.im/post/5b68fe5b6fb9a04fd16039c0)([RickeyBoy](https://github.com/RickeyBoy) 翻译) +* [React Native 中使用转场动画!](https://juejin.im/post/5b69467e5188251b3c3b4e4e)([talisk](https://github.com/talisk) 翻译) +* [一份在你的 iPhone 上平衡实用和美观的指南](https://juejin.im/post/5b4c0d0ce51d4519503b1e67)([94haox](https://github.com/94haox) 翻译) +* [Tab Bar 就是新的汉堡菜单](https://juejin.im/post/5b61684fe51d451986517e31)([rydensun](https://github.com/rydensun) 翻译) +* [Airbnb 中的 React Native 上下的赌注(五 — 完):Airbnb 移动端路在何方?](https://juejin.im/post/5b46f92de51d45198e721cd7)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [Airbnb 中的 React Native 上下的赌注(四):React Native 退役](https://juejin.im/post/5b447b1e6fb9a04fd3437dad)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [Airbnb 中的 React Native 上下的赌注(三):建立一个跨平台的移动端团队](https://juejin.im/post/5b446177f265da0f7c4faec8)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [Airbnb 在 React Native 上下的赌注(二):技术细节](https://juejin.im/post/5b3b40a26fb9a04fab44e797)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [Airbnb 在 React Native 上下的赌注(一):概述](https://juejin.im/post/5b2c924ff265da59a401f050)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [苹果公司如何修复 3D Touch](https://juejin.im/post/5b35e5886fb9a00e3642724f)([Wangalan30](https://github.com/Wangalan30) 翻译) +* [不越狱探索 App](https://juejin.im/post/5b0e7eec518825155a048dc4)([melon8](https://github.com/melon8) 翻译) +* [Swift 中的 Playground 驱动开发](https://juejin.im/post/5b07665c6fb9a07ac5608d8a)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [Swift 中的内存泄漏](https://juejin.im/post/5b07a1c251882538914a5d3e)([RickeyBoy](https://github.com/RickeyBoy) 翻译) +* [使用 iPhone X 与 Maya 实现快速面部捕捉](https://juejin.im/post/5af40eba6fb9a07ac76ed7d1)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [轻松管理 Swift 项目中的不同环境](https://juejin.im/post/5af264a4f265da0b967233ff)([melon8](https://github.com/melon8) 翻译) +* [构建、测试、分发!运用 Fastlane 与 Jenkins,完整的 iOS 持交付指南。](https://juejin.im/post/5af430f0f265da0b8262d1ea)([talisk](https://github.com/talisk) 翻译) +* [Story 中 Type Mode 在 iOS 和 Android 上的实现](https://juejin.im/post/5ae7e1596fb9a07ab9794332)([melon8](https://github.com/melon8) 翻译) +* [Swift 写网络层:用面向协议的方式](https://juejin.im/post/5af432385188256737066c04)([talisk](https://github.com/talisk) 翻译) +* [使用 Swift 实现原型动画](https://juejin.im/post/5ae28a9b6fb9a07aaa10fa1e)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [不使用 fastlane 实现持续交付的 5 种选项](https://juejin.im/post/5acf47cb6fb9a028c523944c)([melon8](https://github.com/melon8) 翻译) +* [没有 Interface Builder 的生活](https://juejin.im/post/5ab88ac0518825558a069c91)([rydensun](https://github.com/rydensun) 翻译) +* [让我们来简化 UserDefaults 的使用](https://juejin.im/post/5abde324f265da23826e1723)([talisk](https://github.com/talisk) 翻译) +* [避免 Swift 单元测试中的强制解析](https://juejin.im/post/5a9ce4ac6fb9a028b547602e)([RickeyBoy](https://github.com/RickeyBoy) 翻译) +* [iOS App 上一种灵活的路由方式](https://juejin.im/post/5aafc278f265da23805973e3)([YinTokey](https://github.com/YinTokey) 翻译) +* [通过 Quick 和 Nimble 在 Swift 中进行测试驱动开发](https://juejin.im/post/5a93635d5188257a7924c5d5)([94haox](https://github.com/94haox) 翻译) +* [为什么你的 APP 在 Sketch 上看起来更好:探索 Sketch 和 iOS 的渲染差异](https://juejin.im/post/5a9572575188257a61326630)([rydensun](https://github.com/rydensun) 翻译) +* [在 Swift playground 中编写单元测试](https://juejin.im/post/5a8e66276fb9a0633c661f3f)([lsvih](https://github.com/lsvih) 翻译) +* [swift 网络单元测试完全手册](https://juejin.im/post/5a784e87f265da4e8a31ca7a)([swants](https://github.com/swants) 翻译) +* [用 LLDB 调试 Swift 代码](https://juejin.im/post/5a7948d35188257a7349a882)([VernonVan](https://github.com/VernonVan) 翻译) +* [不再对 MVVM 感到绝望](https://juejin.im/post/5a782d0d5188257a856f1dd7)([JayZhaoBoy](https://github.com/JayZhaoBoy) 翻译) +* [断点:像专家一样调试代码](https://juejin.im/post/5a72be42518825733b0f374e)([pthtc](https://github.com/pthtc) 翻译) +* [17 个 Xcode 小技巧,每个 iOS 开发者都该知道](https://juejin.im/post/5a7198ac51882573505189c8)([pthtc](https://github.com/pthtc) 翻译) +* [Swift 中的值类型与引用类型使用指北](https://juejin.im/post/5a5c2c046fb9a01cbe654b48)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [Xcode 环境配置最佳实践](https://juejin.im/post/5a4f120cf265da3e3d48f1f6)([swants](https://github.com/swants) 翻译) +* [基于 Metal 的 ARKit 使用指南(上)](https://juejin.im/post/5a225ffcf265da432153daa4)([RichardLeeH](https://github.com/RichardLeeH) 翻译) +* [处理 iOS 中复杂的 Table Views 并保持优雅](https://juejin.im/post/5a078ec3f265da431955c0d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangqippp](https://github.com/zhangqippp) 翻译) +* [Swift 上的高性能数组](https://juejin.im/post/59e84129f265da43128005ed?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jingzhilehuakai](https://github.com/jingzhilehuakai) 翻译) +* [通过 Metal 来使用 ARKit (下)](https://juejin.im/post/59bb2a99f265da0650750e56?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([swants](https://github.com/swants) 翻译) +* [如何在 iOS 上实现类似 Airbnb 中的可展开式菜单](https://juejin.im/post/59acdf2b6fb9a024763806cf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([RichardLeeH](https://github.com/RichardLeeH) 翻译) +* [结构体指针](https://juejin.im/post/59a60cc1f265da249a201ae9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([swants](https://github.com/swants) 翻译) +* [MVVM, Coordinators 和 RxSwift 的抽丝剥茧](https://juejin.im/post/59acf7dcf265da24722fe6a1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jingzhilehuakai](https://github.com/jingzhilehuakai) 翻译) +* [探究 Swift 中的 Futures & Promises](https://juejin.im/post/59afcf5d51882524434163dd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([atuooo](https://github.com/atuooo) 翻译) +* [iOS 响应式编程:Swift 中的轻量级状态容器](https://juejin.im/post/599652ee6fb9a024903a8d59?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([atuooo](https://github.com/atuooo) 翻译) +* [Swift 中的通用数据源](https://juejin.im/post/5990fd7b51882548bc7cabd8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([swants](https://github.com/swants) 翻译) +* [模块化 Swift 中的状态](https://juejin.im/post/597962875188253dda0f05a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [Xcode 中的用户断点](https://juejin.im/post/597934335188253dfb7b0db7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([atuooo](https://github.com/atuooo) 翻译) +* [语句,消息和归约器](https://juejin.im/post/596f17366fb9a06bc17c53db?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangqippp](https://github.com/zhangqippp) 翻译) +* [开发者眼中 iOS 11 都更新了什么?](https://juejin.im/post/595f1f2c5188250d8a605d69?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([swants](https://github.com/swants) 翻译) +* [把 UUID 或者 GUID 作为主键?你得小心啦!](https://juejin.im/post/59561e5b6fb9a06bbf6fdf16?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zaraguo](https://github.com/zaraguo) 翻译) +* [iOS 11:机器学习人人有份](https://juejin.im/post/59533049f265da6c3a54b739?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([changkun](https://github.com/changkun) 翻译) +* [Swift 中关于并发的一切:第一部分 — 当前](https://juejin.im/post/5954571af265da6c4c4fc3f8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [iOS 11:UIKit 中值得注意的新能力](https://juejin.im/post/5944adfffe88c2006a6f6f3a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangqippp](https://github.com/zhangqippp) 翻译) +* [深度学习在 iOS 上的实践 —— 通过 YOLO 在 iOS 上实现实时物体检测](https://juejin.im/post/59433498da2f600067604218?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny1451](https://github.com/Danny1451) 翻译) +* [消息同步 —— 在 Airbnb 我们是怎样扩展移动消息的](https://juejin.im/post/593a7647128fe1006acafaf9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [对元素持有弱引用的 Swift 数组](https://juejin.im/post/5927a34c0ce46300575a81e1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([zhangqippp](https://github.com/zhangqippp) 翻译) +* [在 Swift 中使用闭包实现懒加载](https://juejin.im/post/590a9eeab123db00549776ee/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [掌握 Swift 的字符串细节](https://juejin.im/post/58f822ff5c497d0058e0e427/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay(洪朔)](https://github.com/Tuccuay) 翻译) +* [MVVM-C 与 Swift](https://juejin.im/post/58ef16b8da2f60005d180666/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [Swift 闭包和代理中的保留周期](https://juejin.im/post/58e4ac5d44d904006d2a9a19/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([oOatuo](http://atuo.xyz/) 翻译) +* [一名 iOS 开发者的 React Native 开发经历](https://juejin.im/post/58df4c3fa0bb9f0069e2f2bd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lsvih](https://github.com/lsvih) 翻译) +* [优化 Swift 的编译时间](https://juejin.im/post/58df1d75570c35005796966b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [看!Swift 里竟然有红绿灯 🚦!](https://juejin.im/post/58ddbc612f301e0062fed742/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [原生 iOS(Swift) 和 React-Native 的性能比较](https://juejin.im/post/58ca6d5f44d90400682a215c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [如果只有一个月入门 iOS:我该如何学习呢?](https://juejin.im/post/58c9f436a22b9d0064187e39/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015(Gocy)](https://github.com/Gocy015) 翻译) +* [在 Xcode 项目中使用 swift package fetch](https://juejin.im/post/58c7a4cb1b69e6006bec354c/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015(Gocy)](https://github.com/Gocy015) 翻译) +* [Bob,函数式编程是什么鬼?](https://juejin.im/post/58c24c35a22b9d00589a56d4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [Swift + 关键字](https://juejin.im/post/58bf76aaa22b9d0058896bff/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [重构 Swift 中单例的用法](https://gold.xitu.io/entry/58b81150570c3500598fc567/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Karthus1110](https://github.com/Karthus1110) 翻译) +* [Bob,我要怎样才能成为一名 iOS 开发者](https://gold.xitu.io/entry/58b153c38fd9c50063d38068/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([thanksdanny](https://github.com/thanksdanny) 翻译) +* [步入 Swift 3](https://gold.xitu.io/entry/58aa701fda2f60006fa9978f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [iOS 开发中使用 Swift 进行 iBeacons 交互指南](https://gold.xitu.io/entry/58a6f4091b69e6006d275610/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lovelyCiTY](https://github.com/lovelyCiTY) 翻译) +* [[译] iOS 开发者一定要知道的 14 个知识点](https://gold.xitu.io/entry/58a5727261ff4b006c432a7f/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Deepmissea](http://deepmissea.blue) 翻译) +* [iOS 应用测试](https://gold.xitu.io/entry/58a16cc161ff4b006b51d882/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([thanksdanny](https://github.com/thanksdanny) 翻译) +* [老司机手把手带你在 Swift 中应用代理(Delegate)](https://gold.xitu.io/entry/58a11b7c61ff4b006b4f7f69/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015](https://github.com/Gocy015) 翻译) +* [在 Swift 3 上对视图控件实践面向协议编程](https://gold.xitu.io/entry/589b42692f301e00699b8011/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [让内存管理重振雄风](https://gold.xitu.io/entry/589afeb78d6d81006c78132a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [Swift 面向协议编程入门](https://gold.xitu.io/entry/589439622f301e00693567e5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny Lau](https://github.com/Danny1451) 翻译) +* [如何在 Swift 3 中用 SpriteKit 框架编写游戏 (Part 3)](https://gold.xitu.io/entry/586d359a128fe1006661e361?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeepMissea](https://github.com/DeepMissea) 翻译) +* [如何在 Swift 3 中用 SpriteKit 框架编写游戏 (Part 2)](https://gold.xitu.io/entry/5860d2e4128fe1006dfbb962?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZiXYu](https://github.com/ZiXYu) 翻译) +* [如何在 Swift 3 中用 Spirit Kit 框架编写游戏 (Part 1)](https://gold.xitu.io/entry/585b7cc18d6d810065d2905e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy015](https://github.com/Gocy015) 翻译) +* [macOS Security and Privacy Guide](https://gold.xitu.io/entry/585501e2b123db00656a6947?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09)   [MAYDAY1993](https://github.com/MAYDAY1993)  )([DeadLion](https://github.com/DeadLion) 翻译) +* [Yammer iOS 版移植到 Swift3](https://gold.xitu.io/entry/5848b88ab123db006601f750?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny Lau](https://github.com/Danny1451) 翻译) +* [Swift 面向协议编程,灵丹妙药或是饮鸩止渴?](https://gold.xitu.io/entry/584781e161ff4b006bac77ba?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [如何避免应用崩溃](http://gold.xitu.io/entry/58423231a22b9d006c1959ee?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Gocy](https://github.com/Gocy) 翻译) +* [理解 iOS 应用程序的代码签名 (CODE SIGN) 机制](http://gold.xitu.io/entry/5826ef85570c3500586b241d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [给 iOS App 开发者的 39 个开源的 Swift UI 库](http://gold.xitu.io/entry/58209322570c350060b73588?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [Swift 3 语言中的全模块优化](http://gold.xitu.io/entry/5818b6f52f301e005cf0ef8e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Edison-Hsu](https://github.com/Edison-Hsu) 翻译) +* [UserNotifications Framework 入门介绍](http://gold.xitu.io/entry/5816a28f128fe10055912398?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny Lau](https://github.com/Danny1451) 翻译) +* [Swift 声明式程序设计](http://gold.xitu.io/entry/58105d1e128fe1005feca8dc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [如何使用 UIFeedbackGenerator 让应用支持 iOS 10 的触觉反馈](http://gold.xitu.io/entry/5810433ac4c9710058a74100?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([owenlyn](https://github.com/owenlyn) 翻译) +* [让 iOS 10 今日控件向后兼容的几个技巧](http://gold.xitu.io/entry/580eec1b8ac247005b620267?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Edison.Hsu](https://github.com/edison-hsu) 翻译) +* [Swfit 代码的可测试性](http://gold.xitu.io/entry/58086fe52f301e005c27221f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([steinliber](https://github.com/steinliber) 翻译) +* [iOS 10 中的 NSPersistentContainer](http://gold.xitu.io/entry/580444efa34131005fe77197?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [Swift 中的面向协议编程是如何点亮我的人生的](http://gold.xitu.io/entry/58044fc5a22b9d005b4f56b2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Danny Lau](https://github.com/Danny1451) 翻译) +* [Swift 3 中的函数参数命名规范指北](http://gold.xitu.io/entry/57fa593b2e958a00558b2d17?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [迁移到 Swift 3,这些陷阱在等你](http://gold.xitu.io/entry/57f6fa03816dfa0056a4d782?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shliujing](https://github.com/shliujing) 翻译) +* [让你的应用支持 iOS 10 系统扩展](http://gold.xitu.io/entry/57eb20592e958a005457e038?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiakeqi](https://github.com/jiakeqi) 翻译) +* [顶级 Swift 服务端框架对决 Node.js](http://gold.xitu.io/entry/57e296af0bd1d000570ee3b4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [实现二叉树以及二叉树遍历数据结构](http://gold.xitu.io/entry/57cd6b028ac24700645a789c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cbangchen](https://github.com/cbangchen) 翻译) +* [关于 Swift,我不喜欢的几点](http://gold.xitu.io/entry/57cd6863128fe100697f1fed?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cbangchen](https://github.com/cbangchen) 翻译) +* [iOS APP 中的不可变模型以及一致性数据](http://gold.xitu.io/entry/57caeb8a79bc440063fb7ef0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/kulbear) 翻译) +* [「最简单」的 Core Data 上手指南](http://gold.xitu.io/entry/57c8f62f67f3560057aea07f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [用 RxSwift 实现通用的响应式转场](http://gold.xitu.io/entry/57c91b355bbb500074df6d19?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mypchas6fans](https://github.com/mypchas6fans) 翻译) +* [一些 NSFetchedResultsController 使用报错解决方案](http://gold.xitu.io/entry/57c796a6128fe1006958becc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Siegen](https://github.com/siegeout) 翻译) +* [用 Swift 枚举完美实现 3D touch 快捷操作](http://gold.xitu.io/entry/57c6b223efa631005ad6e7d1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeadLion](https://github.com/DeadLion) 翻译) +* [用 Swift 开发我的第一个 iOS 应用前,我想要知道这些内容](http://gold.xitu.io/entry/57c66667c4c9710061a57b3f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [安全的计时器设计模式](http://gold.xitu.io/entry/57b279f0128fe10055cda9fd?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mypchas6fans](https://github.com/mypchas6fans) 翻译) +* [Swift + 闭包初始化](http://gold.xitu.io/entry/57bd72a3a633bd005d49fa32?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [有关用 Swift 访问后端服务器的 API 文档](http://gold.xitu.io/entry/57bd2d42efa631005a8ea10a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [等不及集成 iOS 10 新特性?如何在应用维护与新特性集成之间找到平衡点](http://gold.xitu.io/entry/57ad9e0e7db2a200540fe491?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [详解 Swift 的类型检查器](http://gold.xitu.io/entry/57a86c25d342d30057701fe1?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [深入理解 Swift 中闭包的捕捉语义(一)](http://gold.xitu.io/entry/57a4b3d37db2a2005a992f67?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [使用流动控制器(Flow Controller )实现 MVVM 协议模型](http://gold.xitu.io/entry/57a037902e958a0066667ff4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shixinzhang](https://github.com/shixinzhang) 翻译) +* [在 Swift Playgrounds 中使用 Core Data 模型](http://gold.xitu.io/entry/579f1d9a5bbb500064ea3b20?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) +* [用 Xamarin 和 Visual Studio 构建 iOS 应用](http://gold.xitu.io/entry/579cb8f58ac247005fdb2a8c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [Swift 2 中为实存类型和泛型搭桥牵线](http://gold.xitu.io/entry/579cba75165abd006104d65c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([yifili09](https://github.com/yifili09) 翻译) +* [iOS 开发,该如何解决弹窗的设计问题?](http://gold.xitu.io/entry/5798724da633bd006a6c8652?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [iOS 开发中的 Flux 架构模式](http://gold.xitu.io/entry/57972cdcc4c97100542c2ed4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [高效的 iOS 应用版本支持方法](https://gold.xitu.io/entry/57957d892e958a006514bdbb?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([DeadLion](https://github.com/DeadLion) 翻译) +* [iOS 开源图形库 Core Plot 使用教程](http://gold.xitu.io/entry/578f393ad342d30058e54bc0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([llp0574](https://github.com/llp0574) 翻译) +* [用 Swift 语言和 SpriteKit 创建有人工智能的井字游戏](http://gold.xitu.io/entry/578ef0bb8ac2470060b3da76?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [WWDC 2016:更加安全的 Swift 3.0](http://gold.xitu.io/entry/5788f7467db2a2005ce4f4fe?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [好的与坏的,Swift 语言面面观(二)](http://gold.xitu.io/entry/578dc9db79bc44005ff580d4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [好的与坏的,Swift 语言面面观(一)](http://gold.xitu.io/entry/578c647a6be3ff006ce49e91?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([达仔](https://github.com/zhangjd) 翻译) +* [假如 Mac 上也有 iOS 应用?](http://gold.xitu.io/entry/577b87d27db2a20054e47ecc?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([wildflame](https://github.com/wildflame) 翻译) +* [iOS 开发者在 Swift 中应避免过度使用 @objc](https://gold.xitu.io/entry/57712f605bbb50005970dc0e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Dwight](https://github.com/ldhlfzysys) 翻译) +* [深度剖析 Swift 编译与运行时的类型检查](http://gold.xitu.io/entry/5767a62a80dda4005f9e97ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Jack](https://github.com/Jack-Kingdom) 翻译) +* [利用 Swift 在 APP 中实现撤销操作的功能](http://gold.xitu.io/entry/575fab19207703006bea9d27?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [关于 Swift 编译时性能优化的一些思考](http://gold.xitu.io/entry/5757f29279bc440061f5822c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([杨龙龙](https://github.com/yllziv) 翻译) +* [抢先看 Swift 3.0](http://gold.xitu.io/entry/57558db97db2a2006995ed53?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [如何检测 iPhone 是否处于低电量模式](http://gold.xitu.io/entry/574ff27d7db2a20055c7aec3?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zheaoli](https://github.com/Zheaoli) 翻译) +* [给 iOS 开发者的 GCD 用户手册](http://gold.xitu.io/entry/574e544971cfe4006bffa552?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([LoneyIsError](https://github.com/LoneyIsError) 翻译) +* [使用 webP 减少图片的大小](http://gold.xitu.io/entry/57383657c4c97100601212d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([circlelove](https://github.com/circlelove) 翻译) +* [打破 Swift 结构体中的循环引用](http://gold.xitu.io/entry/572acc852e958a0069518605?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [使用 Xcode 的 Scheme 来跑不同的测试集合](http://gold.xitu.io/entry/5723223f71cfe400575f4528?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Tuccuay](https://github.com/Tuccuay) 翻译) +* [UIScrollView 新手教程](http://gold.xitu.io/entry/570c71a81ea4930068dcbc5e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhongyi Tong](https://github.com/geeeeeeeeek) 翻译) +* [RxSwift 的第一印象](http://gold.xitu.io/entry/56d5528a1532bc004c6e913a?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([SatanWoo](https://github.com/SatanWoo) 翻译) +* [Facebook iOS 应用是如何加速图片显示的?](http://gold.xitu.io/entry/56de9bc7731956005e1b5b2e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([bobmayuze](https://github.com/bobmayuze) 翻译) +* [编写高质量的 Swift 代码](http://gold.xitu.io/entry/56b60c97816dfa005ae0c0d4?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iThreeKing](https://github.com/iThreeKing) 翻译) +* [Artsy 工程师总结的一些 Cocoa 开发设计误区](http://gold.xitu.io/entry/56cbd1338ac2470053b55ce5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([nathanwhy](https://github.com/nathanwhy) 翻译) +* [UIKit 里如何面向协议编程](https://github.com/xitu/gold-miner/blob/master/TODO/ios-9-tutorial-series-protocol-oriented-programming-with-uikit.md)([walkingway](https://github.com/walkingway) 翻译) +* [3D Force Touch 的新玩儿法](http://gold.xitu.io/entry/56cbd3ec1532bc00535cb0e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([shiguol](https://github.com/shiguol) 翻译) +* [Swift 新手指南](http://gold.xitu.io/entry/56cbd7e3128fe10058092760?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([cdpath](https://github.com/cdpath) 翻译) diff --git a/others.md b/others.md index aac9e48d3f0..3cb171dfb1f 100644 --- a/others.md +++ b/others.md @@ -1,59 +1,109 @@ -* [敏捷也许是个问题](https://juejin.im/post/5d2dfb4ae51d45775f516b1e) ([Charlo-O](https://github.com/Charlo-O) 翻译) -* [npm 的经济风云 —— 下半部分](https://juejin.im/post/5d2d9e7af265da1b8b2b91ca) ([Baddyo](https://github.com/Baddyo) 翻译) -* [类(Class)与数据结构(Data Structures)](https://juejin.im/post/5d12efe7e51d455c8838e193) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Git:透过命令学概念 —— 第一部分](https://juejin.im/post/5d0b3c7ce51d4577531381e3) ([Baddyo](https://github.com/Baddyo) 翻译) -* [10 分钟爆改终端](https://juejin.im/post/5d053fc56fb9a07ee85c283d) ([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) -* [剖析 Stack Overflow,开发者遇到最多的的 Bug 是哪些?](https://juejin.im/post/5d087a32518825403d14758b) ([whatbeg](https://github.com/whatbeg) 翻译) -* [帮你高效使用 VS Code 的秘诀](https://juejin.im/post/5cd8fcedf265da03761eaa45) ([Baddyo](https://github.com/Baddyo) 翻译) -* [我们从招聘技术经理的过程中学到了什么](https://juejin.im/post/5cdcf463f265da0392580820) ([JackEggie](https://github.com/JackEggie) 翻译) -* [最优控制:LQR](https://juejin.im/post/5cdfe49c6fb9a07eee5e9de6) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [Commit 提交指南](https://juejin.im/post/5ccf9e60f265da039c05659d) ([Mirosalva](https://github.com/Mirosalva) 翻译) -* [如何避免我作为初级开发者时所犯下的 7 个错误](https://juejin.im/post/5cbea729e51d456e8240dcfa) ([whatbeg](https://github.com/whatbeg) 翻译) -* [你不能成为成功程序员的 10 个迹象](https://juejin.im/post/5ca2f5ce51882565cb5b962c) ([xionglong58](https://github.com/xionglong58) 翻译) -* [浏览器帧原理剖析](https://juejin.im/post/5c9c66075188251dab07413d) ([WangLeto](https://github.com/WangLeto) 翻译) -* [开源是无法赚钱的,因为开源本身就不是为了赚钱](https://juejin.im/post/5c998753e51d456ef105ac1e) ([kasheemlew](https://github.com/kasheemlew) 翻译) -* [如何心平气和的阅读代码](https://juejin.im/post/5c9c521b5188252d876e5dcb) ([Mcskiller](https://github.com/Mcskiller) 翻译) -* [修改 Git 错误的高明方法](https://juejin.im/post/5c735a235188256262174e48) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [如何写一篇软件工程必杀简历](https://juejin.im/post/5c6ca8b9f265da2dc13c7a10) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [提高营销效率的工程(第一部分)](https://juejin.im/post/5c403b5ce51d452c8e6d3dc4) ([Starriers](https://github.com/Starriers) 翻译) -* [讨论 JS ⚡:文档](https://juejin.im/post/5c4039bbe51d4551733494a6) ([Starriers](https://github.com/Starriers) 翻译) -* [我无法想象没有 Git 别名的的场景](https://juejin.im/post/5c207bd4e51d452b7b032cf6) ([Starriers](https://github.com/Starriers) 翻译) -* [三人研发小组的高效研发尝试](https://juejin.im/post/5c19d1846fb9a049f06a33fc) ([yuwhuawang](https://github.com/yuwhuawang) 翻译) -* [理解编译器 — 从人类的角度(版本 2)](https://juejin.im/post/5c10b2f6e51d452ad958631f) ([Starriers](https://github.com/Starriers) 翻译) -* [深度专注的工作 — 成为 10 倍效率的开发者的秘密武器](https://juejin.im/post/5bffb3f5f265da613a53bd4b) ([tmpbook](https://github.com/tmpbook) 翻译) -* [如何让高效的代码评审成为一种文化](https://juejin.im/post/5bfc9ff9e51d454b6c371f5d) ([CoolRice](https://github.com/CoolRice) 翻译) -* [在远程工作中领悟到的 10 件事](https://juejin.im/post/5bf7a79f51882511a8528cf0) ([Starriers](https://github.com/Starriers) 翻译) -* [职业成长的内部指南](https://juejin.im/post/5bd722a65188252dd11662af) ([yuwhuawang](https://github.com/yuwhuawang) 翻译) -* [6 个最令人满意的和编程相关的工作(和参与这些工作的人们的类型)](https://juejin.im/post/5be271f0e51d450556196864) ([Augustwuli](https://github.com/Augustwuli) 翻译) -* [作为自由开发者,7 个步骤让你获得更多的客户](https://juejin.im/post/5bd660c26fb9a05ce576e9b7) ([rydensun](https://github.com/rydensun) 翻译) -* [C++ 协程:理解运算符 co_await](https://juejin.im/post/5bee59a1e51d4545453dc558) ([7Ethan](https://github.com/7Ethan) 翻译) -* [代码评审的 8 点建议](https://juejin.im/post/5bd1e6696fb9a05d096597c6) ([xiaoxi666](https://github.com/xiaoxi666) 翻译) -* [如何组织 Hacktoberfest 主题聚会](https://juejin.im/post/5bbc150be51d450e6867be7a) ([jianboy](https://github.com/jianboy) 翻译) -* [下一代包管理工具](https://juejin.im/post/5ba9830fe51d450e4d2fe208) ([diliburong](https://github.com/diliburong) 翻译) -* [新手开发者须知](https://juejin.im/post/5bade6a76fb9a05d32515cf0) ([ssshooter](https://github.com/ssshooter) 翻译) -* [用 Workers 让静态网站动态化](https://juejin.im/post/5b95c5375188255c6e70422a) ([MeFelixWang](https://github.com/MeFelixWang) 翻译) -* [关于工程师和影响力](https://juejin.im/post/5b8f9a96f265da0ab33125b0) ([cf020031308](https://github.com/cf020031308) 翻译) -* [如何像程序员般思考 —— 蕴含在问题解决中的经验](https://juejin.im/post/5b76839ae51d4566491c24bb) ([mingxing47](https://github.com/mingxing47) 翻译) -* [编程语言和平台:一条被评论的推文串](https://juejin.im/post/5b4c2b75e51d45195b336d57) ([cf020031308](https://github.com/cf020031308) 翻译) -* [为 GitHub 项目做出贡献的初学者指南](https://juejin.im/entry/5b2e58ba6fb9a00e4966ee4b) ([sophiayang1997](https://github.com/sophiayang1997) 翻译) -* [怎样(以及为什么要)保持你的 Git 提交记录的整洁](https://juejin.im/post/5b29060ee51d4558cd2adac0) ([zhongdeming428](https://github.com/zhongdeming428) 翻译) -* [关于你的编程生涯的一些告诫](https://juejin.im/post/5b0256e36fb9a07aa767f5b4) ([kezhenxu94](https://github.com/kezhenxu94) 翻译) -* [部署!=发布(第二部分)](https://juejin.im/post/5b00d2fa6fb9a07a9a1120e9) ([Starriers](https://github.com/Starriers) 翻译) -* [如何逃离 async/await 地狱](https://juejin.im/post/5aefbb48f265da0b9b073c40) ([Colafornia](https://github.com/Colafornia) 翻译) -* [我在编程初级阶段常犯的错误](https://juejin.im/post/5ae97af6f265da0ba062f797) ([kezhenxu94](https://github.com/kezhenxu94) 翻译) -* [Deploy != Release(第一部分):Deploy 与 Release 的区别及为什么很重要?](https://juejin.im/post/5ad80983f265da505c3c1b3a) ([stormluke](https://github.com/stormluke) 翻译) -* [引导员手册:24 个设计冲刺技巧](https://juejin.im/post/5ae3254d6fb9a07abc29a741) ([PokerF](https://github.com/PokerF) 翻译) -* [简短而又完全精确的编程语言历史](https://juejin.im/post/5ac1b8a25188255c637b1cd5) ([Starriers](https://github.com/Starriers) 翻译) -* [让 Apache Cassandra 尾部延迟减小 10 倍(已开源)](https://juejin.im/post/5ac31083f265da239a5fff0c) ([stormluke](https://github.com/stormluke) 翻译) -* [良好的编码习惯 — 5 个提高代码质量的技巧](https://juejin.im/post/5abc584251882555867f7f1e) ([NeoyeElf](https://github.com/NeoyeElf) 翻译) -* [如何修改域名来提高国际增长率](https://juejin.im/post/5aaf0542f265da239530c653) ([Starriers](https://github.com/Starriers) 翻译) -* [不要害怕 Rebase](https://juejin.im/post/5ab1bdbe518825556e5df5f8) ([sqrthree](https://github.com/sqrthree) 翻译) -* [开启你的开源生涯](https://juejin.im/post/5a5c029d51882573432d21ff) ([zwwill](https://github.com/zwwill) 翻译) -* [自动化持续集成/持续分发,以节省更多时间编写代码](https://juejin.im/post/5a44aab86fb9a044ff31c418) ([NeilLi1992](https://github.com/NeilLi1992) 翻译) -* [为什么我们从来不去感谢开源项目维护者](https://juejin.im/post/5a40c20b518825696f7e3c23) ([leviding](https://github.com/leviding) 翻译) -* [五天拿下硅谷五家顶级互联网公司 offer](https://juejin.im/post/5a1247d26fb9a0452a3bec33) ([freerambo](https://github.com/freerambo) 翻译) -* [为什么我还没 Fix 你的 Issue](https://juejin.im/post/59950fd9f265da248535b46d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([leviding](https://github.com/leviding) 翻译) -* [Chrome 开发者工具提示和技巧](http://gold.xitu.io/entry/56d56f4dc4c971005193ecec?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([chemzqm](https://github.com/chemzqm) 翻译) -* [通过 Electron 开发一个简单的桌面应用](http://gold.xitu.io/entry/56aae5e4a633bd0257ae4ab8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangdroid](https://github.com/Zhangdroid) 翻译) -* [Retrofit 入门教程](http://gold.xitu.io/entry/56cc4085128fe100580dd0ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([kevin xiu](https://github.com/xiuweikang) 翻译) -* [Pokedex.org 给宠物小精灵爱好者的 web app 的技术选型](http://gold.xitu.io/entry/56cebb8edf0eea79dc7c1ff0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([RobertWang](https://github.com/RobertWang) 翻译) +* [代码可视化 - 使用图技术为 Python 项目绘制结构图](https://juejin.cn/post/6935232492299354120)([Ashira97](https://github.com/Ashira97) 翻译) +* [你有设计作品的作品集吗?挺好的,但这还不够](https://juejin.cn/post/6934328263011467277)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [恭喜 Safari 荣获「第二个 Internet Explorer」的美誉](https://juejin.cn/post/6929754875001569294)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [基于 50 万个浏览器指纹的新发现](https://juejin.cn/post/6930974348002590733)([Usualminds](https://github.com/Usualminds) 翻译) +* [我拒绝了 MIT 的 Offer,依然是一个高价值的开发者](https://juejin.cn/post/6924489699641786375)([keepmovingljzy](https://github.com/keepmovingljzy) 翻译) +* [你应该知道的 3 个罕见的 Bash 技巧](https://juejin.cn/post/6923190362706018318)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [10 个你应该现在启用的绝佳的 Chrome Flags](https://juejin.cn/post/6923198038894706701)([PassionPenguin](https://github.com/PassionPenguin) 翻译) +* [如何成为谷歌开发专家(GDE)— 实用指南](https://juejin.cn/post/6918640631317266439)([Usualminds](https://github.com/Usualminds) 翻译) +* [为什么要让你的代码尽可能简单](https://juejin.cn/post/6914669681500487687)([NieZhuZhu](https://github.com/NieZhuZhu) 翻译) +* [迪米特法则](https://juejin.cn/post/6890050952049950733)([samyu2000](https://github.com/samyu2000) 翻译) +* [5 分钟内从单体架构迁移到微服务架构](https://juejin.cn/post/6900884077226917901)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [大数据:简述 Lambda 架构](https://juejin.cn/post/6887845604886741006)([jackwener](https://github.com/jackwener) 翻译) +* [MVC,MVP,MVVM 对比](https://juejin.cn/post/6883088734699388941)([snowyYU](https://github.com/snowyYU) 翻译) +* [知识的极限](https://juejin.im/post/6874475968325484552)([QinRoc](https://github.com/QinRoc) 翻译) +* [世界比以往任何时候都更需要 Web 可访问性](https://juejin.im/post/6872684910058930189)([tonylua](https://github.com/tonylua) 翻译) +* [从头开始到最初的 10 个客户:我是如何设计并推出一个 SaaS 产品](https://juejin.im/post/6860850397293232141)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [使用 Node.js 控制树莓派 4 的 GPIO](https://juejin.im/post/6868946182325043207)([Weirdochr](https://github.com/Weirdochr) 翻译) +* [如何写一份能让你获得面试机会的前端求职简历](https://juejin.im/post/5ef5ef41f265da22ff543630)([febrainqu](https://github.com/febrainqu) 翻译) +* [Deno 会对 Node 造成威胁吗?](https://juejin.im/post/5ecf6f166fb9a047d77cbe35)([ZiXYu](https://github.com/ZiXYu) 翻译) +* [Ubuntu 20.04 会不会偷走更多的 Windows 用户?](https://juejin.im/post/5ec4e7926fb9a0480067b602)([z0gSh1u](https://github.com/z0gSh1u) 翻译) +* [如何编写可节省您时间的日志文件](https://juejin.im/post/5edf8d636fb9a047cd65d136)([PingHGao](https://github.com/PingHGao) 翻译) +* [理解 zip 和 gzip 压缩格式背后的压缩算法](https://juejin.im/post/5ecb7f9651882542f4488845)([JohnieXu](https://github.com/JohnieXu) 翻译) +* [如何编写整洁代码?从 Robert C. Martin 的“代码整洁之道”中吸取的教训](https://juejin.im/post/5eb78370f265da7be959ffc2)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [如何在自己的计算机上模拟 UDP Flood DoS 攻击](https://juejin.im/post/5eb8fb09e51d4540bb6172e1)([chaingangway](https://github.com/chaingangway) 翻译) +* [Google Tag Manager 的真相大揭秘](https://juejin.im/post/5ea41a43f265da47c15cdc53)([zhanght9527](https://github.com/zhanght9527) 翻译) +* [开发者应该写博客的各种原因](https://juejin.im/post/5ea7eb586fb9a043867d4763)([PingHGao](https://github.com/PingHGao) 翻译) +* [如何成为一名优秀的远程开发者](https://juejin.im/post/5e9f9f64f265da47f0794a6e)([Baddyo](https://github.com/Baddyo) 翻译) +* [防止 Git 泄漏的 5 种最佳做法](https://juejin.im/post/5e9e971851882573b047541e)([YueYongDev](https://github.com/YueYongDev) 翻译) +* [“为什么”文档的重要性](https://juejin.im/post/5e9e2a876fb9a03c6e6438d5)([QinRoc](https://github.com/QinRoc) 翻译) +* [怎样让依赖库保持安全和最新](https://juejin.im/post/5e8efe65f265da47dd398a54)([chaingangway](https://github.com/chaingangway) 翻译) +* [云服务如何帮助你提高业务效率?](https://juejin.im/post/5e8d07a96fb9a03c73797cef)([QinRoc](https://github.com/QinRoc) 翻译) +* [作为 2020 年的开发者,你应该学习 VIM 吗?](https://juejin.im/post/5e8d3205518825737a314e58)([chaingangway](https://github.com/chaingangway) 翻译) +* [Git 的历史:软件版本控制的统治之路](https://juejin.im/post/5e69ce5af265da576e64b326)([fireairforce](https://github.com/fireairforce) 翻译) +* [2020 年要学习的 7 种编程语言和框架](https://juejin.im/post/5e663cec518825496e786051)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [如何写出优雅且有意义的 README.md](https://juejin.im/post/5e3a7363e51d452701795512)([cyz980908](https://github.com/cyz980908) 翻译) +* [再见,整洁的代码](https://juejin.im/post/5e2411e0f265da3e4244e683)([zh1an](https://github.com/zh1an) 翻译) +* [现在就该学习的 7 门现代编程语言](https://juejin.im/post/5e1e00fee51d4577794c04f8)([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) +* [如何为求职准备你的 GitHub](https://juejin.im/post/5e1310a8f265da5d7275de8e)([nettee](https://github.com/nettee) 翻译) +* [我个人的 Git 技巧备忘录](https://juejin.im/post/5e006ad4e51d45582248e63f)([Pingren](https://github.com/Pingren) 翻译) +* [如何确定团队工作的优先级](https://juejin.im/post/5de4fc675188252edd0e2828)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [为什么自己动手写代码能让你成为更好的开发者](https://juejin.im/post/5de88ed16fb9a016470c151a)([quzhen12](https://github.com/quzhen12) 翻译) +* [如何计划你的一天 —— 这里有一份攻略请查收](https://juejin.im/post/5db16664f265da4d4c201997)([todaycoder001](https://github.com/todaycoder001) 翻译) +* [设置 git 别名](https://juejin.im/post/5dafc502f265da5b783f1ae1)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [冲冠一怒为代码:论程序员与负能量](https://juejin.im/post/5d67540df265da039d32e0cc)([Baddyo](https://github.com/Baddyo) 翻译) +* [HTTP Security Headers 完整指南](https://juejin.im/post/5d648e766fb9a06b122f4ab4)([cyz980908](https://github.com/cyz980908) 翻译) +* [开源难题:如何保持长久](https://juejin.im/post/5db27be36fb9a02040687055)([lihanxiang](https://github.com/lihanxiang) 翻译) +* [作为初级开发人员,我没有学过的 7 个绝对真理](https://juejin.im/post/5d3d25dce51d457756536881)([cyz980908](https://github.com/cyz980908) 翻译) +* [Git:透过命令学概念 —— 第二部分](https://juejin.im/post/5d2da05ae51d45106b15ffca)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [npm 的经济风云 —— 上半部分](https://juejin.im/post/5d146225e51d4556db694a4b)([Baddyo](https://github.com/Baddyo) 翻译) +* [设计师如何成长为 Leader?](https://juejin.im/post/5d172fca6fb9a07eda032c6f)([TiaossuP](https://github.com/TiaossuP) 翻译) +* [敏捷也许是个问题](https://juejin.im/post/5d2dfb4ae51d45775f516b1e)([Charlo-O](https://github.com/Charlo-O) 翻译) +* [npm 的经济风云 —— 下半部分](https://juejin.im/post/5d2d9e7af265da1b8b2b91ca)([Baddyo](https://github.com/Baddyo) 翻译) +* [类(Class)与数据结构(Data Structures)](https://juejin.im/post/5d12efe7e51d455c8838e193)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Git:透过命令学概念 —— 第一部分](https://juejin.im/post/5d0b3c7ce51d4577531381e3)([Baddyo](https://github.com/Baddyo) 翻译) +* [10 分钟爆改终端](https://juejin.im/post/5d053fc56fb9a07ee85c283d)([lihaobhsfer](https://github.com/lihaobhsfer) 翻译) +* [剖析 Stack Overflow,开发者遇到最多的的 Bug 是哪些?](https://juejin.im/post/5d087a32518825403d14758b)([whatbeg](https://github.com/whatbeg) 翻译) +* [帮你高效使用 VS Code 的秘诀](https://juejin.im/post/5cd8fcedf265da03761eaa45)([Baddyo](https://github.com/Baddyo) 翻译) +* [我们从招聘技术经理的过程中学到了什么](https://juejin.im/post/5cdcf463f265da0392580820)([JackEggie](https://github.com/JackEggie) 翻译) +* [最优控制:LQR](https://juejin.im/post/5cdfe49c6fb9a07eee5e9de6)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [Commit 提交指南](https://juejin.im/post/5ccf9e60f265da039c05659d)([Mirosalva](https://github.com/Mirosalva) 翻译) +* [如何避免我作为初级开发者时所犯下的 7 个错误](https://juejin.im/post/5cbea729e51d456e8240dcfa)([whatbeg](https://github.com/whatbeg) 翻译) +* [你不能成为成功程序员的 10 个迹象](https://juejin.im/post/5ca2f5ce51882565cb5b962c)([xionglong58](https://github.com/xionglong58) 翻译) +* [浏览器帧原理剖析](https://juejin.im/post/5c9c66075188251dab07413d)([WangLeto](https://github.com/WangLeto) 翻译) +* [开源是无法赚钱的,因为开源本身就不是为了赚钱](https://juejin.im/post/5c998753e51d456ef105ac1e)([kasheemlew](https://github.com/kasheemlew) 翻译) +* [如何心平气和的阅读代码](https://juejin.im/post/5c9c521b5188252d876e5dcb)([Mcskiller](https://github.com/Mcskiller) 翻译) +* [修改 Git 错误的高明方法](https://juejin.im/post/5c735a235188256262174e48)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [如何写一篇软件工程必杀简历](https://juejin.im/post/5c6ca8b9f265da2dc13c7a10)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [提高营销效率的工程(第一部分)](https://juejin.im/post/5c403b5ce51d452c8e6d3dc4)([Starriers](https://github.com/Starriers) 翻译) +* [讨论 JS ⚡:文档](https://juejin.im/post/5c4039bbe51d4551733494a6)([Starriers](https://github.com/Starriers) 翻译) +* [我无法想象没有 Git 别名的的场景](https://juejin.im/post/5c207bd4e51d452b7b032cf6)([Starriers](https://github.com/Starriers) 翻译) +* [三人研发小组的高效研发尝试](https://juejin.im/post/5c19d1846fb9a049f06a33fc)([yuwhuawang](https://github.com/yuwhuawang) 翻译) +* [理解编译器 — 从人类的角度(版本 2)](https://juejin.im/post/5c10b2f6e51d452ad958631f)([Starriers](https://github.com/Starriers) 翻译) +* [深度专注的工作 — 成为 10 倍效率的开发者的秘密武器](https://juejin.im/post/5bffb3f5f265da613a53bd4b)([tmpbook](https://github.com/tmpbook) 翻译) +* [如何让高效的代码评审成为一种文化](https://juejin.im/post/5bfc9ff9e51d454b6c371f5d)([CoolRice](https://github.com/CoolRice) 翻译) +* [在远程工作中领悟到的 10 件事](https://juejin.im/post/5bf7a79f51882511a8528cf0)([Starriers](https://github.com/Starriers) 翻译) +* [职业成长的内部指南](https://juejin.im/post/5bd722a65188252dd11662af)([yuwhuawang](https://github.com/yuwhuawang) 翻译) +* [6 个最令人满意的和编程相关的工作(和参与这些工作的人们的类型)](https://juejin.im/post/5be271f0e51d450556196864)([Augustwuli](https://github.com/Augustwuli) 翻译) +* [作为自由开发者,7 个步骤让你获得更多的客户](https://juejin.im/post/5bd660c26fb9a05ce576e9b7)([rydensun](https://github.com/rydensun) 翻译) +* [C++ 协程:理解运算符 co_await](https://juejin.im/post/5bee59a1e51d4545453dc558)([7Ethan](https://github.com/7Ethan) 翻译) +* [代码评审的 8 点建议](https://juejin.im/post/5bd1e6696fb9a05d096597c6)([xiaoxi666](https://github.com/xiaoxi666) 翻译) +* [如何组织 Hacktoberfest 主题聚会](https://juejin.im/post/5bbc150be51d450e6867be7a)([jianboy](https://github.com/jianboy) 翻译) +* [下一代包管理工具](https://juejin.im/post/5ba9830fe51d450e4d2fe208)([diliburong](https://github.com/diliburong) 翻译) +* [新手开发者须知](https://juejin.im/post/5bade6a76fb9a05d32515cf0)([ssshooter](https://github.com/ssshooter) 翻译) +* [用 Workers 让静态网站动态化](https://juejin.im/post/5b95c5375188255c6e70422a)([MeFelixWang](https://github.com/MeFelixWang) 翻译) +* [关于工程师和影响力](https://juejin.im/post/5b8f9a96f265da0ab33125b0)([cf020031308](https://github.com/cf020031308) 翻译) +* [如何像程序员般思考 —— 蕴含在问题解决中的经验](https://juejin.im/post/5b76839ae51d4566491c24bb)([mingxing47](https://github.com/mingxing47) 翻译) +* [编程语言和平台:一条被评论的推文串](https://juejin.im/post/5b4c2b75e51d45195b336d57)([cf020031308](https://github.com/cf020031308) 翻译) +* [为 GitHub 项目做出贡献的初学者指南](https://juejin.im/entry/5b2e58ba6fb9a00e4966ee4b)([sophiayang1997](https://github.com/sophiayang1997) 翻译) +* [怎样(以及为什么要)保持你的 Git 提交记录的整洁](https://juejin.im/post/5b29060ee51d4558cd2adac0)([zhongdeming428](https://github.com/zhongdeming428) 翻译) +* [关于你的编程生涯的一些告诫](https://juejin.im/post/5b0256e36fb9a07aa767f5b4)([kezhenxu94](https://github.com/kezhenxu94) 翻译) +* [部署!=发布(第二部分)](https://juejin.im/post/5b00d2fa6fb9a07a9a1120e9)([Starriers](https://github.com/Starriers) 翻译) +* [如何逃离 async/await 地狱](https://juejin.im/post/5aefbb48f265da0b9b073c40)([Colafornia](https://github.com/Colafornia) 翻译) +* [我在编程初级阶段常犯的错误](https://juejin.im/post/5ae97af6f265da0ba062f797)([kezhenxu94](https://github.com/kezhenxu94) 翻译) +* [Deploy != Release(第一部分):Deploy 与 Release 的区别及为什么很重要?](https://juejin.im/post/5ad80983f265da505c3c1b3a)([stormluke](https://github.com/stormluke) 翻译) +* [引导员手册:24 个设计冲刺技巧](https://juejin.im/post/5ae3254d6fb9a07abc29a741)([PokerF](https://github.com/PokerF) 翻译) +* [简短而又完全精确的编程语言历史](https://juejin.im/post/5ac1b8a25188255c637b1cd5)([Starriers](https://github.com/Starriers) 翻译) +* [让 Apache Cassandra 尾部延迟减小 10 倍(已开源)](https://juejin.im/post/5ac31083f265da239a5fff0c)([stormluke](https://github.com/stormluke) 翻译) +* [良好的编码习惯 — 5 个提高代码质量的技巧](https://juejin.im/post/5abc584251882555867f7f1e)([NeoyeElf](https://github.com/NeoyeElf) 翻译) +* [如何修改域名来提高国际增长率](https://juejin.im/post/5aaf0542f265da239530c653)([Starriers](https://github.com/Starriers) 翻译) +* [不要害怕 Rebase](https://juejin.im/post/5ab1bdbe518825556e5df5f8)([sqrthree](https://github.com/sqrthree) 翻译) +* [开启你的开源生涯](https://juejin.im/post/5a5c029d51882573432d21ff)([zwwill](https://github.com/zwwill) 翻译) +* [自动化持续集成/持续分发,以节省更多时间编写代码](https://juejin.im/post/5a44aab86fb9a044ff31c418)([NeilLi1992](https://github.com/NeilLi1992) 翻译) +* [为什么我们从来不去感谢开源项目维护者](https://juejin.im/post/5a40c20b518825696f7e3c23)([leviding](https://github.com/leviding) 翻译) +* [五天拿下硅谷五家顶级互联网公司 offer](https://juejin.im/post/5a1247d26fb9a0452a3bec33)([freerambo](https://github.com/freerambo) 翻译) +* [为什么我还没 Fix 你的 Issue](https://juejin.im/post/59950fd9f265da248535b46d?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([leviding](https://github.com/leviding) 翻译) +* [Chrome 开发者工具提示和技巧](http://gold.xitu.io/entry/56d56f4dc4c971005193ecec?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([chemzqm](https://github.com/chemzqm) 翻译) +* [通过 Electron 开发一个简单的桌面应用](http://gold.xitu.io/entry/56aae5e4a633bd0257ae4ab8?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangdroid](https://github.com/Zhangdroid) 翻译) +* [Retrofit 入门教程](http://gold.xitu.io/entry/56cc4085128fe100580dd0ca?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([kevin xiu](https://github.com/xiuweikang) 翻译) +* [Pokedex.org 给宠物小精灵爱好者的 web app 的技术选型](http://gold.xitu.io/entry/56cebb8edf0eea79dc7c1ff0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([RobertWang](https://github.com/RobertWang) 翻译) diff --git a/product.md b/product.md index 2a569b69b2a..a152e10e25b 100644 --- a/product.md +++ b/product.md @@ -1,54 +1,57 @@ -* [利用 84 种认知偏见设计更好的产品 —— 第二部分](https://juejin.im/post/5d37e1816fb9a07ee1696a4e) ([JalanJiang](https://github.com/JalanJiang) 翻译) -* [利用 84 种认知偏见设计更好的产品 —— 第一部分](https://juejin.im/post/5d2acf995188254c1915bd12) ([JalanJiang](https://github.com/JalanJiang) 翻译) -* [制定良好的路线图:产品负责人的六个实施步骤](https://juejin.im/post/5cb299436fb9a068744e70a7) ([QiaoN](https://github.com/QiaoN) 翻译) -* [2019 版 web 浏览器现状](https://juejin.im/post/5c89e69a51882536fe67b5b4) ([xionglong58](https://github.com/xionglong58) 翻译) -* [产品管理思维模式适合每一个人](https://juejin.im/post/5c2c266ae51d4511fb7db0c7) ([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) -* [苹果公司如何颠覆瑞士制表业](https://juejin.im/post/5bdc1f3c6fb9a049a9792211) ([noturnot](https://github.com/noturnot) 翻译) -* [如何让你的设计系统被广泛采用](https://juejin.im/post/5bb6118af265da0af609c581) ([rydensun](https://github.com/rydensun) 翻译) -* [如果界面产品设计师设计实体产品](https://juejin.im/post/5baf9697e51d456f087ba2a8) ([ssshooter](https://github.com/ssshooter) 翻译) -* [四个「为什么」:是什么在背后驱动你的产品?](https://juejin.im/post/5bac279cf265da0adc18d31a) ([pmwangyang](https://github.com/pmwangyang) 翻译) -* [为 APP 设计通知提醒](https://juejin.im/post/5ba31ee3e51d450e4115500b) ([rydensun](https://github.com/rydensun) 翻译) -* [虚构问题,低质量软件的根源](https://juejin.im/post/5b65122be51d4517c564d54f) ([ssshooter](https://github.com/ssshooter) 翻译) -* [关于 HomePod WWDC 的愿望清单: 测试版程序、新的语音资源、Echo 等功能](https://juejin.im/post/5b14ff08f265da6e1a602e26) ([dandyxu](https://github.com/dandyxu) 翻译) -* [watchOS 5 愿望清单:Apple Watch Podcasts、open Siri face 和更新 Control Center 等](https://juejin.im/post/5b15045bf265da6e6039372b) ([talisk](https://github.com/talisk) 翻译) -* [WWDC 2018:关于iOS 12、iPad Pro、新MacBooks或者更多产品的所有预测](https://juejin.im/post/5b056d485188256710601ecc) ([dandyxu](https://github.com/dandyxu) 翻译) -* [预测你的游戏的货币化未来](https://juejin.im/post/5ad1d3b6f265da238f12fafa) ([NoName4Me](https://github.com/NoName4Me) 翻译) -* [用行为经济学来传达付费应用订阅的价值](https://juejin.im/post/5ad3ffd0f265da23906c785f) ([ALVINYEH](https://github.com/ALVINYEH) 翻译) -* [怎样把取消订阅的用户吸引回来](https://juejin.im/post/5acc1538518825651d07fdd1) ([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) -* [游戏即服务的五条建议,提升游戏变现能力](https://juejin.im/post/5aa88773f265da23a228cc49) ([pthtc](https://github.com/pthtc) 翻译) -* [一文教你预测 APP 未来的货币化情况](https://juejin.im/post/5a7a94d36fb9a0634d2793c6) ([pthtc](https://github.com/pthtc) 翻译) -* [知己知彼 — 谁在玩你的手机游戏?](https://juejin.im/post/5a960dfcf265da4e853d876b) ([laiyun90](https://github.com/laiyun90) 翻译) -* [如果你想让用户回来,为什么前十分钟是至关重要的?](https://juejin.im/entry/5a7fe27f5188257a6854ce6a) ([sunshine940326](https://github.com/sunshine940326) 翻译) -* [我是如何在谷歌做开发者的用户体验的](https://juejin.im/post/59a785d46fb9a02493222d77?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laiyun90](https://github.com/laiyun90) 翻译) -* [如果你的产品停止成长,你该怎么做?](https://juejin.im/post/5985935c518825261a2d222f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([funtrip](https://github.com/funtrip) 翻译) -* [针对失败者的体验设计](https://juejin.im/post/59013f6eda2f60005de40516/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译) -* [细节是产品设计的重中之重](https://juejin.im/post/58ed96aaa22b9d00634732e9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) -* [单元测试,精益创业,以及两者之间的关系](https://juejin.im/post/58d90a3b44d90400694505c4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译) -* [你正在阅读的用户体验文章是不是在向你进行推销?](https://juejin.im/post/58d4c501a22b9d00645544d9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译) -* [直观设计 vs. 共享式设计](https://gold.xitu.io/entry/5862650a128fe1006d04d398/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Funtrip](https://www.behance.net/Funtrip) 翻译) -* [为何而设计?](https://gold.xitu.io/entry/5857969761ff4b00686ad66b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译) -* [如何建立高效推送通知](https://gold.xitu.io/entry/5856427d61ff4b0063badca2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([phxnirvana](https://github.com/phxnirvana) 翻译) -* [关于程序员被要求做不道德甚至非法的事情的激烈讨论](https://gold.xitu.io/entry/584c122c61ff4b006cc6df53?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([phxnirvana](https://github.com/phxnirvana) 翻译) -* [如何设计精准的推送通知?](http://gold.xitu.io/entry/58199acca22b9d0067a34821?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([laobie](https://github.com/laobie) 翻译) -* [减少认知过载可以为用户带来更佳体验](http://gold.xitu.io/entry/58007345816dfa0056e8ff5c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [为什么用户体验最重要!最重要!最重要!](http://gold.xitu.io/entry/57e388ef5bbb50005d3c97d9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) -* [如何给你的产品写文案?](http://gold.xitu.io/entry/57d3a12067f3560057d58eba?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [开发移动应用,你应该注意这些小细节](http://gold.xitu.io/entry/57d2d60667f3560057d0cd85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([mypchas6fans](https://github.com/mypchas6fans) 翻译) -* [人们为什么会打开你的营销电子邮件?](http://gold.xitu.io/entry/57d170f82e958a00544ebf7c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Deadlion](https://github.com/Deadlion) 翻译) -* [给 UX 设计师的 6 个超实用技巧指南](http://gold.xitu.io/entry/57c6e4bb128fe1005fe80c95?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/Kulbear) 翻译) -* [该叫「我的电脑」还是「你的电脑」?](http://gold.xitu.io/entry/57bbc0212e958a00694055a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) -* [用户体验设计的未来](http://gold.xitu.io/entry/57b875ae79bc44005b9c53d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Kulbear](https://github.com/Kulbear) 翻译) -* [我不是用户体验设计师,你呢?](http://gold.xitu.io/entry/57b680250a2b58005c8217f7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) -* [产品设计怎样做才最优雅](http://gold.xitu.io/entry/57b14ce45bbb500062d9a51f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lizwangying](https://github.com/lizwangying) 翻译) -* [在开发移动应用时你应该考虑的 「Empty State」](http://gold.xitu.io/entry/579f19956be3ff0065f59a90?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) -* [电商列表信息展示,你真的懂吗?](http://gold.xitu.io/entry/575cd2f31532bc00608d241c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([godofchina](https://github.com/godofchina) 翻译) -* [无限下拉,还是分页?](http://gold.xitu.io/entry/573e978171cfe448aa9dd03db?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Ruixi](https://github.com/Ruixi) 翻译) -* [给产品经理的简易优先级法则](http://gold.xitu.io/entry/572ad1cc1532bc0065d5e36b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhaofengWu](https://github.com/ZhaofengWu) 翻译) -* [设计师如何跟开发打好关系?](http://gold.xitu.io/entry/57286f4f2e958a00657d2450?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([L9m](https://github.com/L9m) 翻译) -* [为什么 Spotify 的付费转化率比 Dropbox 高了 667%](http://gold.xitu.io/entry/57232041f38c8400599ef706?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SatanWoo](https://github.com/SatanWoo)翻译) -* [新的 “增长黑客” 实践 —— 构建用户社区](http://gold.xitu.io/entry/5721e80cf38c84005992097e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhongyi Tong](https://github.com/geeeeeeeeek)翻译) -* [互联网公司真的是「看重能力,不看重学历」吗?](http://gold.xitu.io/entry/571d8e4c8ac24700646f30ae?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [产品设计实习生面试指南](http://gold.xitu.io/entry/5715b102c4c971005bdc93e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iThreeKing](https://github.com/iThreeKing) 翻译) -* [你真的懂病毒式营销吗](http://gold.xitu.io/entry/5715d39cdf0eea005c930d80?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([huanglizhuo](https://github.com/huanglizhuo) 翻译) -* [什么是产品设计?](http://gold.xitu.io/entry/570b6a6a75c4cd3c3b917bd0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Zhangjd](https://github.com/zhangjd) 翻译) -* [产品文案要说人话](http://gold.xitu.io/entry/56ee4903c4c971005182e017?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iThreeKing](https://github.com/iThreeKing) 翻译) +* [算法不是产品](https://juejin.im/post/5e398e806fb9a07cb52bb462)([fireairforce](https://github.com/fireairforce) 翻译) +* [利用 84 种认知偏见设计更好的产品 —— 第三部分](https://juejin.im/post/5d568c9ce51d453bc64801cd)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [想帮助用户做决定?你的 APP 可以这样设计!](https://juejin.im/post/5a7194986fb9a01c9f5bbbb2)([pthtc](https://github.com/pthtc) 翻译) +* [利用 84 种认知偏见设计更好的产品 —— 第二部分](https://juejin.im/post/5d37e1816fb9a07ee1696a4e)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [利用 84 种认知偏见设计更好的产品 —— 第一部分](https://juejin.im/post/5d2acf995188254c1915bd12)([JalanJiang](https://github.com/JalanJiang) 翻译) +* [制定良好的路线图:产品负责人的六个实施步骤](https://juejin.im/post/5cb299436fb9a068744e70a7)([QiaoN](https://github.com/QiaoN) 翻译) +* [2019 版 web 浏览器现状](https://juejin.im/post/5c89e69a51882536fe67b5b4)([xionglong58](https://github.com/xionglong58) 翻译) +* [产品管理思维模式适合每一个人](https://juejin.im/post/5c2c266ae51d4511fb7db0c7)([EmilyQiRabbit](https://github.com/EmilyQiRabbit) 翻译) +* [苹果公司如何颠覆瑞士制表业](https://juejin.im/post/5bdc1f3c6fb9a049a9792211)([noturnot](https://github.com/noturnot) 翻译) +* [如何让你的设计系统被广泛采用](https://juejin.im/post/5bb6118af265da0af609c581)([rydensun](https://github.com/rydensun) 翻译) +* [如果界面产品设计师设计实体产品](https://juejin.im/post/5baf9697e51d456f087ba2a8)([ssshooter](https://github.com/ssshooter) 翻译) +* [四个「为什么」:是什么在背后驱动你的产品?](https://juejin.im/post/5bac279cf265da0adc18d31a)([pmwangyang](https://github.com/pmwangyang) 翻译) +* [为 APP 设计通知提醒](https://juejin.im/post/5ba31ee3e51d450e4115500b)([rydensun](https://github.com/rydensun) 翻译) +* [虚构问题,低质量软件的根源](https://juejin.im/post/5b65122be51d4517c564d54f)([ssshooter](https://github.com/ssshooter) 翻译) +* [关于 HomePod WWDC 的愿望清单: 测试版程序、新的语音资源、Echo 等功能](https://juejin.im/post/5b14ff08f265da6e1a602e26)([dandyxu](https://github.com/dandyxu) 翻译) +* [watchOS 5 愿望清单:Apple Watch Podcasts、open Siri face 和更新 Control Center 等](https://juejin.im/post/5b15045bf265da6e6039372b)([talisk](https://github.com/talisk) 翻译) +* [WWDC 2018:关于iOS 12、iPad Pro、新MacBooks或者更多产品的所有预测](https://juejin.im/post/5b056d485188256710601ecc)([dandyxu](https://github.com/dandyxu) 翻译) +* [预测你的游戏的货币化未来](https://juejin.im/post/5ad1d3b6f265da238f12fafa)([NoName4Me](https://github.com/NoName4Me) 翻译) +* [用行为经济学来传达付费应用订阅的价值](https://juejin.im/post/5ad3ffd0f265da23906c785f)([ALVINYEH](https://github.com/ALVINYEH) 翻译) +* [怎样把取消订阅的用户吸引回来](https://juejin.im/post/5acc1538518825651d07fdd1)([allenlongbaobao](https://github.com/allenlongbaobao) 翻译) +* [游戏即服务的五条建议,提升游戏变现能力](https://juejin.im/post/5aa88773f265da23a228cc49)([pthtc](https://github.com/pthtc) 翻译) +* [一文教你预测 APP 未来的货币化情况](https://juejin.im/post/5a7a94d36fb9a0634d2793c6)([pthtc](https://github.com/pthtc) 翻译) +* [知己知彼 — 谁在玩你的手机游戏?](https://juejin.im/post/5a960dfcf265da4e853d876b)([laiyun90](https://github.com/laiyun90) 翻译) +* [如果你想让用户回来,为什么前十分钟是至关重要的?](https://juejin.im/entry/5a7fe27f5188257a6854ce6a)([sunshine940326](https://github.com/sunshine940326) 翻译) +* [我是如何在谷歌做开发者的用户体验的](https://juejin.im/post/59a785d46fb9a02493222d77?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laiyun90](https://github.com/laiyun90) 翻译) +* [如果你的产品停止成长,你该怎么做?](https://juejin.im/post/5985935c518825261a2d222f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([funtrip](https://github.com/funtrip) 翻译) +* [针对失败者的体验设计](https://juejin.im/post/59013f6eda2f60005de40516/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ylq167](https://github.com/ylq167) 翻译) +* [细节是产品设计的重中之重](https://juejin.im/post/58ed96aaa22b9d00634732e9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iloveivyxuan](https://github.com/iloveivyxuan) 翻译) +* [单元测试,精益创业,以及两者之间的关系](https://juejin.im/post/58d90a3b44d90400694505c4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([gy134340](http://gy134340.com/) 翻译) +* [你正在阅读的用户体验文章是不是在向你进行推销?](https://juejin.im/post/58d4c501a22b9d00645544d9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ylq167](https://github.com/ylq167) 翻译) +* [直观设计 vs. 共享式设计](https://gold.xitu.io/entry/5862650a128fe1006d04d398/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Funtrip](https://www.behance.net/Funtrip) 翻译) +* [为何而设计?](https://gold.xitu.io/entry/5857969761ff4b00686ad66b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([王子建](https://github.com/Romeo0906) 翻译) +* [如何建立高效推送通知](https://gold.xitu.io/entry/5856427d61ff4b0063badca2?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([phxnirvana](https://github.com/phxnirvana) 翻译) +* [关于程序员被要求做不道德甚至非法的事情的激烈讨论](https://gold.xitu.io/entry/584c122c61ff4b006cc6df53?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([phxnirvana](https://github.com/phxnirvana) 翻译) +* [如何设计精准的推送通知?](http://gold.xitu.io/entry/58199acca22b9d0067a34821?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([laobie](https://github.com/laobie) 翻译) +* [减少认知过载可以为用户带来更佳体验](http://gold.xitu.io/entry/58007345816dfa0056e8ff5c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [为什么用户体验最重要!最重要!最重要!](http://gold.xitu.io/entry/57e388ef5bbb50005d3c97d9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Nicolas(Yifei) Li](https://github.com/yifili09) 翻译) +* [如何给你的产品写文案?](http://gold.xitu.io/entry/57d3a12067f3560057d58eba?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [开发移动应用,你应该注意这些小细节](http://gold.xitu.io/entry/57d2d60667f3560057d0cd85?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([mypchas6fans](https://github.com/mypchas6fans) 翻译) +* [人们为什么会打开你的营销电子邮件?](http://gold.xitu.io/entry/57d170f82e958a00544ebf7c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Deadlion](https://github.com/Deadlion) 翻译) +* [给 UX 设计师的 6 个超实用技巧指南](http://gold.xitu.io/entry/57c6e4bb128fe1005fe80c95?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/Kulbear) 翻译) +* [该叫「我的电脑」还是「你的电脑」?](http://gold.xitu.io/entry/57bbc0212e958a00694055a9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([jiaowoyongqi](https://github.com/jiaowoyongqi) 翻译) +* [用户体验设计的未来](http://gold.xitu.io/entry/57b875ae79bc44005b9c53d5?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Kulbear](https://github.com/Kulbear) 翻译) +* [我不是用户体验设计师,你呢?](http://gold.xitu.io/entry/57b680250a2b58005c8217f7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) +* [产品设计怎样做才最优雅](http://gold.xitu.io/entry/57b14ce45bbb500062d9a51f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([lizwangying](https://github.com/lizwangying) 翻译) +* [在开发移动应用时你应该考虑的 「Empty State」](http://gold.xitu.io/entry/579f19956be3ff0065f59a90?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([MAYDAY1993](https://github.com/MAYDAY1993) 翻译) +* [电商列表信息展示,你真的懂吗?](http://gold.xitu.io/entry/575cd2f31532bc00608d241c?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([godofchina](https://github.com/godofchina) 翻译) +* [无限下拉,还是分页?](http://gold.xitu.io/entry/573e978171cfe448aa9dd03db?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Ruixi](https://github.com/Ruixi) 翻译) +* [给产品经理的简易优先级法则](http://gold.xitu.io/entry/572ad1cc1532bc0065d5e36b?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([ZhaofengWu](https://github.com/ZhaofengWu) 翻译) +* [设计师如何跟开发打好关系?](http://gold.xitu.io/entry/57286f4f2e958a00657d2450?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([L9m](https://github.com/L9m) 翻译) +* [为什么 Spotify 的付费转化率比 Dropbox 高了 667%](http://gold.xitu.io/entry/57232041f38c8400599ef706?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([SatanWoo](https://github.com/SatanWoo) 翻译) +* [新的 “增长黑客” 实践 —— 构建用户社区](http://gold.xitu.io/entry/5721e80cf38c84005992097e?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhongyi Tong](https://github.com/geeeeeeeeek) 翻译) +* [互联网公司真的是「看重能力,不看重学历」吗?](http://gold.xitu.io/entry/571d8e4c8ac24700646f30ae?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [产品设计实习生面试指南](http://gold.xitu.io/entry/5715b102c4c971005bdc93e9?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iThreeKing](https://github.com/iThreeKing) 翻译) +* [你真的懂病毒式营销吗](http://gold.xitu.io/entry/5715d39cdf0eea005c930d80?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([huanglizhuo](https://github.com/huanglizhuo) 翻译) +* [什么是产品设计?](http://gold.xitu.io/entry/570b6a6a75c4cd3c3b917bd0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([Zhangjd](https://github.com/zhangjd) 翻译) +* [产品文案要说人话](http://gold.xitu.io/entry/56ee4903c4c971005182e017?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([iThreeKing](https://github.com/iThreeKing) 翻译)