0%

前言

SVG图案一般用于在图图形对象内部定义形状,创建一个新形状并用图案填充它。一个SVG元素或是位图图像,都可以通过元素在x轴或y轴方向以固定的间隔平铺。
下面会展示几个的简单SVG形状的。这个列表可能会随着时间的推移而增长,但是要想拥有一个全面的集合,可以在这基础上创造新图案。

圆形图案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<svg width="100%" height="100%">

<mask maskUnits="userSpaceOnUse" id="fade">
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="100%">
<stop offset="0" style="stop-color: #FFFFFF"></stop>
<stop offset="1" style="stop-color: #000000"></stop>
</linearGradient>
<rect fill="url(#gradient)" width="100%" height="100%"></rect>
</mask>

<pattern id="pattern-circles" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse">
<circle mask="url(#fade)" cx="20" cy="20" r="20"></circle>
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-circles)"></rect>

</svg>

SVG图案填充-Pattern1

棋盘图案

1
2
3
4
5
6
7
8
9
10
11
<svg width="100%" height="100%">

<pattern id="pattern-checkers" x="0" y="0" width="200" height="200" patternUnits="userSpaceOnUse">
<rect class="checker" x="0" width="100" height="100" y="0"></rect>
<rect class="checker" x="100" width="100" height="100" y="100"></rect>
</pattern>

<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-checkers)"></rect>

</svg>

SVG图案填充-Pattern2

六角形图案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<svg width="100%" height="100%">

<pattern id="pattern-hex" x="0" y="0" width="112" height="190" patternUnits="userSpaceOnUse" viewBox="56 -254 112 190">

<g id="hexagon">
<path d="M168-127.1c0.5,0,1,0.1,1.3,0.3l53.4,30.5c0.7,0.4,1.3,1.4,1.3,2.2v61c0,0.8-0.6,1.8-1.3,2.2L169.3-0.3 c-0.7,0.4-1.9,0.4-2.6,0l-53.4-30.5c-0.7-0.4-1.3-1.4-1.3-2.2v-61c0-0.8,0.6-1.8,1.3-2.2l53.4-30.5C167-127,167.5-127.1,168-127.1 L168-127.1z"></path>
<path d="M112-222.5c0.5,0,1,0.1,1.3,0.3l53.4,30.5c0.7,0.4,1.3,1.4,1.3,2.2v61c0,0.8-0.6,1.8-1.3,2.2l-53.4,30.5 c-0.7,0.4-1.9,0.4-2.6,0l-53.4-30.5c-0.7-0.4-1.3-1.4-1.3-2.2v-61c0-0.8,0.6-1.8,1.3-2.2l53.4-30.5 C111-222.4,111.5-222.5,112-222.5L112-222.5z"></path>
<path d="M168-317.8c0.5,0,1,0.1,1.3,0.3l53.4,30.5c0.7,0.4,1.3,1.4,1.3,2.2v61c0,0.8-0.6,1.8-1.3,2.2L169.3-191 c-0.7,0.4-1.9,0.4-2.6,0l-53.4-30.5c-0.7-0.4-1.3-1.4-1.3-2.2v-61c0-0.8,0.6-1.8,1.3-2.2l53.4-30.5 C167-317.7,167.5-317.8,168-317.8L168-317.8z"></path>
</g>

</pattern>
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-hex)"></rect>

</svg>

SVG图案填充-Pattern3

立方体图案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<svg width="100%" height="100%">

<pattern id="pattern-cubes" x="0" y="126" patternUnits="userSpaceOnUse" width="126" height="200" viewBox="0 0 10 16">

<g id="cube">
<path class="left-shade" d="M0 0l5 3v5l-5 -3z"></path>
<path class="right-shade" d="M10 0l-5 3v5l5 -3"></path>
</g>

<use x="5" y="8" xlink:href="#cube"></use>
<use x="-5" y="8" xlink:href="#cube"></use>

</pattern>

<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-cubes)"></rect>

</svg>

SVG图案填充-Pattern4

前言

之前为了操纵DOM元素class列表,经常会引入jQuery之类的库。其实html5的classList API还是非常方便的,而且兼容性也不错。

API用法

假设我们有这样一个DOM元素

1
<div id="el"></div>

获取DOM元素

1
const el = document.querySelector("#el");

然后你可以用classList方法操纵该元素上所有的类

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 添加一个类
el.classList.add("open");

// 添加多个类
el.classList.add("this", "little", "piggy");
let classes = ["is-message", "is-warning"];
el.classList.add(...classes);

// 删除一个类
el.classList.remove("open");

// 删除多个类
el.classList.remove("this", "little", "piggy");

// 遍历每个类
el.classList.forEach(className => {
// 不要使用“class”作为变量名,因为这是保留字
console.log(className);
});
for (let className of $0.classList) {
console.log(className);
}

el.classList.length; // 获取类的个数

// 替换类
el.classList.replace("is-big", "is-small");

// 切换一个类(如果存在,则将其删除,如果不存在,则将其添加)
el.classList.toggle("open");
// 删除类
el.classList.toggle("open", false);
// 增加类
el.classList.toggle("open", true);

// 查看各个类是否存在
el.classList.contains("open");

// 按顺序查看每个类:<div class="hot dog">
el.classList.item(0); // hot
el.classList.item(1); // dog
el.classList.item(2); // null
el.classList[1]; // dog

兼容性

.classList() API简介

前言

现在一种流行的设计是创建一个容器,并在里面堆叠其他纸,然后添加分层或三维样式。我们可以使用CSS来完成这个效果,而且还可以做成多种类型的堆叠纸设计。接下来我们将展示3个不同效果。

底部垂直层叠纸

这里的想法是,我们的内容容器是顶层纸,并且更多的纸堆在其下方,并且其边缘显示在顶层纸的底部。

层叠纸效果1

1
<div class="paper"></div>
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
30
31
32
.paper {
background-color: #fff;
position: relative;
padding: 30px;
}

.paper,
.paper::before,
.paper::after {
box-shadow: 2px 1px 1px rgba(0,0,0,0.15);
}

.paper::before,
.paper::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
background-color: #eee;
}

.paper::before {
left: 7px;
top: 5px;
z-index: -1;
}

.paper::after {
left: 12px;
top: 10px;
z-index: -2;
}

对角层叠纸

这是一种效果使用的方法略有不同,我们使用::before和::after伪元素来创建其他纸张,而不是前面的示例中使用的box-shadow属性。

层叠纸效果2

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
30
31
32
33
.paper {
background-color: #fff;
position: relative;
padding: 30px;
}

.paper,
.paper::before,
.paper::after {
box-shadow: 2px 1px 1px rgba(0,0,0,0.15);
}

.paper::before,
.paper::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
background-color: #eee;
}

.paper::before {
left: 7px;
top: 5px;
z-index: -1;
}

.paper::after {
left: 12px;
top: 10px;
z-index: -2;
}

混乱层叠纸

我们可以使用与上一个示例相同的伪元素技术,使纸页错开以创建的凌乱形态,这里会使用transform属性旋转底层纸页。(注意transform属性浏览器兼容性)。

层叠纸效果2

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
30
31
32
33
34
35
.paper {
background: #fff;
padding: 30px;
position: relative;
}

.paper,
.paper::before,
.paper::after {
box-shadow: 1px 1px 1px rgba(0,0,0,0.25);
border: 1px solid #bbb;
}

.paper::before,
.paper::after {
content: "";
position: absolute;
height: 95%;
width: 99%;
background-color: #eee;
}

.paper::before {
right: 15px;
top: 0;
transform: rotate(-1deg);
z-index: -1;
}

.paper::after {
top: 5px;
right: -5px;
transform: rotate(1deg);
z-index: -2;
}

网页滚动就是一个DOM事件。我可以使用window.scrollY随时查看窗口滚动了多远。我可以监听该事件并获取该数值:

1
2
3
window.addEventListener("scroll", () => {
console.log(window.scrollY)
});

假设我想知道用户是否向下滚动了100px或更多,我可以通过判断window.Y > 100来进行测试。这里,我将结果log出来:

1
2
3
4
5
6
7
window.addEventListener("scroll", () => {
if (window.scrollY < 100) {
console.log("Not past 100px");
} else {
console.log("Past 100px!");
}
});
1
<div id="pixel-to-watch"></div>

虽然它简单,易于理解且有效,但这是一个坏主意。因为这有点反模式,这种事件会发生很多次。当用户向下滚动页面时,它可以轻松触发几十,数百或数千次。每次这样做,我们都必须在JavaScript的单线程上运行。这意味着需要更多的时间来解决滚动问题,而花费较少的时间进行其他重要的事情。

有很多方法可以减少这种强度,并且自然地,这是一个非常好的主意。Throttling和Debouncing是JavaScript中提高性能的良好模式。其要点是,在它们执行之前,它们阻止执行较大的JavaScript。

不过,还有更好的方法:

1
<div id="pixel-to-watch"></div>
1
2
3
4
5
6
7
#pixel-to-watch {
position: absolute;
width: 1px;
height: 1px;
top: 100px;
left: 0;
}

使用IntersectionObserver:

1
2
3
4
5
6
7
8
9
let observer = new IntersectionObserver(entries => {
console.log(entries);
if (entries[0].boundingClientRect.y < 0) {
console.log("Past 100px!");
} else {
console.log("Not past 100px");
}
});
observer.observe(document.querySelector("#pixel-to-watch"));

前言

反向字符串问题是常见的算法问题。我们需要写一个反向字符串的函数,如果将“tom”传递给函数,则返回“mot”。在本文中,我们将考虑针对它的4个JavaScript解决方案。

方法1.使用数组reverse·方法

有了Array.reverse() 方法,我们可以轻松地反转数组。 reverse() 方法将数组反转到位。但我们正在处理字符串,这意味着我们必须使用split方法将字符串转换为数组,使用reverse方法将其反向,并使用join方法将其转换回字符串。 这是代码示例。

1
2
3
4
5
6
7
function reverseString(string) {
let array = string.split('');

array.reverse()

return array.join('')
}

我们可以使用箭头函数写成一行

1
const reverseString = (string) => string.split('').reverse().join('');

方法2.使用For Of循环

这是反向转换字符串的经典示例。我们在这里要做的是创建一个空字符串,该字符串将保留反向的string,循环遍历字符串中的每个字符,并将其附加到新字符串的开头。

1
2
3
4
5
6
7
8
9
function reverse(str) {
let reverseString = '';

for (let character of str) {
reverseString = character + reverseString;
}

return reverseString
}

方法3.使用Array.reduce()

reduce方法在数组的每个元素上执行reducer函数,从而产生单个输出值。要使用reduce方法,我们需要将字符串转换为数组。接下来,我们使用reduce方法将其转换为字符串。这样,reducer将字符串的每个字符附加到累加值,该累加器值就是反转的字符串。

1
2
3
4
5
6
7
8
9
function reverseString(string) {
const array = string.split('');

const reversedString = array.reduce((reversed, character) => {
return character + reversed
}, '')

return reversedString
}

上述函数也可以写成下面的形式

1
2
3
const reverseString = (string) => {
return string.split('').reduce((reversed, character) => character + reversed, '')
}

甚至可以写成更短的单行

1
const reverseString = (string) => string.split('').reduce((rev, char) => char + rev, '')

方法4.使用递归

你熟悉递归的吗? 递归是一种通过使用调用自身的函数来解决问题的方法。每次函数调用自身时,它将问题减少为子问题。该递归调用继续进行,直到到达无需进一步递归。
你可以参考

首先我们使用string.substring()方法获取删除字符串中的第一个字符,并将其他字符传递给函数。 然后,将第一个字符添加到return语句中,如下面的代码所示。

1
2
3
4
5
6
7
function reverse(string){
if(string === '') {
return string
} else{
return reverse(string.substring(1)) + string[0]
}
}

我们可以使用三元操作符简化上述函数

1
2
3
function reverse(string) {
return string ? reverse(string.substring(1)) + string[0] : string
}

总结

这样就可以用四种很酷的方法来反转JavaScript中的字符串。扎实的数据结构和算法知识来自许多实践,还有什么更好的方式欢迎留言。

前言

无服务器架构计算变得越来越流行,但是,当使用无服务器架构来构建后端API时,经常会遇到一些小问题。使用无状态函数是否意味着必须在每次运行该函数时都建立与数据库的新连接? 其实大多数问题都有解决方法,因此不必每次运行函数时花费额外的时间来连接数据库。所以今天准备写一下关于使用MongoDB驱动程序和mongoose与Azure Functions重复使用数据库连接的文章。本文将完成在Node.js中创建Azure Functions的过程,以及将该函数将连接到MongoDB并在请求之间重用数据库连接。

创建一个简单的Azure函数

在之前的文章中已经讲解了如何创建Azure Functions,这里也不再赘述。首先我们在Azure Portal上创建一个Azure Function。
![创建好的Azure Function](/images/Azure Functions 连接 MongoDB1.jpg)

安装MongoDB驱动程序

接下来让我们将该功能连接到数据库。在Azure Function中添加npm模块与在AWS Lambda的过程非常不同。使用Azure Functions,必须登录到服务器,然后创建package.json,然后运行npm install。对于“无服务器”架构来说,这似乎很奇怪,但是好处就是不必一遍又一遍地捆绑相同的依赖,也不必担心node_modules运行在Lambda对函数大小的限制。

要安装MongoDB Node.js驱动程序,请首先转到.scm.azurewebsites.net,然后单击“调试控制台”->“ PowerShell”。
![PowerShell](/images/Azure Functions 连接 MongoDB2.jpg)

转到D:\home\site\wwwroot目录下,新建名为的package.json文件,增加MongoDB一览,最后保存。
![创建好package.json](/images/Azure Functions 连接 MongoDB3.jpg)

执行npm i
![执行npm i](/images/Azure Functions 连接 MongoDB4.jpg)

回到Azure Function编辑界面,写入代码。

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
30
31
const mongodb = require('mongodb');

// URI for MongoDB Atlas xxx为省略 https://www.mongodb.com/cloud/atlas
const uri = 'mongodb+srv://xxx.mongodb.net/test';

module.exports = function (context, req) {
context.log('Running');
mongodb.MongoClient.connect(uri, function(error, client) {
if (error) {
context.log('Failed to connect');
context.res = { status: 500, body: res.stack }
return context.done();
}
context.log('Connected');

client.db('test').collection('tests').find().toArray(function(error, docs) {
if (error) {
context.log('Error running query');
context.res = { status: 500, body: res.stack }
return context.done();
}

context.log('Success!');
context.res = {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ res: docs })
};
context.done();
});
});
};

重用数据库连接

但是每次该函数运行时创建一个新的数据库连接会降低性能。所以与Lambda一样,可以使用Node.js运行时的小技巧来保留调用之间的数据库连接。具体来说,脚本中的全局变量可能在函数调用之间保留,因此,如果向MongoDB客户端添加全局指针,则它将一直保留,直到它被Azure清除它。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const mongodb = require('mongodb');

const uri = 'mongodb+srv://xxx/test';

// May be retained between function executions depending on whether Azure
// cleans up memory
let client = null;

module.exports = function (context, req) {
context.log('Running');

let hasClient = client != null;

if (client == null) {
mongodb.MongoClient.connect(uri, function(error, _client) {
if (error) {
context.log('Failed to connect');
context.res = { status: 500, body: res.stack }
return context.done();
}
client = _client;
context.log('Connected');
query();
});
} else {
query();
}

function query() {
client.db('test').collection('tests').find().toArray(function(error, docs) {
if (error) {
context.log('Error running query');
context.res = { status: 500, body: res.stack }
return context.done();
}

context.log('Success!');
context.res = {
headers: { 'Content-Type': 'application/json' },
body: 'Num docs ' + docs.length + ', reused connection ' + hasClient
};
context.done();
});
}
};

第一次运行会创杰数据库连接,第二次运行就会从全局变量中拿到以前的连接。很明显会更快。

最后

Azure Functions不需要您捆绑node_modules,而是让您在功能应用程序中的多个功能之间共享node_modules。
Azure Functions可以大规模执行代码,而不必担心置备和管理基础虚拟机和操作系统。MongoDB使开发人员能够快速将想法变为现实,而不会影响数据库的工作效率。 Azure平台和MongoDB一起为开发人员提供了一套快速开发的环境。

前言

如果你是一个React开发者,那么你经常会听到关于React hooks,也就是所说的钩子的讨论。而对于那些没有使用过React hooks的开发者来说,这只是React内置的函数,它们可以让我们让在functional组件内里做所有可以在class组件内做的事。

但是为什么要使用React hooks呢? 如果类组件可以完成我们希望它们做的所有事情,比如初始化状态,设置状态,访问组件的生命周期,创建上下文,调用引用等,那么我们为什么要为我们的展示性组件提供一种方法,做同样的事情呢?functional组件有什么特别之处?

好吧,事实证明,使用钩子为开发人员带来好处的原因有很多。首先是大型组件可能难以使用,在大型项目上工作的开发者们,组件的状态可能会越来愈多,愈来愈复杂,其大小经常会在组件生命周期方法中散布相同或相似的逻辑。第二个是方法重用,重用组件方法(尤其是复杂的逻辑)依赖于设计模式,例如高阶组件或渲染参数,这反过来又需要开发人员重新组织其组件层次结构,并可能导致组件层级混乱。最后,类语法对卡发者和编译器都造成了混淆,并且可能导致React所追求的纯粹的功能设计模式无法实现。

那么钩子如何解决这些问题呢?

组件大小

当涉及到组件的规模,大小时,钩子使用useEffect提取生命周期方法中的许多重复功能,并使用useState初始化,改变状态。例如,一个useEffect挂钩可以完成3种生命周期方法的工作:componentDidMount,componentDidUpdate和componentWillUnmount。通过指定一个可选的依赖项数组,您可以告诉useEffect在指定的状态引用中查找更改,然后再次运行该效果,等效于componentDidUpdate。通过指定一个空的依赖关系数组,您可以告诉useEffect仅运行一次componentDidMount。当从DOM中删除组件时,您需要执行一些数据清除操作(例如清除间隔或阻止api调用),您可以在return语句中为useEffect回调,该语句将在unmount- componentWillUnmount上运行。所有这些工作都可以通过一个useEffect调用来完成,这使其成为解决副作用的强大方法!

方法复用

在应用中其他地方重用组件逻辑时,我们概括这些方案的传统方式是使用渲染道具或HOC(高阶组件)。
渲染道具的工作方式是将带有独立JSX的自定义回调作为参数,传递给我们的组件。当我们希望相同的渲染组件的多个实例之间重用时,就可以这样。例如,如果我们想通过一个组件跟踪鼠标的位置,但想对该数据做不同的事情(例如在p标签而不是h1标签中显示位置),则可以通过指定渲染擦输来实现使用定制的JSX。

1
2
<MousePosition render = {position => <p>{position}</p>}></MousePosition>
<MousePosition render = {position => <h1>{position}</h1>}></MousePosition>

HOC(高阶组件)通过创建包装器组件或返回包装器组件的函数来实现,该函数使包装的组件可以访问某些数据或功能。如果多个组件正在执行相似但略有不同的工作,例如从相同来源获取某些数据但使用不同方法,则我们将希望使用此功能。想想Redux的connect()函数,它将包装好的组件连接到我们的商店。这里可能需要连接多个组件,但是状态和调度方法的需求却有所不同。因此,我们可以向我们的连接HOC提供自定义的mapStateToProps和mapDispatchToProps函数,以为包装的组件提供个性化数据。

1
export default connect(mapStateToProps, mapDispatchToProps)(SomeComponent);

尽管这些模式对于类组件非常有效,但它们也有缺点。特别是,它们要求开发人员重写其组件层次结构,并可能导致包装器地狱的第9个循环。 React hooks的替代方法是允许我们的可以调用以自定义hook的形式在各​​个组件之间共享。自定义钩子只是可组合的函数,可以像其他任何函数一样在组件之间导出和共享。可组合的意思是指具有多个部分(例如useState和useEffect调用),将它们组合为可重用模式并将其抽象为自己的单独功能的能力。这种模式在类组件中将是不可能的,因为做诸如获取数据或实例化状态之类的简单操作不能与调用它们的类方法分开。

性能与困惑

最后,大家对于类组件的性能其实没有什么担心。在2018年React Conference上,当React Hooks揭幕时,有人指出类组件对于机器和人类都很难理解。由于类语法只是JavaScript原型继承的一种语法糖,因此类的工作方式与其他编程语言不同。React团队注意到在生产环境中最小化类组件的问题,并且在实现热模块重新加载时存在不一致之处。此外,对于开发者,尤其是对那些刚接触类语法的开发者来说,可能很难理解’this’关键字的绑定是如何工作的,或者难以理解其他类的细微差别,例如在构造函数内部调用super()的目的。

由于React hooks使我们能够在功能组件内部使用所有相同的类组件功能,因此我们能够提高React代码的性能。此外,钩子具有简洁的语法,不仅与React的纯功能设计紧密相关,而且与JavaScript紧密相关。 React在其他基于组件的前端库(如Vue)之间的主要区别之一是它通过JSX和css模块将html,css和JavaScript耦合在一起。这意味着,如果你是JavaScript专家,那么您就是React(提供或获取实现细节)专家,而不是像过去那样依赖Vue在HTML,CSS和JS之间拆分文件的模板结构jQuery和Vanilla JS的DOM处理的概念。

尽管功能组件的性能略有提高,但性能不应成为使用React hooks的主要原因。它也不会在React中添加尚不存在的任何功能。其主要目的只是简单地将功能组件提升到与类组件相同的级别,从而通过更干净,更可维护的代码,更好地在组件之间重用方法以及更简单,更具声明性的使用方式,从而获得更好的DX(开发人员体验)。

话虽这么说,但我有一些同事发现React hooks在概念上不容易掌握,尤其是在了解useEffect,useState或useContext时。例如,很难看到应该如何将生命周期方法中的各种逻辑组合成单个函数调用。因此,最近,有开发者创建了一个称为Hookd的CLI模板工具,以将类组件立即转换为带有钩子的功能组件。

清理代码,理清思路

最后,使用React hooks似乎不仅仅是开发者“装x”的工具,它可以让开发人者清理自己的代码,进而理清自己的思路。所以不应低估简洁和声明性代码提高的可读性,开发效率和模块化且可维护的应用程序的重要性。在AI代替人类编程之前,我们必须遵循这些可以让打击都清楚理解的约束,这样才有助于项目壮大。

前言

本文将介绍部署Azure Function的完整过程。这一次会使用Node.js作为开发语言,以及使用VS Code作为编辑器。
![如何使用VS Code如何快速部署Azure Function-1](/images/如何使用VS Code如何快速部署Azure Function-1.jpg)

在后面的博文中会写到如何提高Node.js Azure functions的性能。

进入正题

首先在Azure portal上创建一个Function App然后选择使用VS Code做为开发环境。

1

我们先了解一些基本参数:

  1. App name:functions群组的唯一名称。这也是资源最终URL的尾部。比如App name是example,URL就会是example.azurewebsites.net
  2. Subscription: 选择你的订阅
  3. Resource group & version: 选择开发语言和版本
  4. OS: Windows是默认的选项,但是你也可以使用Linux
  5. Runtime stack: 我们选择node,版本选择10
  6. Publish: 发布类型,我们选择code
  7. Hosting plan: 现在一个消费计划,Azure Fuctions计费已次计算,很便宜。具体参考Azure functions定价
  8. Location: 选择一个资源的位置,中国速度最快应该是东亚地区
  9. Application Insights: 用于记录日志定位问题
    xxxx

点击创建过几分钟之后,会提示创建成功。
xxxx

然后我们选择VS Code作为开发环境
xxxx

提示我们需要安装所需工具,在上一篇博文中,我们介绍安装了开发Azure Functions的工具。这里不再赘述。
xxxx

我们推荐在VS Code中安装两个扩展:

  1. Azure Account: 整合Azure账户和VS Code.
  2. Azure Functions: 帮助我们创建,维护,管理,部署function
    xxxx

下一步我们登录的我们的Azure账号,然后我们就可以看到我们刚刚建立的Function App
xxxx

现在可以使用Azure Functions扩展床一个HTTP trigger的function
xxxx

然后输入Function名称,选择‘Function’作为缱绻等级
xxxx
xxxx

现在我们已经创建了一个function。主文件是index.js。这是一个模版,它接受一个get或post请求,在参数中如果有name字段,则返回“Hello ” + (req.query.name || req.body.name),否则返回400错误.
xxxx

另外一个重要的文件是function.json,它包含了一些配置。比较常用的配置是HTTP请求方式。你可以选择GET, POST, PUT, DELETE, OPTIONS等。
xxxx

测试你的Function然后部署到Azure

本地运行之后,我们可以断点进行调试。
xxxx

接下来我们要部署到这个function,选中function名称,右键,选择“Deploy to Function App…”
xxxx

选择你想部署到的Fnction App
xxxx
xxxx
xxxx

如果没有问题,我们可以收到一个部署成功的提示
xxxx

总结

使用VS Code开发是非常高效的,它集合Azure官方的扩展,所以很容易地本地开发和部署到Azure。

前言

Azure functions之前先来说说Serverless。Serverless是最近很火的一个概念,它是一种基于互联网的技术架构理念,应用逻辑并非全部在服务端实现,而是采用FAAS(Function as a Service)架构,通过功能组合来实现应用程序逻辑。应用业务逻辑将基于FAAS架构形成独立为多个相互独立功能组件,并以API服务的形式向外提供服务;很多公司都在自己的云平台推出了FAAS,比如Amazon Lambda,Azure Function,Google Cloud Functions,阿里云Function Compute等。

微软的Azure functions是基于Azure的无服务器计算服务,可以快速的帮助用户构建一个基于事件驱动的应用架构。用户无需关心服务器的部署运营,只需专注于核心的逻辑,既可以发布上线。费用按照实际调用次数与时长计费,自动缩放,仅在运行函数时为计算资源付费。更棒的是Azure Functions支持C#,Python,Javascript,TypeScript,F#和Java,本文带大家快速看在本地搭建Javascript开发环境开发Azure Functions。

环境安裝

可以使用Visual Studio CodeVisual Studio开发,本文将会使用的VS Code。

首先在扩展市场中搜索Azure functions,你也可以直接安裝Azure App Service,这样你就拥有所有相关扩展服务,也可以仅安裝Azure Functions。

![Azure Function扩展](/images/Azure Function Ext.jpg)

接著,我们要安裝 Azure Function Core Tools,在命令行安装:

1
2
3
4
5
6
7
8
9
10
#via npm
npm i -g azure-functions-core-tools --unsafe-perm true

#Linux
wget -q https://packages.microsoft.com/config/ubuntu/19.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb

#Mac
brew tap azure/functions
brew install azure-functions-core-tools

或者我们可以点击Debug | Run, VS Code会自动提示安装Azure Function Core Tools,确定后自动执行上方命令。

![Azure Function Core Tools 自动安装](/images/Azure Function Debug1.jpg)

安裝成功之后,我们可以在命令行输入 func 来检查是否安装成功。

![Azure Function Core Tools 安装成功](/images/Azure Function Core Tools.jpg)

出现 闪电 就说明安装成功了!

##预告

下一篇博文将会讲到 如何快速部署Azure Function

普通数组:

1
let fruits = [`bananas`, `Apples`, `Oranges`];

很简单,一行搞定:

1
fruits.sort();

但是要注意数组中不同字符串的大小写不一致… 大写的字符会被排在小写字符之前😂
所以还有其他的步骤:

1
2
3
4
5
6
7
let fruits = [`bananas`, `Apples`, `Oranges`];
fruits.sort((a, b) => {
return a.toLowerCase().localeCompare(b.toLowerCase());
})
console.log(fruits);

// ["Apples", "bananas", "Oranges"]

对象数组(按对象键值排序)

对对象数组的排序会变得很稍微更复杂一些。经常我们会在处理JSON API的时候遇到。

1
2
3
4
5
6
7
8
9
10
11
let fruits = [
{
fruit: `Bananas`
},
{
fruit: `apples`
},
{
fruit: `Oranges`
}
];

我们可以为此写一个排序函数,但是更进一步我们需要一个更通用的方法把需要排序的键以参数的形式传进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const propComparator = (propName) =>
(a, b) => a[propName].toLowerCase() == b[propName].toLowerCase() ? 0 : a[propName].toLowerCase() < b[propName].toLowerCase() ? -1 : 1
So now we can use it to sort:

fruits.sort(propComparator(`fruit`));
console.log(fruits);

/*
[
{fruit: "apples"},
{fruit: "Bananas"},
{fruit: "Oranges"}
]
*/

普通对象

如果我们有个对象是这样的:

1
2
3
4
5
let fruits = {
Bananas: true,
apples: false,
Oranges: true
};

我们依然可以将那些键小写化,然后我们先排序键的数组,然后用排序好的键数组建一个新对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let sortedFruits = {};
Object.keys(fruits).sort((a, b) => {
return a.toLowerCase().localeCompare(b.toLowerCase());
}).forEach(function(key) {
sortedFruits[key] = fruits[key];
});
console.log(sortedFruits);

/*
{
apples: false,
Bananas: true,
Oranges: true
}
*/

对象数组(按对象键排序)

1
2
3
4
5
6
7
8
9
10
11
let fruits = [
{
Bananas: true
},
{
Apples: false
},
{
oranges: true
}
];

可能这是上述情况中最复杂,但是结合所有的方法,其实也很简单🐶