开拓者的,的多少个工具

在实战中学习 JavaScript 的几个工具

2016/06/07 · JavaScript · 工具

本文由 伯乐在线 - HansDo 翻译,HansDo 校稿。未经许可,禁止转载!
英文出处:developer.telerik.com。欢迎加入翻译组。

每当被问到开发者应该如何深入学习某一种语言时,我总会强调的一点是:找到适合自己的学习方法很关键。提到学习编程,多数人会立刻想到下面的方式:

  • 阅读相关书籍
  • 参加会议
  • 参加学习培训

尽管这些学习手段都是行之有效的,但对我来说,它们或多或少都有一些缺点。拿看书学习来说,我发现这种方式只有当我旁边放着一台电脑时才有效果。因为在读到某个知识点时,我必须立即试着编写几行代码并运行看看结果,这样才能完全理解它。

我非常热爱阅读,但我尽量不在电脑边读书,因为我很少能够在有电脑的情况下把注意力始终集中在书上。出于这个原因,尽管我每年读的书都不少,但只有很少的几本是技术类书籍。

参加技术会议来长长见识还可以,可很难让你深入掌握——一般他们只会花 60 分钟来介绍一种语言或某个话题,充其量鼓励你自己在会后多实践一下提到的技术。不过值得一提的是,有些会议会设置一天的「预前会」,预前会上会安排一些比较详尽的演讲和相关环节——这些环节对学习则更有裨益, 尤其是他们有时会提供实验环境,让你同演讲者一起动手实践演讲中涉及的项目代码。

最后,上课培训的方式固然可以让你在短期内取得惊人进步,但前提是你有足够的(下班后的)时间和金钱。记得两年前我参加过一个为时七天的 Big Nerd 的课程。课程本身棒极了——但也耗费了我大把大把的钱和时间。

在上面给出的建议中,我提到了在学习过程中多写一些练习代码,边「玩」边学。我发现这是用来迅速掌握新技术极其有效的途径。

所以在这篇文章里,我会介绍一些不同于上面那些常规途径的工具,来帮你「边做边学」JavaScript。这些工具都需要你编写一些代码来完成各种任务,从而帮你掌握某个具体技术点、或让你的整体技术水平得到训练和提高。我们开始吧!

图片 1

NodeJS 开发者的 10 个常见错误

2015/06/16 · CSS · 1 评论

本文由 伯乐在线 - 刘健超-J.c 翻译,黄利民 校稿。未经许可,禁止转载!
英文出处:www.toptal.com。欢迎加入翻译组。

自 Node.js 公诸于世的那一刻,就伴随着赞扬和批评的声音。这个争论仍在持续,而且并不会很快消失。而我们常常忽略掉这些争论产生的原因,每种编程语言和平台都是因某些问题而受到批评,而这些问题的产生,是取决于我们如何使用这个平台。不管有多难才能写出安全的 Node.js 代码,或有多容易写出高并发的代码,该平台已经有相当长一段时间,并已被用来建立一个数量庞大、稳健和成熟的 web 服务器。这些 web 服务器伸缩性强,并且它们通过在 Internet 上稳定的运行时间,证明自己的稳定性。

然而,像其它平台一样,Node.js 容易因开发者问题而受到批评。一些错误会降低性能,而其它一些问题会让 Node.js 直接崩溃。在这篇文章里,我们将会聊一聊关于 Node.js 新手的 10 个常犯错误,并让他们知道如何避免这些错误,从而成为一名 Node.js 高手。

图片 2

全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) 。

Js-assessment (js-测验)

第一个工具是 Rebecca Murphey 写的 js-assessment , 它的核心其实就是一组测试用例。每条测试用例都代表一个需要你解决的问题。当你通过修改代码让某条测试通过,你也就完成了相应知识点的测验。

来看一 个 arrays 文件里的简单的例子:

JavaScript

indexOf : function(arr, item) { },

1
2
3
indexOf : function(arr, item) {
 
},

如你所见,这里给出了一个空函数和它的参数,你需要实现该函数的内部逻辑来让它按照期望的方式工作,从而让相应的自动化测试用例成功。不过有的时候你需要实现什么样的功能并不容易一眼就看出来,比如同样在 arrays 文件里有这样一个函数:

JavaScript

curtail : function(arr) { },

1
2
3
curtail : function(arr) {
 
},

我研究了一番才搞明白(但这就是学习的过程,对吧?),原来它应该实现的功能是删除数组中的第一个元素。

在编写代码的过程中,你可以随时在浏览器里查看当前所有测试用例的执行结果。下图显示的是我完成其中一部分测验时的状态。

图片 3

关于这个项目我最喜欢的一点是:你可以一次只搞定一个测试用例,从而一点点地完成整个项目,而不用一次性投入太多时间。

介绍

NodeSchool 是一个针对初学者,教授 Web 开发技能的免费开源教程(NodeSchool 包含一堆教程,不仅仅是 Node.js 的)。

NodeSchool 的教程由一系列任务构成,每个任务除了常规的描述,还有详细的提示。如下图所示:

图片 4

错误 #1:阻塞事件循环

JavaScript 在 Node.js (就像在浏览器一样) 提供单线程执行环境。这意味着你的程序不能同时执行两部分代码,但能通过 I/O 绑定异步回调函数实现并发。例如:一个来自Node.js 的请求是到数据库引擎获取一些文档,在这同时允许 Node.js 专注于应用程序其它部分:

JavaScript

// Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked.. // 尝试从数据库中获取一个用户对象。在这个函数执行的一刻,Node.js 有空去运行代码其它部分.. db.User.get(userId, function(err, user) { // .. until the moment the user object has been retrieved here // .. 直到用户对象检索到这里的那一刻 })

1
2
3
4
5
6
// Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked..
// 尝试从数据库中获取一个用户对象。在这个函数执行的一刻,Node.js 有空去运行代码其它部分..
db.User.get(userId, function(err, user) {
// .. until the moment the user object has been retrieved here
        // .. 直到用户对象检索到这里的那一刻
})

图片 5

然而,具有计算密集型代码的 Node.js 实例被数以万计客户端同时连接执行时,会导致阻塞事件循环,并使所有客户端处于等待响应状态。计算密集型代码,包括尝试给一个庞大数组进行排序操作和运行一个格外长的循环等。例如:

JavaScript

function sortUsersByAge(users) { users.sort(function(a, b) { return a.age > b.age ? -1 : 1 }) }

1
2
3
4
5
function sortUsersByAge(users) {
users.sort(function(a, b) {
return a.age > b.age ? -1 : 1
})
}

基于小 “users” 数组执行 “sortUserByAge” 函数,可能没什么问题,当基于庞大数组时,会严重影响整体性能。如果在不得不这样操作的情况下,你必须确保程序除了等待事件循环而别无他事(例如,用 Node.js 建立命令行工具的一部分,整个东西同步运行是没问题的),然后这可能没问题。然而,在 Node.js 服务器实例尝试同时服务成千上万个用户的情况下,这将是一个毁灭性的问题。

如果用户数组是从数据库检索出来的,有个解决办法是,先在数据库中排序,然后再直接检索。如果因需要计算庞大的金融交易历史数据总和,而造成阻塞事件循环,这可以创建额外的worker / queue 来避免阻塞事件循环。

正如你所看到的,这没有新技术来解决这类 Node.js 问题,而每种情况都需要单独处理。而基本解决思路是:不要让 Node.js 实例的主线程执行 CPU 密集型工作 – 客户端同时链接时。

GUID是一种由算法生成的二进制长度为128位的数字标识符。GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中的 x 是 0-9 或 a-f 范围内的一个32位十六进制数。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。

NodeSchool

NodeSchool  并不只是 Node.js,事实上它包括了关于JavaScript 的各种教程。课程覆盖了从 JavaScript 基础到 Node(既然叫NodeSchool当然要有Node。) 甚至 WebGL 的内容。你可以先安装最感兴趣的教程, 可如果还不熟悉 JavaScript 的话,我推荐从 javascripting 课程开始。

Shell

npm install -g javascripting

1
npm install -g javascripting

然后只需要在命令行里输入 javascripting

图片 6

这个赏心悦目的古典风格菜单会提示你选择一个子课程,然后具体的指导和练习信息就会显示出来。

图片 7

注意上面最后两行内容,这个命令行程序 javascripting 还能够验证你写的程序是否符合要求。你只要写好解题代码,然后到命令行里去完成验证就可以完成相应的子课程了。

下面是验证被我故意写错的代码时的输出:

图片 8

你可以看到这里的帮助信息相当详尽—— 其实还有更多的信息没有展示出来,因为屏幕上实在显示不下了。当然,javascripting 毕竟是给没接触过 JS 的人准备的课程。虽然我不认为其他的教程也会提供这么多帮助,但我目前还没被什么问题难倒过。这里的问题一般一分钟内就可以解决——最多也就30分钟。这个程序还会随着你的进度贴心地标记出你完成的练习,以及还有哪些挑战等着你。

图片 9

前面我说到,你可以在 NodeSchool 找到各种类型的教程。他们还有一个关于 ES6 的课程,所以如果你想获得一些关于这项热门技术的上手经验,NodeSchool 会是一个能帮你迅速掌握它的绝佳选择。

Node.js 教程的安装

第 1 步 安装: Node.js
Windows 有 .exe 的安装包,Mac 用 Homebrew 安装。在命令行中执行 node -v, 显示 Node.js 的版本号表示安装成功。

第 2 步: 安装 NodeSchool
在命令中执行如下命令:

npm install -g learnyounode

在命令行中执行 learnyounode, 若出现如下图所示的学习目录,则表示安装成功。

图片 10

看到都是英文?别怕,可以将语言切换成中文。方法:执行learnyounode,按键盘上的下移键,将光标移动到CHOOSE LANGUAGE 按回车,选择简体中文 按回车即可。切换后如下图所示:

图片 11

错误 #2:调用回调函数多于一次

JavaScript 一直都是依赖于回调函数。在浏览器中,处理事件是通过调用函数(通常是匿名的),这个动作如同回调函数。Node.js 在引进 promises 之前,回调函数是异步元素用来互相连接对方的唯一方式 。现在回调函数仍被使用,并且包开发者仍然围绕着回调函数设计 APIs。一个关于使用回调函数的常见 Node.js 问题是:不止一次调用。通常情况下,一个包提供一个函数去异步处理一些东西,设计出来是期待有一个函数作为最后一个参数,当异步任务完成时就会被调用:

JavaScript

module.exports.verifyPassword = function(user, password, done) { if(typeof password !== ‘string’) { done(new Error(‘password should be a string’)) return } computeHash(password, user.passwordHashOpts, function(err, hash) { if(err) { done(err) return } done(null, hash === user.passwordHash) }) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports.verifyPassword = function(user, password, done) {
if(typeof password !== ‘string’) {
done(new Error(‘password should be a string’))
return
}
 
computeHash(password, user.passwordHashOpts, function(err, hash) {
if(err) {
done(err)
return
}
 
done(null, hash === user.passwordHash)
})
}

注意每次调用 “done” 都有一个返回语句(return),而最后一个 “done” 则可省略返回语句。这是因为调用回调函数后,并不会自动结束当前执行函数。如果第一个 “return” 注释掉,然后给这个函数传进一个非字符串密码,导致 “computeHash” 仍然会被调用。这取决于 “computeHash” 如何处理这样一种情况,“done” 可能会调用多次。任何一个人在别处使用这个函数可能会变得措手不及,因为它们传进的该回调函数被多次调用。

只要小心就可以避免这个 Node.js 错误。而一些 Node.js 开发者养成一个习惯是:在每个回调函数调用前添加一个 return 关键字。

JavaScript

if(err) { return done(err) }

1
2
3
if(err) {
return done(err)
}

对于许多异步函数,它的返回值几乎是无意义的,所以该方法能让你很好地避免这个问题。

GUID 的总数达到了2^128(3.4×10^38)个,所以随机生成两个相同GUID的可能性非常小,但并不为0。GUID一词有时也专指微软对UUID标准的实现。

Advent of Code(代码降临,又名邪恶之塔)

接下来这个是我最爱——呃或者是最讨厌的一个项目——好吧,我就是这样一个反复无常的人。 在去年的圣诞季,作者发布 Advent of Code 的时候,他声称这是一种可以用来「轻松愉快地」打发圣诞节假期的方式。这里面的每个编程挑战都跟圣诞节主题相关,而且每个都包含两个问题。不过一般情况下,只需要在第一道题的答案上做很小改动就能得到第二道的答案。

图片 12

这些题目并不限定使用的编程语言,所以你可以用它来学习任何语言,而不仅是 JavaScript。刚开始的第一道题很容易:

图片 13

要完成这一题,只要读取给定的那个很长的输入字符串、解析它的内容并进行简单统计就可以了。下面是我的解题代码——是的,我知道这并不是最好的解法,不过对我来说够用了。

JavaScript

var input = '()(((( LOTS OF TEXT REMOVED ()('; var floor = 0; for(var i=0;i<input.length;i ) { var char = input.charAt(i); if(char === '(') floor ; if(char === ')') floor--; } console.log("Done - " floor);

1
2
3
4
5
6
7
8
9
10
11
var input = '()((((  LOTS OF TEXT REMOVED ()(';
 
var floor = 0;
 
for(var i=0;i<input.length;i ) {
    var char = input.charAt(i);
    if(char === '(') floor ;
    if(char === ')') floor--;
}
 
console.log("Done - " floor);

这一题的第二部分也很简单 ——我只花了大约一分钟时间改了一下代码,就能让代码在循环中保存符合条件的那个值了。

看上去有点儿意思对吧?可是这些题目的难度很快就会上升到让人灰心丧气的水平(至少对我而言)。比如第24题:给你一组包裹和他们的重量信息,你需要把这些包裹分为三组,并保证每个组里包裹的重量之和相等。噢对了,要保证第一组的包裹数量是最小的,这样圣诞老人才有地方坐…噢还有!第一组还要保证最小的“量子纠缠态”—— 这个值是将所有包裹的重量相乘求积得来的。

在做这一题的时候,我作弊了… 事实上我大概一共没羞没臊地作弊了四题。这些题目都有对应的 Reddit 博客链接,你可以在上面学习别人的解法。对于那几道难住我的题,我在那里找到了其他语言实现的解法,并利用他们的解题思路转换成 JavaScript 完成了挑战。

开始学习

在命令行中执行 learnyounode 。选择想学的课程,按回车键,开始学习。

如果读了任务的描述和提示,你还是不知道无从下手,可以到讨论区提问。

错误 #3:函数嵌套过深

函数嵌套过深,时常被称为“回调函数地狱”,但这并不是 Node.js 自身问题。然而,这会导致一个问题:代码很快失去控制。

JavaScript

function handleLogin(..., done) { db.User.get(..., function(..., user) { if(!user) { return done(null, ‘failed to log in’) } utils.verifyPassword(..., function(..., okay) { if(okay) { return done(null, ‘failed to log in’) } session.login(..., function() { done(null, ‘logged in’) }) }) }) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function handleLogin(..., done) {
db.User.get(..., function(..., user) {
if(!user) {
return done(null, ‘failed to log in’)
}
utils.verifyPassword(..., function(..., okay) {
if(okay) {
return done(null, ‘failed to log in’)
}
session.login(..., function() {
done(null, ‘logged in’)
})
})
})
}

图片 14

任务有多复杂,代码就有多糟糕。以这种方式嵌套回调函数,我们很容易就会碰到问题而崩溃,并且难以阅读和维护代码。一种替代方式是以函数声明这些任务,然后将它们连接起来。尽管,有一种最干净的方法之一 (有争议的)是使用 Node.js 工具包,它专门处理异步 JavaScript 模式,例如 Async.js :

JavaScript

function handleLogin(done) { async.waterfall([ function(done) { db.User.get(..., done) }, function(user, done) { if(!user) { return done(null, ‘failed to log in’) } utils.verifyPassword(..., function(..., okay) { done(null, user, okay) }) }, function(user, okay, done) { if(okay) { return done(null, ‘failed to log in’) } session.login(..., function() { done(null, ‘logged in’) }) } ], 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
function handleLogin(done) {
async.waterfall([
function(done) {
db.User.get(..., done)
},
function(user, done) {
if(!user) {
return done(null, ‘failed to log in’)
}
utils.verifyPassword(..., function(..., okay) {
done(null, user, okay)
})
},
function(user, okay, done) {
if(okay) {
return done(null, ‘failed to log in’)
}
session.login(..., function() {
done(null, ‘logged in’)
})
}
], function() {
// ...
})
}

类似于 “async.waterfall”,Async.js 提供了很多其它函数来解决不同的异步模式。为了简洁,我们在这里使用一个较为简单的案例,但实际情况往往更糟。

算法1

来点不一样的…

DevTools Challenger 是贯彻了“边做边学”理念的一个超级棒的的典范,尽管它的内容和 JavaScript 语言无关。它是 Rachel Nabors 开发的一套展示案例,用来演示通过 Firefox 的开发者工具来调试 CSS 动画的各种方法。

图片 15

尽管 CSS 动画不是我的菜,但我还是挺喜欢开发者工具的。在我见过的介绍开发者工具的网站里,这个项目或许是界面最漂亮、同时也是最友好的一个。

运行代码

完成任务后,可以用如下两种方式运行代码:
方式1:

node 程序文件.js

方式2:

learnyounode run 程序文件.js

错误 #4:期望回调函数以同步方式运行

异步程序的回调函数并不是 JavaScript 和 Node.js 独有的,但它们是造成回调函数流行的原因。而对于其它编程语言,我们潜意识地认为执行顺序是一步接一步的,如两个语句将会执行完第一句再执行第二句,除非这两个语句间有一个明确的跳转语句。尽管那样,它们经常局限于条件语句、循环语句和函数调用。

然而,在 JavaScript 中,回调某个特定函数可能并不会立刻运行,而是等到任务完成后才运行。下面例子就是直到没有任何任务,当前函数才运行:

JavaScript

function testTimeout() { console.log(“Begin”) setTimeout(function() { console.log(“Done!”) }, duration * 1000) console.log(“Waiting..”) }

1
2
3
4
5
6
7
function testTimeout() {
console.log(“Begin”)
setTimeout(function() {
console.log(“Done!”)
}, duration * 1000)
console.log(“Waiting..”)
}

你会注意到,调用 “testTimeout” 函数会首先打印 “Begin”,然后打印 “Waiting..”,紧接大约一秒后才打印 “Done!”。

任何一个需要在回调函数被触发后执行的东西,都要把它放在回调函数内。

复制代码 代码如下:

其他的选项

当然这一类的学习资源还有很多。下面列出了其他几个可以考虑的选项,像往常一样,我建议大家把自己使用过的类似工具发到下面的评论区里,和我们一起分享。

  • The JavaScript Warrior –  在尝试通过代码控制一个勇者的过程中学习和练习 JavaScript。
  • WarriorJS – 跟上面一个类似的编程挑战。
  • Untrusted – 用你的 JavaScript 来对抗邪恶博士!

打赏支持我翻译更多好文章,谢谢!

打赏译者

验证代码

在确定任务完成后,用如下命令验证你的程序与任务的要求是否一致:

learnyounode verify 程序文件.js

上面命令运行完成后,会生成测试报告。如果验证成功,该课程会被标记为完成。如果失败,可以在测试报告中观察程序的预期值和实际的值的差异,修改代码后,执行 learnyounode run 程序文件.js 再进行验证。

输入 learnyounode 进入下一个课程的学习。

错误 #5:用“exports”,而不是“module.exports”

Node.js 将每个文件视为一个孤立的小模块。如果你的包(package)含有两个文件,或许是 “a.js” 和 “b.js”。因为 “b.js” 要获取 “a.js” 的功能,所以 “a.js” 必须通过为 exports 对象添加属性来导出它。

JavaScript

// a.js exports.verifyPassword = function(user, password, done) { ... }

1
2
// a.js
exports.verifyPassword = function(user, password, done) { ... }

当这样操作后,任何引入 “a.js” 模块的文件将会得到一个带有属性方法 “verifyPassword” 的对象:

JavaScript

// b.js require(‘a.js’) // { verifyPassword: function(user, password, done) { ... } }

1
2
// b.js
require(‘a.js’) // { verifyPassword: function(user, password, done) { ... } }

然而,如果我们想直接导出这个函数,而不是作为某个对象的属性呢?我们能通过覆盖 exports 对象来达到这个目的,但我们不能将它视为一个全局变量:

JavaScript

// a.js module.exports = function(user, password, done) { ... }

1
2
// a.js
module.exports = function(user, password, done) { ... }

注意,我们是如何将 “exports” 作为 module 对象的一个属性。在这里知道 “module.exports” 和 “exports” 之间区别是非常重要的,并且这经常会导致 Node.js 开发新手们产生挫败感。

function uuid() {
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i ) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

图片 16 图片 17

1 赞 7 收藏 评论

更多课程

上文提到是 NodeSchool 中 Node.js 相关的教程,除此之外,NodeSchool 还包含: JavaScriptWebGL函数式编程Gitnpm 等一堆课程。这些课程可以在官网的首页中找到。

大家会用学会 NodeSchool 了吗~ 点击这里 报名,一起学起来吧!

错误 #6:在回调函数内抛出错误

JavaScript 有个“异常”概念。异常处理与大多数传统语言的语法类似,例如 Java 和 C ,JavaScript 能在 try-catch 块内 “抛出(throw)” 和 捕捉(catch)异常:

JavaScript

function slugifyUsername(username) { if(typeof username === ‘string’) { throw new TypeError(‘expected a string username, got ' (typeof username)) } // ... } try { var usernameSlug = slugifyUsername(username) } catch(e) { console.log(‘Oh no!’) }

1
2
3
4
5
6
7
8
9
10
11
12
function slugifyUsername(username) {
if(typeof username === ‘string’) {
throw new TypeError(‘expected a string username, got ' (typeof username))
}
// ...
}
 
try {
var usernameSlug = slugifyUsername(username)
} catch(e) {
console.log(‘Oh no!’)
}

然而,如果你把 try-catch 放在异步函数内,它会出乎你意料,它并不会执行。例如,如果你想保护一段含有很多异步活动的代码,而且这段代码包含在一个 try-catch 块内,而结果是:它不一定会运行。

JavaScript

try { db.User.get(userId, function(err, user) { if(err) { throw err } // ... usernameSlug = slugifyUsername(user.username) // ... }) } catch(e) { console.log(‘Oh no!’) }

1
2
3
4
5
6
7
8
9
10
11
12
try {
db.User.get(userId, function(err, user) {
if(err) {
throw err
}
// ...
usernameSlug = slugifyUsername(user.username)
// ...
})
} catch(e) {
console.log(‘Oh no!’)
}

如果回调函数 “db.User.get” 异步触发了,虽然作用域里包含的 try-catch 块离开了上下文,仍然能捕捉那些在回调函数的抛出的错误。

这就是 Node.js 中如何处理错误的另外一种方式。另外,有必要遵循所有回调函数的参数(err, …)模式,所有回调函数的第一个参数期待是一个错误对象。

    var uuid = s.join("");
    return uuid;
}

关于作者:HansDo

图片 18

游走于Web前后端,一直在野路子上摸索着。对美术和数学有心无力(・-・*),尽其所能做一个生产者。 个人主页 · 我的文章 · 18 ·    

图片 19

错误 #7:认为数字是整型

数字在 JavaScript 中都是浮点型,JS 没有整型。你可能不能预料到这将是一个问题,因为数大到超出浮点型范围的情况并不常见。

JavaScript

Math.pow(2, 53) 1 === Math.pow(2, 53)

1
Math.pow(2, 53) 1 === Math.pow(2, 53)

不幸的是,在 JavaScript 中,这种关于数字的怪异情况远不止于此。尽管数字都是浮点型,对于下面的表达式,操作符对于整型也能正常运行:

JavaScript

5 >> 1 === 2 // true

1
5 >> 1 === 2 // true

然而,不像算术运算符那样,位操作符和位移操作符只能操作后 32 位,如同 “整型” 数。例如,尝试位移 “Math.pow(2,53)” 1 位,会得到结果 0。尝试与 1 进行按位或运算,得到结果 1。

JavaScript

Math.pow(2, 53) / 2 === Math.pow(2, 52) // true Math.pow(2, 53) >> 1 === 0 // true Math.pow(2, 53) | 1 === 1 // true

1
2
3
Math.pow(2, 53) / 2 === Math.pow(2, 52) // true
Math.pow(2, 53) >> 1 === 0 // true
Math.pow(2, 53) | 1 === 1 // true

你可能很少需要处理很大的数,但如果你真的要处理的话,有很多大整型库能对大型精度数完成重要的数学运算,如  node-bigint。

算法2

错误 #8:忽略了 Streaming(流) API 的优势

大家都说想建立一个小型代理服务器,它能响应从其它服务器获取内容的请求。作为一个案例,我们将建立一个供应 Gravatar 图像的小型 Web 服务器:

JavaScript

var http = require('http') var crypto = require('crypto') http.createServer() .on('request', function(req, res) { var email = req.url.substr(req.url.lastIndexOf('/') 1) if(!email) { res.writeHead(404) return res.end() } var buf = new Buffer(1024*1024) http.get(''), function(resp) { var size = 0 resp.on('data', function(chunk) { chunk.copy(buf, size) size = chunk.length }) .on('end', function() { res.write(buf.slice(0, size)) res.end() }) }) }) .listen(8080)

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
var http = require('http')
var crypto = require('crypto')
 
http.createServer()
.on('request', function(req, res) {
var email = req.url.substr(req.url.lastIndexOf('/') 1)
if(!email) {
res.writeHead(404)
return res.end()
}
 
var buf = new Buffer(1024*1024)
http.get('http://www.gravatar.com/avatar/' crypto.createHash('md5').update(email).digest('hex'), function(resp) {
var size = 0
resp.on('data', function(chunk) {
chunk.copy(buf, size)
size = chunk.length
})
.on('end', function() {
res.write(buf.slice(0, size))
res.end()
})
})
})
.listen(8080)

在这个特殊例子中有一个 Node.js 问题,我们从 Gravatar 获取图像,将它读进缓存区,然后响应请求。这不是一个多么糟糕的问题,因为 Gravatar 返回的图像并不是很大。然而,想象一下,如果我们代理的内容大小有成千上万兆。那就有一个更好的方法了:

JavaScript

http.createServer() .on('request', function(req, res) { var email = req.url.substr(req.url.lastIndexOf('/') 1) if(!email) { res.writeHead(404) return res.end() } http.get(''), function(resp) { resp.pipe(res) }) }) .listen(8080)

1
2
3
4
5
6
7
8
9
10
11
12
13
http.createServer()
.on('request', function(req, res) {
var email = req.url.substr(req.url.lastIndexOf('/') 1)
if(!email) {
res.writeHead(404)
return res.end()
}
 
http.get('http://www.gravatar.com/avatar/' crypto.createHash('md5').update(email).digest('hex'), function(resp) {
resp.pipe(res)
})
})
.listen(8080)

这里,我们获取图像,并简单地通过管道响应给客户端。绝不需要我们在响应之前,将全部内容读取到缓冲区。

复制代码 代码如下:

错误 #9:把 Console.log 用于调试目的

在 Node.js 中,“console.log” 允许你向控制台打印几乎所有东西。传递一个对象给它,它会以 JavaScript 对象字面量的方式打印出来。它接受任意多个参数,并以空格作为分隔符打印它们。有许多个理由让开发者很想用这个来调试(debug)自己的代码;然而,我强烈建议你避免在真正程序里使用 “console.log” 。你应该避免在全部代码里使用 “console.log” 进行调试(debug),当不需要它们的时候,应注释掉它们。相反,使用专门为调试建立的库,如:debug。

当你开始编写应用程序时,这些库能方便地启动和禁用某行调试(debug)功能。例如,通过不设置 DEBUG 环境变量,能够防止所有调试行被打印到终端。使用它很简单:

JavaScript

// app.js var debug = require(‘debug’)(‘app’) debug(’Hello, %s!’, ‘world’)

1
2
3
// app.js
var debug = require(‘debug’)(‘app’)
debug(’Hello, %s!’, ‘world’)

为了启动调试行,将环境变量 DEBUG 设置为 “app” 或 “*”,就能简单地运行这些代码了:

JavaScript

DEBUG=app node app.js

1
DEBUG=app node app.js

function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

错误 #10:不使用管理程序

不管你的 Node.js 代码运行在生产环境还是本地开发环境,一个监控管理程序能很好地管理你的程序,所以它是一个非常有用并值得拥有的东西。开发者设计和实现现代应用时常常推荐的一个最佳实践是:快速失败,快速迭代。

如果发生一个意料之外的错误,不要试图去处理它,而是让你的程序崩溃,并有个监控者在几秒后重启它。管理程序的好处不止是重启崩溃的程序。这个工具允许你重启崩溃的程序的同时,也允许文件发生改变时重启程序。这让开发 Node.js 程序变成一段更愉快的体验。

有很多 Node.js 可用的管理程序。例如:

  • pm2
  • forever
  • nodemon
  • supervisor

所有这些工具各有优劣。一些有利于在同一个机器里处理多个应用程序,而其它擅长于日志管理。然而,如果你想开始使用这些程序,它们都是很好的选择。

算法3

总结

正如你所知道的那样,一些 Node.js 问题能对你的程序造成毁灭性打击。而一些则会在你尝试完成最简单的东西时,让你产生挫败感。尽管 Node.js 的开发门槛较低,但它仍然有很容易搞混的地方。从其它编程语言转过来学习 Node.js 开发者可能会遇到这些问题,但这些错误在 Node.js 新手中也是十分常见的。幸运的是,它们很容易避免。我希望这个简短指导能帮助 Node.js 新手写出更优秀的代码,并为我们开发出稳定高效的软件。

打赏支持我翻译更多好文章,谢谢!

打赏译者

复制代码 代码如下:

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

图片 20 图片 21

1 赞 7 收藏 1 评论

function guid() {
    function S4() {
       return (((1 Math.random())*0x10000)|0).toString(16).substring(1);
    }
    return (S4() S4() "-" S4() "-" S4() "-" S4() "-" S4() S4() S4());
}

关于作者:刘健超-J.c

图片 22

前端,在路上... 个人主页 · 我的文章 · 19 ·     

图片 23

算法4

复制代码 代码如下:

function uuid(len, radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [], i;
    radix = radix || chars.length;

    if (len) {
      // Compact form
      for (i = 0; i < len; i ) uuid[i] = chars[0 | Math.random()*radix];
    } else {
      // rfc4122, version 4 form
      var r;

      // rfc4122 requires these characters
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
      uuid[14] = '4';

      // Fill in random data.  At i==19 set the high bits of clock sequence as
      // per rfc4122, sec. 4.1.5
      for (i = 0; i < 36; i ) {
        if (!uuid[i]) {
          r = 0 | Math.random()*16;
          uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
        }
      }
    }

    return uuid.join('');
}

这个可以指定长度和基数。比如

复制代码 代码如下:

// 8 character ID (base=2)
uuid(8, 2)  //  "01001010"
// 8 character ID (base=10)
uuid(8, 10) // "47473046"
// 8 character ID (base=16)
uuid(8, 16) // "098F4D35"

您可能感兴趣的文章:

  • 浅谈js中字符和数组一些基本算法题
  • javascript算法题:求任意一个1-9位不重复的N位数在该组合中的大小排列序号
  • javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
  • js交换排序 冒泡排序算法(Javascript版)
  • js数组去重的5种算法实现
  • 很好用的js日历算法详细代码
  • javascript常用经典算法实例详解
  • Javascript中的常见排序算法
  • 一个简单的JavaScript 日期计算算法
  • 面试常见的js算法题

本文由星彩网app下载发布于前端技术,转载请注明出处:开拓者的,的多少个工具

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。