vue系列--- 认识Flow(一)
1. 什么是Flow?
Flow 是javascript代码的静态类型检查工具。它是Facebook的开源项目(https://github.com/facebook/flow),Vue.js(v2.6.10的源码使用了Flow做了静态类型检查。因此我们现在先来了解下Flow的基本知识,有助于我们分析源码。
2. 为什么要用Flow?
javascript是弱类型语言,弱类型体现在代码中的变量会根据上下文环境自动改变的数据类型。那么这种弱类型有优点也有缺点,优点是我们容易学习和使用,缺点是:开发者经常因为赋值或传值导致类型错误。造成一些和预期不一样的结果。在代码编译的时候可能不会报错,但是在运行阶段就可能会出现各种奇怪的bug。因此在大型项目中我们有必要使用Flow来做代码静态类型检查。
下面我们从一个简单的demo说起。比如如下代码:
function add (x) {
return x + 10;
} var a = add('Hello!');
console.log(a); // 输出:Hello!10
如上代码,x这个参数,我们在add函数声明的时候,其实我们希望该参数是一个数字类型,但是在我们代码调用的时候则使用了字符串类型。导致最后的结果为 "Hello!10"; 为什么会出现这种结果呢?那是因为 加号(+)在javascript语言中,它既有作为数字的加运算符外,还可以作为字符串的拼接操作。
因此为了解决类型检查,我们可以使用Flow来解决。下面我们来介绍下 如何在我们项目中使用Flow。
3. 开始一个新的 Flow 项目
首先我们创建一个名为 v-project 项目:
$ mkdir -p v-project
$ cd v-project
接着,添加Flow, 执行如下命令:
$ npm install --save-dev flow-bin
如上安装完成后,我们需要在要执行静态检查文件的根目录下 执行一下命令:flow init.执行完成后,我们会发现我们根目录下多了一个 .flowconfig 文件。该文件的作用是: 告诉Flow在这个目录下文件开始检测。我们可以在该 .flowconfig 配置文件内可以进行一些高级配置,比如说仅包含一些目录, 或 忽略一些目录进行检测等操作。
现在在我们的项目下会有如下目录结构:
|--- v-project
| |--- node_modules
| |--- .flowconfig
| |--- package.json
package.json 文件基本代码如下:
{
"name": "v-project",
"devDependencies": {
"flow-bin": "^0.106.3"
}
}
现在我们在 v-project根目录下新建 index.js 文件,代码如下:
// @flow var str = "hello world!";
console.log(str);
接着我们在项目的根目录下运行如下命令,如果一切正常的话,会提示如下信息:
$ flow check
Found 0 errors
但是如果我们把代码改成如下所示; 它就会报错了,index.js 代码改成如下:
// @flow var str != "hello world!";
console.log(str);
执行结果如下图所示:
注意第一行,我们添加了 // @flow, 是用来告诉 Flow,你需要检查我这个文件。如果不加这个注释,Flow就不会检查该文件了。
当然,我们可以强制 Flow 来检测所有的文件,不管文件有没有 @flow 注释,我们只需要在命令行中带上 --all 参数就行了,如下所示:
$ flow check --all
但是这个命令,我们一般情况下还是需要慎用的,当我们在一个大型项目中,该项目假如引入了很多第三方库,那么检测器可能会找到很多我们不想要的错误。
注意:flow check 这个命令虽然是可行,但不是最高效的用法,该命令会让flow每次都在项目下检查所有文件一遍。
4. 理解类型注释
Javascript是一种弱类型语言,在语法上没有规定明确的表示类型,比如如下JS代码运行是正常的。
function add(num1, num2) {
return num1 + num2;
} var result = add(1, '2');
console.log(result); // 输出:12
如上代码,输出的 result 的值为 '12'; 但是有可能这并不是我们想要的,我们有可能想要两个数字相加得出结果,但是编写代码的时候,一不小心把参数写成字符串去了。导致预期的结果不一样。
Flow 可以通过静态分析和类型注释,来帮我们解决类似的问题,让我们的代码更加符合预期。
类型注释一般都是以 : 开头的,可以使用在方法参数中、变量声明及返回值中,比如使用类型注释更改上面的代码如下:
// @flow function add(num1:number, num2:number) :number {
return num1 + num2;
} var result = add(1, '2');
执行命令后结果如下所示:
$ flow check
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ index.js:8:21 Cannot call add with '2' bound to num2 because string [1] is incompatible with
number [2]. [2] 4│ function add(num1:number, num2:number) :number {
5│ return num1 + num2;
6│ }
7│
[1] 8│ var result = add(1, '2');
9│ console.log(result); Found 1 error
如上代码,num1:number 和 num2:number 的含义是:num1 和 num2 传递的参数都为数字类型的,:number {} 中的 :number的含义是:希望返回结果也是数字类型。上面如果我们把 '2' 改成 数字 2 就正常了。
类型注释在大型复杂的项目文件中很有用,它能保证代码按照预期进行。
下面我们来看看Flow能支持的其他更多类型注释,分别为如下:
函数
// @flow function add(num1:number, num2:number) :number {
return num1 + num2;
} add(1, 2);
数组
// @flow var foo : Array<number> = [1, 2, 3];
如上数组类型注释的格式是 Array<number>,number的含义表示数组中的每项数据类型都为 number(数字) 类型。
类
下面是类和对象的注释模型,在两个类型之前我们可以使用 或(|) 逻辑,变量foo添加了必须为Foo类的类型注释。
// @flow class Foo {
x: string; // x 必须为字符串类型
y: string | number; // y 可以为字符串或数字类型
constructor(x, y) {
this.x = x;
this.y = y;
}
}
// 类实例化
var foo : Foo = new Foo("hello", 112);
对象字面量
对象字面量需要指定对象属性的类型即可。如下演示:
// @flow class Foo {
x: string; // x 必须为字符串类型
y: string | number; // y 可以为字符串或数字类型
constructor(x, y) {
this.x = x;
this.y = y;
}
} var obj : {a : string, b : number, c : Array<string>, d : Foo} = {
a : "kongzhi",
b : 1,
c : ["kongzhi111", "kongzhi222"],
d : new Foo("hello", 1)
}
Null
假如我们想任意类型 T 可以为null或undefined的话,我们只需要类似如下写成 ?T 的格式的即可。
// @flow var foo : ?string = null;
如上代码,foo 可以为字符串,也可以为null。
5. 理解模块界限
在跨模块使用的时候,Flow需要明确注释,为了保证Flow在各自模块内的独立检测,提高性能,因此我们需要在每个模块中有自己的Flow.
在我们的 v-project 项目目录中新建一个 module.js, 整个目录结构假如变为如下:
|--- v-project
| |--- node_modules
| |--- index.js
| |--- module.js
| |--- .flowconfig
| |--- package.json
module.js 代码如下:
/*
* module.js
* @flow
*/ function module(str: string) : number {
return str.length;
} module.exports = module;
index.js 代码如下:
/*
* index.js
* @flow
*/ var module = require('./module');
var result = module(1122);
在命令行中运行发现报错,如下提示:
$ flow check
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ index.js:8:21 Cannot call module with 1122 bound to str because number [1] is incompatible with
string [2]. index.js
5│ */
6│
7│ var module = require('./module');
[1] 8│ var result = module(1122);
9│ module.js
[2] 7│ function module(str: string) : number { Found 1 error
如果我们把 index.js 代码中的 module(1122); 改成 module('1122'); 字符串这样的,再运行下就不会报错了。
6. 使用Flow检测第三方库模块
大多数javascript应用程序都依赖于第三方库。如果在我们的项目代码中引用外部资源时,我们要如何使用Flow呢?庆幸的是,我们不需要修改第三方库源码,我们只需要创建一个库定义 (libdef). libdef是包含第三方库声明的JS文件的简称。
下面我们来演示下这个过程,假如我们选择了 lodash 库。下面我们的 index.js 代码中使用了该库。如下代码所示:
// @flow
import _ from 'lodash';
然后我们在命令行运行的时候 会报错如下信息:
$ flow check
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ index.js:4:15 Cannot resolve module lodash. 1│
2│ // @flow
3│
4│ import _ from 'lodash';
5│
6│
7│ Found 1 error
这是因为flow 找不到 lodash 模块,因此我们这个时候需要去下载 lodash 的模块文件,我们可以使用 flow-typed 来管理这些第三方库的定义文件。
1. flow-typed
flow-typed 仓库包含了很多流行的第三方库的定义文件。 flow-typed 可以看github代码(https://github.com/flow-typed/flow-typed)
我们使用npm命令行方式全局安装下 flow-typed, 如下命令:
npm install -g flow-typed
安装成功后,我们需要查找该库,是否存在我们的 flow-typed 仓库中,如下命令查找下:
flow-typed search lodash;
运行命令完成后,我们就可以看到有如下版本的了。
Found definitions:
╔═══════════╤═════════════════╤══════════════════════╗
║ Name │ Package Version │ Flow Version ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash-es │ v4.x.x │ >=v0.104.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash-es │ v4.x.x │ >=v0.63.x <=v0.103.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.47.x <=v0.54.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.38.x <=v0.46.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.55.x <=v0.62.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.63.x <=v0.103.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.104.x ║
╟───────────┼─────────────────┼──────────────────────╢
║ lodash │ v4.x.x │ >=v0.28.x <=v0.37.x ║
╚═══════════╧═════════════════╧══════════════════════╝
现在我们可以选择一个版本进行安装,我们需要在我们的项目根目录下运行如下命令:
flow-typed install lodash@4.x.x;
文件下载完成后,会自动在我们的项目根目录下 新建一个 flow-typed/npm 文件夹,在该文件夹下有一个 lodash_v4.x.x.js文件。
那么这个时候,我们再运行 flow check; 命令就不会报错了。
2. 自定义libdef
如果我们用的库在flow-typed仓库搜索不到怎么办?比如我引入了一个在flow-typed管理库中找不到的库,比如该库叫 "kongzhi" 库(但是在npm包中确实有该库),该库下有对外暴露的方法,比如叫 findWhere 这样的方法,我们在 index.js 中调用了该方法,并且该库的假如别名对外叫_; 如下代码:
// @flow var obj = [
{ title: 'kongzhi1111', flag: true },
{ title: 'kongzhi2222', flag: false }
]; function test() {
return _.findWhere(obj, {flag: true});
}
因此 运行 flow check; 命令后,会报如下错误:
$ flow check
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ index.js:10:10 Cannot resolve name _. 7│ ];
8│
9│ function test() {
10│ return _.findWhere(obj, {flag: true});
11│ }
12│
13│ Found 1 error
如上代码报错,那是因为Flow不认识全局变量 _. ,要解决这个问题,我们需要为我们的 kongzhi库创建一个接口文件。
因此我们需要在我们项目中根目录下新建一个叫 "interfaces" 文件夹,在该文件夹下新建一个 'kongzhi.js' 文件,在该文件下代码如下所示:
declare class Kongzhi {
findWhere<T>(list: Array<T>, properties: {}) : T;
} declare var _: Kongzhi;
然后我们需要在我们的 根目录中的 .flowconfig 文件中配置 [libs] 为 interfaces/ 了, 如下所示:
[ignore] [include] [libs]
interfaces/ [lints] [options] [strict]
如上,在 .flowconfig 中默认有如上配置项。如上配置后,Flow就会查找 interfaces/目录下的所有 .js 文件作为接口定义。
有了该接口文件,我们在命令中再次运行下 就不会报错了。如下运行结果:
$ flow check
Found 0 errors
现在整个项目的目录结构变为如下:
|--- v-project
| |--- flow-typed
| | |--- npm
| | | |--- lodash_v4.x.x.js
| |--- interfaces
| | |--- kongzhi.js
| |--- node_modules
| |--- .flowconfig
| |--- index.js
| |--- module.js
| |--- package.json
更多的自定义 libdef,请查看(https://flow.org/en/docs/libdefs/creation/)。
7. 剔除类型注释
类型注释不是我们JS规范的一部分,因此我们需要移除它,这里我们使用Babel来移除它。
比如我们的 module.js 中的代码,如下代码:
function module(str: string) : number {
return str.length;
}
str: string 和 : number 它不是我们的JS规范中的一部分,因此不管我们在浏览器端还是在nodeJS中运行都会报错的。
为了简单的来测试下,我们在node.js中运行测试下,如下:
$ node module.js function module(str: string) : number {
^
SyntaxError: Unexpected token :
at new Script (vm.js:80:7)
at createScript (vm.js:264:10)
at Object.runInThisContext (vm.js:316:10)
at Module._compile (internal/modules/cjs/loader.js:670:28)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:718:10)
at Module.load (internal/modules/cjs/loader.js:605:32)
at tryModuleLoad (internal/modules/cjs/loader.js:544:12)
at Function.Module._load (internal/modules/cjs/loader.js:536:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:760:12)
at startup (internal/bootstrap/node.js:303:19)
如上可以看到,会报错,在编程时,我们希望使用Flow对类型检查,但是在代码运行的时候,我们需要把所有的类型约束要去掉。因此我们需要使用Babel这个工具来帮我们去掉。
因此首先我们要安装babel相关的库,安装命令如下:
npm install --save-dev babel-cli babel-preset-flow
babel-cli: 只要我们要安装babel的话,那么babel-cli库都需要安装的。
babel-preset-flow: 该库目的是去除类型。
安装完成后,我们的 package.json 变成如下:
{
"name": "v-project",
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-flow": "^6.23.0",
"flow-bin": "^0.106.3"
},
"scripts": {
"flow": "flow check"
}
}
为了项目结构合理及方便,我们把上面的 index.js 和 module.js 放到 src/js 目录里面去,因此目录结构变成如下:
|--- v-project
| |--- flow-typed
| | |--- npm
| | | |--- lodash_v4.x.x.js
| |--- interfaces
| | |--- kongzhi.js
| |--- node_modules
| |--- .flowconfig
| |--- src
| | |--- js
| | | |--- index.js
| | | |--- module.js
| |--- package.json
| |--- .babelrc
src/js/module.js 在剔除之前代码如下:
/*
* module.js
* @flow
*/ function module(str: string) : number {
return str.length;
} module.exports = module;
如上安装完成相应的库之后,我们需要在项目的根目录下新建 .babelrc 文件,添加如下配置:
{
"presets": ["flow"]
}
我们现在在项目的根目录下运行如下命令,就可以在项目的根目录生成 dist/js 文件夹,该文件夹下有index.js和module.js文件,如下命令:
./node_modules/.bin/babel src -d dist
然后我们查看 dist/js/module.js 代码变成如下:
/*
* module.js
*
*/ function module(str) {
return str.length;
} module.exports = module;
我们也可以在node命令行中测试:$ node dist/js/module.js 后也不会报错了。
8. Flow类型自动检测
如上我们虽然使用了Babel去除了Flow的类型注释,但是我们并没有对Flow的静态类型检测。因此如果我们想让babel进行Flow的静态类型校验的话,那么我们需要手动集成另外一个插件--- babel-plugin-typecheck。
想了解更多相关的知识, 可以看npm库(https://www.npmjs.com/package/babel-plugin-typecheck)。
接下来我们需要进行具体的babel集成步骤,因此我们需要安装 babel-plugin-typecheck 插件。如下命令:
npm install --save-dev babel-plugin-typecheck
当然我们要全局安装下 babel-cli; 如下命令:
npm install -g babel-cli
接下来,我们需要在我们的 .babelrc 中添加 typecheck 插件进去,如下所示:
{
"presets": ["flow"],
"plugins": ["typecheck"]
}
现在我们就可以使用babel来编译我们的Flow代码了。如下命令所示:
$ babel src/ -d dist/ --watch src/js/index.js -> dist/js/index.js
src/js/module.js -> dist/js/module.js
现在我们把 src/js/module.js 中的代码改成如下:
/*
* module.js
* @flow
*/ function module(str: string) : number {
return str.length;
} var str != "hello world!";
console.log(str); module.exports = module;
然后我们保存后,在命令行中会看到如下报错信息:
可以看到,我们使用babel就可以完成了校验和编译的两项工作。再也不用使用 flow check; 这样的对全局文件进行搜索并检测了。
我们使用了 babel 的 --watch 功能解决了之前 Flow命令不能同时监听,提示的缺憾了。
babel的缺陷:
但是使用 babel 也有缺陷的,比如我们现在把 src/js/module.js 代码改成如下:
/*
* module.js
* @flow
*/ function module(str: string) : number {
return str.length;
} function foo(x : number) :number {
return x * 12;
} foo('a'); module.exports = module;
如上代码,我们添加了一个foo函数,有一个参数x,我们希望传递的参数为 number 类型,并且希望返回的值也是 number 类型,但是我们在 foo('a'); 函数调用的时候,传递了一个字符串 'a' 进去,babel 在检测的时候并没有报错,这或许是它的缺陷。
但是我们在 flow check; 就会报错如下:
9. 了解 .flowconfig 配置项
我们在项目中的根目录运行命令:flow init; 会创建 .flowconfig文件,该文件的作用是告诉Flow在这个目录下开始检测。不过 .flowconfig配置项也提供了一些配置选项,告诉Flow哪些文件需要检测,哪些文件不需要检测。
.flowconfig 默认有如下配置(我们讲解前面三个比较常用的配置项):
[ignore] [include] [libs] [lints] [options] [strict]
1. [ignore] 该配置是用来告诉flow哪些文件不需要检测,默认为空,所有的文件需要检测。我们也可以使用正则去匹配路径,哪些路径不需要进行检测。
[ignore]
.*/src/*
如上表示的含义是:在src目录下的所有文件不需要检测,因此如果src下有某个js文件是不对的类型,也不会报错的。
2. [include] 该配置是用来告诉Flow还要检测哪些文件或者目录。该配置的每一行表示一个待检测的路径,我们可以使用相对于根目录下的路径,或者绝对路径,或支持一个或多个星号通配符。比如如下:
[include]
../xx.js
../xxxDir/
../xxxDir/*.js
注意:如果 [ignore] 和 [include] 同时存在,并且同时匹配同个路径,那就看那个配置在后面,那个优先级就更高。
3. [libs]
该配置下一般存放第三方接口文件,当我们引用第三方库文件后,我们需要声明一个接口文件,我们可以放在该目录下。比如:
[libs]
interfaces/
Flow就会查找 interfaces/目录下的所有 .js 文件作为接口文件的定义。
如上就是Flow一些基本的知识了解下即可。
vue系列--- 认识Flow(一)的更多相关文章
- Vue系列:在vux的popup组件中使用百度地图遇到显示不全的问题
问题描述: 将百度地图封装成一个独立的组件BMapComponent,具体见 Vue系列:如何将百度地图包装成Vue的组件(http://www.cnblogs.com/strinkbug/p/576 ...
- [js高手之路] vue系列教程 - 事件专题(4)
本文主要讲解事件冒泡,事件绑定的简写,事件默认行为,按键码等一系列与事件相关的知识. 一.事件绑定的简写,@事件类型. 之前我的[js高手之路] vue系列教程 - vue的事件绑定与方法(2) 用 ...
- 【vue系列之三】从一个vue-pdf-shower,说说vue组件和npm包
前言 从去年年初开始,自己便下决心要写一个vue系列的博客,但时至今日,才写系列的第三篇博客,想来甚是惭愧. 但是慢归慢,每一篇都要保证质量,以及要写出自己的心路历程,防止自己工作中填的坑再让读者走一 ...
- 在vue中配置flow类型检查
flow中文文档:https://zhenyong.github.io/flowtype/docs/objects.html#_ 1.安装flow npm install --save-dev flo ...
- Vue系列(2):Vue 安装
前言:关于页面上的知识点,如有侵权,请看 这里 . 关键词:小白.Vue 安装.Vue目录结构.Vue 构建页面流程 ? 初学者安装 vue 用什么好 大家都知道,学 Vue 最好还是去官网学,官网写 ...
- Vue系列(一):简介、起步、常用指令、事件和属性、模板、过滤器
一. Vue.js简介 1. Vue.js是什么 Vue.js也称为Vue,读音/vju:/,类似view,错误读音v-u-e 是一个轻量级MVVM(Model-View-ViewModel)框架,和 ...
- Vue系列(二):发送Ajax、JSONP请求、Vue生命周期及实例属性和方法、自定义指令与过渡
上一篇:Vue系列(一):简介.起步.常用指令.事件和属性.模板.过滤器 一. 发送AJAX请求 1. 简介 vue本身不支持发送AJAX请求,需要使用vue-resource.axios等插件实现 ...
- Vue系列(三):组件及数据传递、路由、单文件组件、vue-cli脚手架
上一篇:Vue系列(二):发送Ajax.JSONP请求.Vue生命周期及实例属性和方法.自定义指令与过渡 一. 组件component 1. 什么是组件? 组件(Component)是 Vue.js ...
- 手写 Vue 系列 之 Vue1.x
前言 前面我们用 12 篇文章详细讲解了 Vue2 的框架源码.接下来我们就开始手写 Vue 系列,写一个自己的 Vue 框架,用最简单的代码实现 Vue 的核心功能,进一步理解 Vue 核心原理. ...
随机推荐
- 洛谷P2508 [HAOI2008]圆上的整点
题目描述 求一个给定的圆$ (x^2+y^2=r^2) $,在圆周上有多少个点的坐标是整数. 输入格式 \(r\) 输出格式 整点个数 输入输出样例 输入 4 输出 4 说明/提示 \(n\le 20 ...
- 十一、Spring之事件监听
Spring之事件监听 ApplicationListener ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成Applica ...
- python在字节流中对int24的转换
python在字节流中对int24的转换 概述 最近在写项目的过程中,需要对从串口中读取的数据进行处理,本来用C写完了,但是却一直拿不到正确的数据包,可能是因为自己太菜了.后来用了python重新写了 ...
- 明解C语言 中级篇 第二章答案
练习2-1 /* 倒计时后显示程序运行时间 */ #include <time.h> #include <stdio.h> /*--- 等待x毫秒 ---*/ int slee ...
- windows10 启动安卓模拟器会蓝屏的解决方案
最近突然想用win10装个安卓模拟器玩游戏,然后提示vt被占用. 查了一下,了解到在windows 10 系统上,我们会用vmware,virtual box ,hyper-v,安卓模拟器,360安全 ...
- JQ动态生成节点绑定事件无效问题
最近做项目的时候遇见了一个问题,通过jq将动态节点绑定到dom节点上,并且为动态节点绑定方法,此方法再次为动态节点添加动态节点,但在刷新之后,动态节点上的方法失效了,过程为:创建动态节点->动态 ...
- C#使用HttpClient上传文件并附带其他参数
HttpClient和MultipartFormDataContent(传送门)最低适用于.NET Framework 4.5版本 发送端代码 using (HttpClient client = n ...
- Python - 字符串 - 第七天
Python 字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号( ' 或 " )来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hel ...
- Java多线程——查看线程堆栈信息
Java多线程——查看线程堆栈信息 摘要:本文主要介绍了查看线程堆栈信息的方法. 使用Thread类的getAllStackTraces()方法 方法定义 可以看到getAllStackTraces( ...
- Linux nodejs 安装以及配置环境
从官网中下载nodejs 打开官网 https://nodejs.org/en/download/ 复制拿到链接,下载nodejs wget https://nodejs.org/dist/v10.1 ...