分类目录归档:前端

JavaScript 异步流程控制的知识点整理

在写信息管理系统的时候,经常需要等待前面的任务执行完,比如最常见的Ajax请求后做弹窗提示,又或者是多个Ajax需要并行/串行执行操作等。

因为JS是单线程语言,所以在整个执行环境都依靠EventLoop。因此,实现异步除了最基本的Callback回调函数,社区还开发了Promise、Async/Await等语法糖或者库,我写一篇文章整理一下工作以来接触到的异步知识

Callback 回调函数

异步控制接触最早的,其实就是这个Callback回调函数,代码示例如下

// JQuery的Ajax请求
$.ajax({
   url: '/api/system/login',
   params: {},
   success: () ={
      console.log('在异步Ajax请求成功之后,会调用到此回调函数');
   }
});

// setTimeout/setInterval绑定回调函数
setTimeout(()={
    console.log('两秒之后会调用到此函数');
},2000)

// Node.js 经常的回调函数以及传参
var fs = require('fs');

fs.readFile('test.txt', 'utf-8', function(err, data) {
    // 这里同样绑定了回调函数,Node.js设计一般第一个参数是err,第二个参数是data数据等
    if(err) 

Redux数据流框架介绍,构建易维护的单向数据流

React本身是一个View层,尽管借助prop属性和事件,能够完成父子组件之间的通信,但是在一个逻辑复杂的系统里,往往DOM的层次很深,如果每一层都传递一遍prop,开发效率就会有所下降。

这个时候,我们需要有一个专门管理数据流的框架来处理——Redux,通过Store/Dispatch/Reducers等概念,将整个数据流进行抽象。除此之外,还能加一些中间件(middleware)来进行拦截操作。下面我整理一下我使用Redux以来的一些知识点

1, 安装Redux依赖

基础框架可以使用我的开源仓库https://github.com/tun100/webpack-configure-react,并且在package.json里添加以下依赖,并且执行命令cnpm i -S -D

    "react-redux": "^5.0.5",
    "redux": "^3.7.2",
    "redux-saga": "^0.15.6",

2,最简单的Redux配置

首先,在import顶部增加以下代码

import React, { useEffect, useState, useContext, PureComponent, Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider, connect } from "react-redux";
import { 

使用Babel的AST功能,来智能分析处理源码

在重构时,往往会遇到一些不合理的代码需要被批量替换。这种需求一般的全文替换是可以的,但是如果要根据文件名、变量名动态的进行智能替换,而且被替换的代码块格式不一,这时还有什么方式?正则是一个办法,但是还有没有别的方法可以尝试呢?

有的!之前在重构某些项目时,有许多属性需要批量替换,但是我希望能加入一些逻辑判断、和一些其他变量的状态获取。在查询许多资料之后,除了正则+脚本,还有Babel能帮我解决这个问题

Babel

我们一般前端开发是用Babel来转换新语法,然而它的API也能让你来自定义转换源码。这个API就是将你的源码转换成AST(Abstract Syntax Tree)抽象语法树。能实现AST转换的其实不止Babel一家,在Babel之前还有Esprima等。只不过我们大部分用的都是Babel,为了和.babelrc语法一致,所以我更推荐使用Babel来进行AST转换

AST(抽象语法树)

维基百科:在计算机科学中,抽象语法树(AST),或简称语法树,是用编程语言编写的源代码的抽象语法结构的树表示。树的每个节点表示源代码中出现的一个构造。

例如:Program -[Code1 ,Code2],同时Code1又包含
VariableDeclaration(变量定义)、CallExpression(函数定义)等,在函数内又有许多语法在其中。这么一看,是不是很像一颗树呢?有树层次、节点关系等^_^。然后实践的过程中,只要我们增减其中的节点,或者是修改节点的属性值,再将AST转换成源码,这样就可以很轻松的达到“智能转换代码”的功能了!

学习资料

官方手册:
https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/README.md

AST Explorer(在线解析语法AST):https://astexplorer.net/

维基百科定义:https://en.wikipedia.org/wiki/Abstract_syntax_tree

具体实践

只是给出几个定义感觉不直观,让我们直接上手AST吧!相信AST能让你今后的重构或者代码调整,能够如虎添翼,这并不是奇巧淫技,而是真正提升你效率的一个利器!下面列出一个Github仓库,这是我实际用AST进行转换的例子:

Github仓库:
https://github.com/tun100/ReplaceContentByBabelAST

实际需求:

替换前文件
替换后文件

我们现在需要拿到{form.getFieldDecorator(‘myname’, {})}的“myname”字符串,这是定义form的prop值的。然后对Form.Item的label需要改为传递<ErrorTooltip>

一般正则是可以使用,但是AST也可以帮助你实现这个功能,让我们打开index.js这个文件

index.js文件概览

在进行AST处理时,我们会通过core.parse得到一颗树。那么我们怎么去遍历,去拿到这个值呢?这时候会用到traverse这个函数,通过这个函数,它可以帮你遍历所有的节点,如果你判断当前的tree node符合你的条件,那么就立刻进行处理,如下图:

具体解析转换代码

在语法树中,每个节点都有自己的定义,比如:节点是什么语法,带有什么属性,自身是什么值,在自己语法下还有没有更深层次的子树存在。那么这些节点具体有哪些属性,我应该怎么知道呢?

其实有一个很快捷的方式,就是把你的代码拷贝到 https://astexplorer.net (如果不放心可以clone它的仓库,在本地运行,不过我检查过不会有隐私问题),然后在菜单顶部选择babylon7,这样右侧就会有你想要的各个节点的属性和之间的关系

AST-Explorer具体使用

手动配置webpack 4.x,定义属于自己的脚手架

概述

webpack作为一个构建工具是非常优秀的,提供了多页面、Plugin、Loader等功能,而且还有基于webpack的零配置工具(如create-react-app)等。在webpack应用如此广泛的情况下,我觉得有必要深入了解webpack并从零开始配置,因为至少出了问题能很快的找到异常配置并快速修改好。之前搭建webpack也好多次了,但是没有进行总结。这次决定从头开始搭建,然后边操作边记录

之前还用过Parcel等新秀解决方案,它讲究的是零配置,用过在一些小项目上,但貌似还不太稳定,经常会出编译错误,所以又跑回了webpack的怀抱^_^

测试环境

Node.js: 8.14.0

Npm: 6.4.1

已搭建好环境的仓库

为了方便随时Clone出webpack编译环境,我把最终环境部署在Github仓库上了,
地址是:https://github.com/tun100/webpack-basic-frame

依赖初始化

npm init -y

然后将下面的依赖信息添加到package.json(因为不同依赖版本的差异,容易导致bug,如果使用我的这个依赖,我确信肯定能构建环境成功^_^),在添加成功之后执行npm i -S && npm i -D

   "scripts": {
     "dev": "npx webpack-dev-server --config ./webpack.dev.config.js --progress --profile --colors --watch --mode development",
     "dist": "npx webpack --config 

【React快速学习一】基础JSX语法和生命周期

学习React也有近两年多的时间,因为一些知识点用久了容易忘记,决定找空闲时间整理下自己理解的React知识文章,顺便做一下总结!😀

什么是React

React不同于以往的JQuery+BootStrap,它是一个简单的View层框架,搭配上周边生态(Redux/Mobx/ReactRouter等),就能构建起各种逻辑复杂的系统。

我所理解的React框架具备以下特点:

1.,使用JSX语法

借助该语法,可以在JavaScript文件里混编类似HTML的代码,不仅支持原生H5标签,还可以支持用户自定义的React组件,该语法风格如下:

let Clock = () =<divthis is clock</div// 此处渲染了一个React组件
ReactDOM.render(
    <Clock/,
    document.querySelector('#root')
);

2,采用VirtualDOM优化渲染性能

浏览器内核有JS引擎和渲染引擎,每当JS手工去操作DOM树的时候,往往会引起Repaint或者Reflow,这个操作会比较耗时,从而导致页面性能不佳

于是,开源社区想出了一个VirtualDOM的解决方案。使用JavaScript来虚拟定义一个DOM树,并且更新之前会对虚拟DOM节点进行比较,React会根据比较结果,只会部分更新所需的DOM节点,减少了不必要的渲染工作

不仅React,还有Vue等框架也采用了VirtualDOM diff算法,思想都是大同小异,下面是相关代码说明

// 在React里,VirtualDOM定义的元素格式如下
{
  type: "div",
  props: null,
  children: [{type: "text", props: {textContent: "Hello"}}]

使用Lodash编写安全、高效、优雅的JavaScript应用

在编写JS应用时,相信很多开发者会遇到“Uncaught TypeError: Cannot read property ‘prop’ of null” ,这种情况一般是没有做安全预判断。然而如果每一处都要加 obj != null && obj != undefined,不仅编写繁琐,也让代码的信噪比降低

为了让应用safety first,同时编写代码能够优雅高效,JS社区终于出现了一个瑞士军刀–Lodash。它的前身其实是underscore,这个和Lodash的概念差不多,其实API有点不一致而已,我主要介绍以下Lodash^_^

Lodash使用非常简单,你只需要记住它的变量是_就可以了(下划线)。在Lodash的编程哲学里,安全是第一的,而且融入了函数式编程。通过使用Lodash,你能感觉到它所有的API都可以大幅度减少无用的代码,让你的JS应用从1000行减到200行。我相信你会喜欢Lodash,而且在使用的过程中会逐渐理解贯彻它的编程哲学的

使用资料

Lodash官方仓库:
https://github.com/lodash/lodash

Lodash参考文档:
https://www.css88.com/doc/lodash/#_bindfunc-thisarg-partials

API简介

你在使用Lodash一段时间会发现,_.map既可以用在Object也可以用在Array,_.pickBy可以过滤Object不需要的key值,同时哪怕你传进去是null/undefined/NaN,Lodash也不会直接报错中断当前执行,而且返回一个空的结果(数字0,空数组,空对象等),可以确保你不会收到异常的情况。

在Lodash一些方法,比如_.difference,_.differenceBy, _.differenceWith,它们分别是默认处理函数,提供指定属性或者函数结果值来判断,手动编写compartor来进行判断

接下来,我介绍一些常用的API和它们的用途,其他的API如果感兴趣可以看上面的参考文档^_^

_.isNil

判断传参是不是null或者undefined,这对于常规的判断非常有用

_.get(object,path,[defaultvalue])

这是最常用的API,能够让你对一个数组或者数字,进行路径path的值访问,而且如果这个path的值是为空的,将会使用defaultvalue,举例:

// path的格式:
// 比如a.0.c对应的path路径就是 obj = {a:[{c: 

JavaScript原型链知识点总结

在学习JavaScript的时候,原型链总是困扰着我,对它的概念一直模模糊糊。在查阅资料书籍之后,总结了以下知识点,希望能对大家有帮助

构造函数的prototype和实例的__proto__关系

  • 函数的默认prototype包含constuctor和__proto__,constructor指向其构造函数自身
  • 通过new创建的对象,包含__proto__(指向构建函数的prototype),但是不包含prototype(因为实例不会有prototype,有prototype的只能是Function类型)
  • 所以基于上面两点,构造函数和实例之间通过__proto__指针进行关联,这也是为什么要在构建函数.prototype定义方法和变量域让所有实例可以访问

prototype和__proto__之间的关系

  • 大部分类型的值都有__proto__,比如String,NaN(number),true等。同理可得 “test”.
    __ proto__.constructor === String输出为true
  • 只有Function才有prototype,其他类型的值都没有(包括new出来的实例也没有)
  • 修改Function.prototype,那么在下次new实例的时候,将会以新的prototype进行初始化,__proto__也会指向新的prototype
  • 修改构造函数的prototype一般有两种方式,我常用后者,因为不会对原有的赋值对象有影响:
第一种:
  func100.prototype = func200
  func100.prototype.constructor.name = func200.name
第二种:
  func100.prototype =