• Microsoft OCR Form Tool前端技术文档


    前端技术文档

    依着在北航软工NameNotFound小组里二次开发Microsoft OCR Form Tool开源项目的机会,前端程序猿零零碎碎写一点技术文档,目的是让新手尽快看懂项目代码。一些基础的东西我并不打算在技术文档里面将,只提一些最关键最常见的地方。如有错误,望不吝赐教。

    技术栈

    React

    Redux

    sass(scss)、css

    office-ui-fabric-react

    前言

    当我还是新手的时候,总是看不懂html代码,自然而然在这上面倾注过多心血,比如

    <div style={{display: "flex",  "100px", background: "red", paddingLeft: "20px"}}>
        <span className="span-class"><strong>hello world</strong></span>
    </div>
    

    各种标签、各种样式,头都大了。这是前端工作人员的必经之路,但是把太多时间花在html和css上面是不可取的,我认为这叫捡了芝麻丢了西瓜。我的建议是:这些东西不需要记忆,只需要在遇到不懂的时候查百度就可以了,html标签和css样式毕竟太多太杂,需要时间和经验的积累。

    React

    React 是一个用于构建用户界面的Javascript库(当然Typescript也可以)。React部分大部分内容都可以通过看组件名、参数和返回值,揣测其含义来看懂;就像我们刚刚接触到一个全新的语言时一样:先注重语义,再去研究它的语法。

    当我还是新手时,被javascript的箭头函数()=>{}困扰了足足一个星期,后来硬是靠着从大量的代码中猜,猜出了它的含义:

    const func1 = (para1,para2) => {
        ;;
    };
    

    function func1(para1,para2) {
        ;;
    }
    

    其实可以认为是等价的,箭头函数实际上还就是一个函数,在调用的时候,一样通过func1()来调用。

    React组件

    React组件是React前端代码的积木,也是React的核心和精髓。一个典型的react组件可以通过函数或者ES6 class来定义。

    function HelloMessage(props:any) {
        return (<h1>Hello World!</h1>);
    }
    
    interface IHelloMessageProps {
        array: [];
        numb: number;
        str: string;
        things: any;
    }
    class HelloMessage extends React.Component<IHelloMessageProps> {
      public render() {
        return (
           	<div>
                <h5>{this.props.numb}</h5>
                <h1>Hello World!</h1>
            </div>
        );
      }
    }
    

    上述两者均可。在第二种实现中,组件可以包含三大要素:state(表示组件当前的状态)、props(表示外界传给组件的参数)、render(渲染前端页面的函数)。

    props在实现时最好定义一个接口(必须以大写字母I开头),外界在调用这个HelloMessage类(组件)的时候必须传入IHelloMessageProps接口定义的参数,而后就可以在组件内部几乎任意位置使用this.props.XXX来调用名为XXX的props。

    render则是组件必须要实现的一个函数,用于渲染前端页面,调用组件时就相当于把render里面的前端代码渲染到被调用的位置。一个调用组件和渲染的实例如下:

    import HelloMessage from '路径';
    class AnotherComponent extends React.Component {
    	render (){
            return (<HelloMessage array={[1,2,3]} numb={1} str={"hello"} things:undefined/>);
        }
    }
    

    React状态

    React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

    一个典型的例子如下:

    class Machine extends React.Component {
        constructor(props) {
            super(props);
            this.state = {count: 1};
        }
        public componentDidMount() {
            console.log("the counter inits", this.state.count);
        }
        public componentDidUpdate() {
            console.log("the counter has increment", this.state.count);
        }
        public render() {
    		return (
                <div>
    				<span>{this.state.count}</span>
    				<Button onClick={handleClick}></Button>
    			</div>
            );
        }
        private handleClick() {
            this.setState({count: this.state.count + 1});
        }
    }
    

    在组件被构建时,会执行constructor,导入调用方的给Machine的参数props,并且设定Machine 自身的状态为{count: 1};在准备执行render()进行渲染界面时,会执行componentDidMount() ,这个函数常用于为页面状态设定一些初始值,比如从数据库取数据、对数据进行整理。

    用户在触发一些操作后,会调用一些定义好的处理该操作的函数。比如上方<Button onClick={handleClick}></Button>以为点击该按钮,就会调用我们自己定义的一个handleClick函数。

    handleClick函数内,我们定义“用户点击了按钮之后我们要干什么”的逻辑,比如修改state,this.setState({count: this.state.count + 1});则是点击了按钮之后把count值由原来的count值加上1。

    在发现自生状态发生改变之后,Machine组件会调用componentDidUpdate()方法,这个函数常用于页面状态修改后的一些操作,比如重新从数据库更新数据。然后页面会重新渲染,屏幕上显示的数字马上就从1变成了2。

    异步处理

    在JavaScript的世界中,所有代码都是单线程执行的。

    在Microsoft OCR Form Tool中,由于前端需要直接访问Microsoft Azure,故在数据交互部分使用了很多异步处理。首先讲一下Promise:

    function function1(resolved, rejected) => {
        const a = 1;
        wait 1000 years
        if (a === 1){resolved();}
        else{rejected();}
    }
    function good(){console.log("good");}
    function bad(){console.log("bad");}
    funtion main() {
    	new Promise(function1).then(good).catch(bad);
        console.log("我先去忙别的");
    }
    

    Promise意味“承诺”,这个语句的意思就是:我保证你给我的函数能执行完,到时候把结果告诉你,现在你先去忙别的。上面main函数执行逻辑是这样的:

    1. 进入main函数

    2. 把执行function1的任务交给Promise,然后告诉他:“你做完了马上告诉我,失败了也及时打我电话”,然后main就不管了,直接执行下一条console

    3. 可怜的Promise被迫背锅,帮main执行function1

    4. 一千年后(wait 1000 years),Promise终于完成了任务,如果完成了,就执行resolved函数,告诉main:俺完成了你交给我的任务;或者失败了,也通知main。

    在项目的数据交互中,常常用到这样的异步操作。但是ES6更新了await/async之后,异步的写法就更加简便了。如下是一个数据交互结构的伪代码:

    public main = () => {
        console.log("before fetch");
        onFetch();
        console.log("behind fetch");
    }
    public onFetch = async (): Promise<void> => {
        const ret = await fetch('https://www.baidu.com/', {method: "GET"});
        const ret2 = await fetch('https://www.google.com/', {method: "GET"});
        console.log("after fetch");
        return ret.data;
    }
    

    这里的async说明onFetch函数是异步的,其中的await其实就是Promise。onFetch函数看到await就知道这是别人交代给我的委托,要我帮他完成,但是我先不妨碍他干下一步,于是onFetch()函数就先返回,让main执行 console.log("behind fetch")这一句。

    onFetch()中await的第二个作用就能体现出来,那就是等待,await能强制fetch百度fetch谷歌两个操作按顺序进行,即使fetch百度中还有别的嵌套的Promise,也会在fetch百度之后再fetch谷歌

    所以上述结构的执行顺序应该是这样:

    1. console.log("before fetch");
    2. 进入onFetch,开始fetch百度
    3. console.log("behind fetch");
    4. fetch百度结束,开始fetch谷歌
    5. fetch谷歌结束
    6. console.log("after fetch");
    7. onFetch()返回

    结语

    前端真实爆肝,积累十分重要,没事去看文档,天天项目练手,吃饭思索组件,喝水考虑异步,睡觉琢磨样式,努力跳出桎梏,早日不当码农。

  • 相关阅读:
    互联网商业数据分析(二十七):运营分析(三)用户分层
    鲲鹏服务器上跑dpdk kni bug
    dpdk 网卡顺序
    dpvs ipvsadm.c:114:10: fatal error: popt.h: No such file or directory
    dpvs keepalived编译出错
    ps查看线程所在的cpu + pstack 线程+ strace 线程
    查看内核模块加载时参数
    dpdk kni二
    dpdk eal 参数
    dpdk project gdb
  • 原文地址:https://www.cnblogs.com/lzhmark/p/12963445.html
Copyright © 2020-2023  润新知