0%

该职位期望招聘高级软件开发人员 以完成基础软件开发 具备独立搭建框架能力和较丰富的前后端开发经验

1介绍一下原型链

2变量提升

  • js中变量和函数的声明都会被提升到函数最顶部
  • 这使得变量和函数在coding时可以先调用在声明

    2属性绑定实现视图更新的原理

    3编写单元测试用例

    4只执行一次的生命周期钩子 constructor init之间进行了什么

钩子 目的

ngAfterContentInit | 在Angular将外部内容放到视图内之后。
ngAfterContentChecked | 在Angular检测放到视图内的外部内容的绑定后。
ngAfterViewInit | 在Angular创建了组件视图之后。
ngAfterViewChecked | 在Angular检测了组件视图的绑定之后。

constructor 依赖注入

5依赖注入 反射

6面向对象的核心——抽象

7docker

8持续集成

hexo d

Error: spawn git ENOENT
hexo s
cannot GET

自定义js

放在/themes/next/source/js/, 官网说的根路径scripts文件夹并不行

配置依赖库。

  • gcc(GNU Compiler Collection)

  • pcre依赖库

  • zlib依赖库

  • SSL依赖库

1
yum install gcc pcre-devel zlib zlib-devel openssl openssl-devel

安装NGINX

官网下载地址: http://nginx.org/en/download.html

—> 解压

1
tar -zxvf nginx-1.14.2.tar.gz

z(gz格式)j(bz2格式)x(解压)v(显示所有过程)f(使用档案名称命名)
—> configure
进入解压目录下
1
./configure

—>编译
1
2
make
make install

启动和停止

1
2
3
4
/nginx/sbin/nginx
/nginx/sbin/nginx -s stop

/nginx/sbin/nginx -s reload

—>查看进程

1
ps -ef | grep nginx

访问index.html页面,404

—>检查端口
1
telnet 127.0.0.1 8080

显示Connection closed by foreign host

—>查看和关闭防火墙

1
2
firewall-cmd --state
systemctl stop firewalld.service

—>服务开机启动
1
2
systemctl disable firewalld.service
systemctl enable nginx.service

手动下载源码,并编译安装的是没有nginx.service的,手动创建
1
vi /lib/systemd/system/nginx.service

编辑内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=nginx
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true

[Install]
WantedBy=multi-user.target

web服务及反向代理

/usr/local/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
 server {
listen 8080; #nginx服务器的代理端口
server_name _;
location / {
proxy_pass http://172.18.78.14:6080; #需要反向代理的IP地址+端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}

负载均衡

juejin

代理服务

ngx_http_proxy_connect_module

查看RedHat版本

1
cat /etc/redhat-release

1
yum install nginx

error:cannot find a valid baseurl

ping
connect:network is unreachable

ls /etc/sysconfig/network-scripts/

ifcfg-enp0s3 ifcfg-lo ….
其中ifcfg-lo是localhost配置
将第一个配置文件重命名

1
mv ifcfg-enp0s3 ifcfg-eth0

查看网卡
1
ip add

显示了lo和enp0s3
修改默认网卡设置
编辑/etc/default/grub文件,在GRUB_CMD_LINE_LINUX=””项中,插入”net.ifnames=0 biosdevname=0”
修改ip配置
注意
1
DEVICE=eth0

1
ONBOOT=no //设置开机启动网卡,将值修改为“yes”

1
BOOTPROTO=static //默认为no,修改为static

重启
service network restart

reboot

直播原理

协议

H5 video标签

直播流的制作

Nginx+ffmpeg

安装

下载RTMP模块并重编译nginx

官方源代码https://github.com/arut/nginx-rtmp-module.git

配置

1
./configure --prefix=/usr/local/nginx --add-module=~/nginx-rtmp-module --with-http_ssl_module

编译并安装

1
make && make install

nginx reload后报“open() “/usr/local/nginx/logs/nginx.pid” failed”,执行下面的命令,指定nginx的configure路径

1
./nginx -c /usr/local/nginx/conf/nginx.conf

编译通过nginx可访问,还没完,配置nginx.conf,在末尾添加rtmp模块配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rtmp{
server {
listen 1935;
chunk_size 4000;

# RTMP 直播流配置
application rtmplive {
live on;
max_connections 1024;
}

# hls 直播流配置
application hls{
live on;
hls on;
hls_path /usr/local/userdata/live;
hls_fragment 5s;
}
}
}

hls_path是分割文件存储路径

在http模块中添加服务路径

1
2
3
4
5
6
7
8
9
10
11
12
http {
server {
location /hls{
types{
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /usr/local/userdata/live;
add_header Cache-Control no-cache
}
}
}

安装流媒体文件转换工具ffmpeg

官方release:http://www.ffmpeg.org/download.html#releases
解压

1
tar jxvf ffmpeg-4.1.3.tar.bz2

执行configure报“yasm/nasm not found or too old. Use —disable-x86asm for a crippled build”,ffmpeg默认的编译器未安装,需使用—disable-x86asm

将本地视频文件通过nginx推流

本地视频文件kon.mp4

推送RTMP流

1
ffmpeg -re -i test.mp4 -vcodec libx264 -acodec acc -f flv rtmp://127.0.0.1:1935/rtmplive/rtmp

推送HLS流

1
ffmpeg -re -i test.mp4 -vcodec libx264 -acodec acc -f flv rtmp://127.0.0.1:1935/hls/stream

这里有一个关于编码器的坑

vcodec acodec 分别指明了视频、音频的编码器,其实这里可以用copy也就是不需要转码,从官方GitHub下载安装的ffmpeg是没有libx264的编码器的,故而在执行上述推流命令时报unkown encoder libx264

而通用的h.264视频编码器是叫x264:https://www.videolan.org/developers/x264.html

安装x264需要将类库提供给外部应用程序(如ffmpeg)

1
2
3
./configure –enable-shared 

make && make install

配置编译的时候最好有—prefix指明安装路径,否则一般默认到/usr/local/lib路径下
需要将/usr/local/lib路径加入共享库配置文件/etc/ld.so.conf中
1
2
3
echo "/usr/local/lib" >> /etc/ld.so.conf

ldconfig

编译安装含外部解码器的FFmpeg
1
2
3
./configure --enable-static --enable-gpl --enable-libx264 --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/lib

make && make install

概念

(略)

方法

1
2
3
4
5
6
7
8
keys *
redis-cli
set key value
get key
del key
hget key fieldname
hget all
flushall

redis作为认证token数据库

ticket=(accountid, token)

centos安装Redis

参考:Linux 平台将 Redis 设置为服务并开机自启动

服务部署好之后,若无法远程访问

首先检查防火墙设置

1
2
3
systemctl status firewalld # 查看防火墙状态
firewall-cmd --zone= public --query-port=6379/tcp # 查询防火墙端口状态
firewall-cmd --zone=public --add-port=6379/tcp --permanent # 永久开发端口及协议

确认是否绑定服务主机ip 参考 处理CentOS 7.2 x64端口不通的问题

远程访问

修改/etc/redis/redis.conf

1
2
# 注释掉或将其改为服务器静态ip
# bind 127.0.0.1 ::1

DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients…..

受保护的模式,改为no

1
protected-mode no

ControlValueAccessor接口

定义一个接口,该接口充当 Angular 表单 API 和 DOM 中的原生元素之间的桥梁。 实现此接口以创建与 Angular 表单集成的自定义表单控件指令, from Angular Doc

删除线小注:见下文“关于原生控件”

1
2
3
4
5
6
7
// angular2/packages/forms/src/directives/control_value_accessor.ts 
export interface ControlValueAccessor {
writeValue(obj: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState?(isDisabled: boolean): void;
}

  • writeValue(obj: any):该方法用于将宿主传入的新值写入自定义组件的视图或 DOM 属性。
  • registerOnChange(fn: any):设置当控件接收到来自宿主的 change 事件后,调用的函数 一般将其对接到input控件的ngOnChange响应事件上
  • registerOnTouched(fn: any):设置当控件接收到 touched 事件后,调用的函数
  • setDisabledState?(isDisabled: boolean):当控件状态变成 DISABLED 或从 DISABLED 状态变化成 ENABLE 状态时,会调用该函数。该函数会根据参数值,启用或禁用指定的 DOM 元素。

自定义的组件实现ControlValueAccessor接口,可以像原生表单控件一样使用ngModel绑定值
stackbliz demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import {Component, OnInit, forwardRef, Input} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';

@Component({
selector: 'app-custom-input',
templateUrl: './custom-input.component.html',
styleUrls: ['./custom-input.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
}
]
})
export class CustomInputComponent implements ControlValueAccessor {
onChange: any = () => {}
onTouch: any = () => {}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
input: string;
writeValue(input: string) {
this.input = input;
}
}

关于原生控件
不直接操作自定义组件 而在组件内逻辑赋值绑定值input 控件会响应 但是自定义组件的ngOnChange不会响应 即父组件绑定ngModel的值并不更新, 即逻辑赋值input还需要手动调用registerOnChange注入的外部响应事件,也就是上述范例代码的onChange变量

参考ng-zorro的select控件源码发现 在实现ControlValueAccessor的自定义组件模板中原生组件是不必要的,自定义组件可以自行管理对外暴露的ngModel的值,没有必要响应原生组件的特性

OnChange接口

A lifecycle hook that is called when any data-bound property of a directive changes. Define an ngOnChanges() method to handle the changes.当指令的任何一个可绑定属性发生变化时调用。 定义一个 ngOnChanges() 方法来处理这些变更。

实际上是自定义组件继承OnChange接口,实现ngOnChange方法,当自定义组件@Input的变量更新时,该方法响应,传入SimpleChanges类型参数,该参数是发生更新的变量的哈希表, 即

1
2
3
4
5
6
7
8
9
10
11
@Component({selector: 'my-cmp', template: `...`})
class MyComponent implements OnChanges {
// TODO(issue/24571): remove '!'.
@Input() prop!: number;
@Input() data:any

ngOnChanges(changes: SimpleChanges) {
const {prop, data} = changes
// prop and data is an SimpleChange boject which contains the old and the new value...
}
}

SimpleChanges是SimpleChange类型的map
1
2
3
4
5
6
7
8
9
10
export declare class SimpleChange {
previousValue: any;
currentValue: any;
firstChange: boolean;
constructor(previousValue: any, currentValue: any, firstChange: boolean);
/**
* Check whether the new value is the first value assigned.
*/
isFirstChange(): boolean;
}

Caution! ngOnChange的底层逻辑是使用‘===’判断前后值的,因此引用类型的属性变化不会触发ngOnChange,workaround是将此类输入属性拆成基本值类型变量,或者在宿主更新该输入属性时赋予新的引用地址,亦或使用ngDoCheck

1
2
3
4
<app-voter *ngFor="let voter of voters"
[name]="voter"
(voted)="onVoted($event)">
</app-voter>

@Input()

@Input()可以带set、get属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-voter',
template: '<h3>"{{name}}"</h3>'
})
export class VoterComponent {
private _name = '';

@Input()
set name(name: string) {
this._name = (name && name.trim()) || '<no name set>';
}

get name(): string { return this._name; }
}

在set、get时进行格式化等操作。

ngOnChanges()生命周期钩子是专门用来监听@Input入参的,非传入参数不会触发ngOnChanges()方法

@Output()

子组件发射事件

1
2
3
4
5
@Output() voted = new EventEmitter<boolean>();

vote(agreed: boolean) {
this.voted.emit(agreed);
}

模板标记子组件

1
2
3
4
5
6
7
8
<h3>Countdown to Liftoff (via local variable)</h3>

<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>

<div class="seconds">{{timer.seconds}}</div>

<app-countdown-timer #timer></app-countdown-timer>

timer 作为父组件的变量,标记在子组件标签中,用以代表子组件,即可使父组件获取子组件的引用,进而可以调用子组件公用方法

该方法有局限性在于,父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。

@ViewChild()

1
2
@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;

使用@ViewChild()装饰器将CountdownTimerComponent实例注入到本组件,记为私有变量timerComponent

  • 特别注意
    被注入的组件只有在 Angular 显示了父组件视图之后才能访问
    下面的语法很关键

    1
    2
    3
    4
    5
    ngAfterViewInit() {
    // wait a tick first to avoid one-time devMode
    // unidirectional-data-flow-violation error
    setTimeout(() => this.timerComponent.init(), 0);
    }

    父组件要及时调用子组件方法进行初始化,须实现AfterViewInit生命周期钩子,且用定时器异步操作。
    否则报异常

    1
    ExpressionChangedAfterItHasBeenCheckedError

    引入第三者通信

    这类方法包括注入服务,借助相同父组件以及借助发布订阅可观察对象等,此处略。

SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能。

将Angular项目样式由css改为scss

安装 node-sass sass-loader

修改angular.json

1
2
3
4
5
6
"styles": [
"src/styles.scss"
],
"default": {
"styleExt":"scss"
},

上面的修改也就看看,不做实操指导,新建ng项目时可以选择样式类型,当时选scss便可,免得多事

SCSS嵌套结构样式优先级高于非嵌套结构样式,因此可以用某元素父元素嵌套的写法覆盖该元素样式

常用新语法

map类型
1
2
3
4
$pie:(
width:125px
height:140px
)
1
width:map-get($pie, width)
@import @mixin

定义一个Mixin模块

1
2
3
4
5
@mixin button{
font-size:1em;
padding:0.5em;
color:#fff
}

调用
1
2
3
4
.button-green{
@include button;
back-ground:green
}

@extend

引用已定义的样式

1
2
3
4
.button-green-mini{
@extend .button-green;
width:2em
}

循环语句创建样式
1
2
3
4
5
6
7
8
9
$lvlcolors:(
1:$color-danger
2:$color-orange
3:$color-warning
4:$color-blue
)
@for $lvl from 1 through 4{
.lvl#{$lvl} {background: map-get($lvlcolors, $lvl)}
}

each:

1
2
3
4
5
6
7
8
9
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f");

@each $name, $glyph in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
}
}

issue: scss variables are not working in calc
1
2
3
4
5
.main {
width: 100%;
height: calc(100% - #{$header-height});
background: #313030;
}

伪类 icon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$icon:(
add:"%3Csvg%20width%3D%2218%22%20height%3D%2218%22%20viewBox...",
edit:"%3Csvg%20width%3D%2230%22%20height%3D%2230%22%20viewBox...",
delete:"%3Csvg%20width%3D%2230%22%20height%3D%2230%22%20viewBox...",
refresh:"%3Csvg%20width%3D%2230%22%20height%3D%2230%22%20viewBox..."
)
@each $key, $val in $icon{
.qqs-design-icon.icon-#{$key}{
position: relative;
padding-left: 22px;
margin-left: 4px;
&::before{
content: '';
position: absolute;
left: 0px;
bottom: calc(50% - 10px);
background: url("data:image/svg+xml," + $val + "") no-repeat top left;
width: 25px;
height: 25px;
}
}
}

拼接url

1
2
3
4
5
6
7
$sites: ("twitter.com", "facebook.com", "linkedin.com");

@each $site in $sites {
a[href*="#{$site}"] {
background-image: url("/images/" + $site + ".png");
}
}

总结一下就是#{}这个符号用于将变量拼接在css选择器上,包括class名,属性名等,在样式的值中,字符串与变量的拼接可以直接用“+”连接

issues

jenkins build fail

1
npm i -g node-sass

以下理解未必完全正确,但包含了若干方面的可能因素,可日后进一步探究(QQs:不太会探究):jenkins 在打包angular过程中为webpack的sass-loader安装所需包node-sass,但是缺少node-gyp,python等工具链的调用权限,因而build失败,至于npm install为什么会build,electron编译过程中也遇到过,编译对象是package中调用的c++库。对此的解决方案之一是在jenkins所在的物理机上全局安装node-sass,当下的默认版本是5.0.0,曾尝试在项目package.json中将node-sass更新为5.0.0,然而angular9中的sass-loader似乎是支持node-sass^4.0.0,因此出现“Node Sass version 5.0.0 is incompatible with ^4.0.0”的报错,应在全局重装npm i -g node-sass@4

参考
node-sass troubleshooting#Running with sudo or as root
stackoverflow:Error: Node Sass version 5.0.0 is incompatible with ^4.0.0
node-sass issues#941

Cannot download “https://github.com/sass/node-sass/releases/download/v4.13.1/win32-x64-83_binding.node”
package-lock指定了node-sass@4.13.1, 关于node-sass的release版本没有win32-x64-83_binding.node, ‘-83’为node 14的支持模块,而4.13的node-sass不支持node 14,见Node version support policy. 即此问题是由于编译环境升级到node14造成的,解决方法是安装支持node14的4.14+

参考