---
author: Danny Morabito
category: 技术
comments_data:
- date: '2016-01-25 20:37:00'
  message: 这也能叫操作系统？你待么逗我？？？顶多顶多算得上Linux下的一款应用罢了……
  postip: 182.148.111.89
  username: fanbt [Firefox 43.0|Fedora]
- date: '2016-01-25 21:36:34'
  message: 这和现在直接在Linux上运行nodejs有什么区别？
  postip: 175.43.121.13
  username: 来自福建泉州的 Sina Weibo 5.7|iOS 9.2 用户
- date: '2016-01-26 14:50:20'
  message: 这个教程写得好，如果高校教材或编程的书都写成这样，天朝编程人才怎么的也能比现在多十个以的数量级，比起我朝上国，世界顶级大牛还是阿三哥籍的多啊
  postip: 60.223.221.28
  username: 来自山西晋中的 Chrome 39.0|Windows XP 用户
- date: '2016-01-26 22:27:51'
  message: 这和直接运行node.js或是python没什么区别。
  postip: 36.62.184.114
  username: 哲学传播者 [Chrome 47.0|GNU/Linux]
- date: '2016-02-02 10:19:33'
  message: 如果说这个是大财，那么Firefox OS还不飞天上去了
  postip: 121.52.226.236
  username: 来自浙江杭州的 Firefox 44.0|Ubuntu 用户
- date: '2016-02-02 10:48:26'
  message: ffmpeg（libav）的作者不是已经把linux内核移植到js平台了吗？那才算真正的基于Javascript的系统吧。
  postip: 211.143.202.74
  username: 来自福建莆田的 Firefox 44.0|GNU/Linux 用户
- date: '2016-02-03 08:51:59'
  message: 居然有 4 个赞，那个其实把模拟器或虚拟机的代码转译为 Javascript，最近那个在浏览器运行 Windows 95 的原理也是这样。
  postip: 118.122.120.235
  username: 来自四川成都的 Chrome 48.0|GNU/Linux 用户
- date: '2016-02-03 15:39:59'
  message: 仔细一看，确实是我注意看，抱歉。项目名称是jslinux，但全名是Javascript PC Emulator，即仍是虚拟机。
  postip: 112.47.6.49
  username: 来自福建的 Firefox 44.0|GNU/Linux 用户
count:
  commentnum: 8
  favtimes: 1
  likes: 0
  sharetimes: 0
  viewnum: 16565
date: '2016-01-25 17:40:00'
editorchoice: false
excerpt: 我想大多数人听说过 Node.js，但是你听说过 NodeOS 吗？没错，NodeOS，一个用 Node.js 写的操作系统。好吧，实话说，NodeOS
  用 Linux 内核来处理各种底层任务，比如硬件通讯什么的，但是除此之外，使用的都是 Node.js。NodeOS 的开发始于两年前，创建者的目的很简单，他只是好奇，“是否有可能仅使用
  Node.js 创建一个操作系统呢？”
fromurl: http://www.toptal.com/nodejs/nodeos-the-javascript-based-operating-system
id: 6931
islctt: true
largepic: /images/p/201601/25/174057ew38q31r82y9yk2c.jpg
permalink: /article-6931-1.html
pic: /images/p/201601/25/174057ew38q31r82y9yk2c.jpg.thumb.jpg
related: []
reviewer: ''
selector: ''
summary: 我想大多数人听说过 Node.js，但是你听说过 NodeOS 吗？没错，NodeOS，一个用 Node.js 写的操作系统。好吧，实话说，NodeOS
  用 Linux 内核来处理各种底层任务，比如硬件通讯什么的，但是除此之外，使用的都是 Node.js。NodeOS 的开发始于两年前，创建者的目的很简单，他只是好奇，“是否有可能仅使用
  Node.js 创建一个操作系统呢？”
tags:
- Node.js
- NodeOS
- JavaScript
thumb: false
title: 基于 JavaScript 的操作系统你听说过吗？
titlepic: false
translator: wxy
updated: '2016-01-25 17:40:00'
---

我想大多数人听说过 Node.js，但是你听说过 NodeOS 吗？没错，NodeOS，一个用 Node.js 写的操作系统。好吧，实话说，NodeOS 用 Linux 内核来处理各种底层任务，比如硬件通讯什么的，但是除此之外，使用的都是 Node.js。NodeOS 的开发始于两年前，创建者的目的很简单，他只是好奇，“是否有可能仅使用 Node.js 创建一个操作系统呢？” 


![](/images/p/201601/25/174057ew38q31r82y9yk2c.jpg)


*是否有可能仅使用 Node.js 创建一个操作系统呢？*


### 这个主意怎么样？


我们已经看到了 Node.js 在这几年已经取得如此迅猛的发展，那么我们为何不让它更酷一些呢？比如用它做个操作系统。


### 用户自主的独立文件系统


NodeOS 引入了一个有趣的特性：所有的用户都有一个独立的文件系统，他们在一个简单的文件系统中完成各种工作。因为他们的“主目录”事实上就是他们自己的文件系统的根（root），所以他们可以不需要任何超级权限就可以将软件包安装到系统中，也不需要配置什么，因为软件包默认就安装在他们自己的主目录里面。此外，这样也提供了良好的安全性，如果黑客攻入到了某个账户，那么只能访问到该用户所在的部分，最终的结果就是黑客并不能由此影响到整个系统。


### Node.js 和 NPM


你可以想想，如果一个操作系统使用 Node.js，那就意味着所有在 NPM 中可用的包同时也都是 NodeOS 的软件包。在写作本文时，已经有了超过 21 万的软件包，而且每分每秒都在不断增长。如果几年以后，NodeOS 有了一百万应用，那也没什么好奇怪的。


### 基于 Linux 内核


这看起来并不算什么，Linux 是大多数服务器所采用的操作系统。因为 NodeOS 是基于 Linux 内核的，所以你只需要很少的修改就可以使用那些给其它的 Linux 发行版开发的应用了。


### 不好的消息


我非常希望 NodeOS 是一个已经完成的作品，但是，它现在还不是。它仍然缺少一些服务器操作系统所必需的关键功能。比如，缺失完整的 BASH 工具集，包括 ps、tail、nano 和 grep 等都没有。更糟糕的是，你也不能把它当成桌面操作系统使用，因为它没有 GUI。当然，你可以实现一些缺失的功能，只需要使用一点点 JavaScript，但是默认情况下，这些功能现在都还没有，真糟糕。


### 好吧，那我可以试试 NodeOS 吗？



#### 使用 Docker 来体验


最容易、最快捷的体验 NodeOS 的方法如下：


1. 一台运行 Mac OSX 或 Linux 计算机，也许 Windows 也可以，但是我没试过。
2. Docker。


当你安装好 Docker 之后，运行一个 NodeOS 实例是很容易的。你只需要执行如下命令就可以了， Docker 会为你完成这魔法般的一切：



```
sudo docker run -t -i nodeos/nodeos

```

![](/images/p/201601/25/174059uahhh3r00z034uh0.jpg)


*最容易、最快捷的体验 NodeOS 的方法是通过 Docker。*


当你运行了上述命令，Docker 会自动从仓库下载 NodeOS 的镜像，并将其安装到一个虚拟环境中。安装好之后，会打开一个连接到 NodeOS 的 SSH 会话。


#### 不用 docker 呢？


有些情况下你也许不能使用 Docker 来体验，或者是你想体验一下最新版本的 NodeOS 。在写作本文时，NodeOS 的镜像已经是两个月前生成的了，而开发版本则是六天前更新的。所以，如果你希望使用最新版本，你应该从源代码开始。这也不算很难，但是要花费一些时间。你需要：


1. 一台运行 Linux 的计算机。你可以在 OS X 上编译它，但是跨平台编译需要花费很多时间，对于 Windows 也如此。
2. Linux 编译构建相关的工具（make、g++、gcc、autoconf）。
3. Qemu。
4. 时间，真的需要很多。


如果万事俱备，你就可以从源代码开始编译了：


1. 下载项目源代码：`bash git clone git@github.com:NodeOS/NodeOS.git`。
2. 使用下列命令编译： `cd NodeOS` 并 `npm install`。
3. 我逐字引用了其官方文档的话：“拿上爆米花去看场电影吧，不开玩笑，真的。”，是的，它需要很多时间，做些有意思的事情去吧。
4. 执行 `bash npm start` 来在 Qemu 中运行 NodeOS。


#### 可以工作了吗？


当安装完成后，我们可以通过在 NodeOS 的 shell 中执行 `ls`命令来看看它是否工作了。输出类似如下：



```
[ 'etc', 'lib', 'lib64', 'root', 'bin', 'sys', 'usr', 'share', 'proc' ]

```

如果显示如上，说明一些基本的命令可以工作了。但是如果我们想要知道网卡地址呢？在 Linux 下，这个命令是 `ifconfig` ，让我们试试：



```
command not found: ifconfig

```

看起来没有 `ifconfig` 命令。这是因为 NodeOS 默认没有 `ifconfig`命令。现在怎么办？很简单，NodeOS 有一个集成的包管理器（类似 `apt` 或 `yum`） ，叫做 `npkg`，它是基于 Node 的 NPM 的，很容易使用。可以通过如下命令很方便的安装 `ifconfig` ：



```
npkg install bin-ifconfig

```

如果一切正常， `ifconfig` 命令现在就可以在 shell 中使用了。我们再次试着执行一下，输出类似如下：（我替换了其中的 MAC 地址）：



```
eth0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
  ether 01:23:45:67:89:ab 
  inet6 f0cd::ef01:0203:0405:181%en1 prefixlen 64 scopeid 0x5 
  inet 192.168.0.21 netmask 0xffffff00 broadcast 192.168.0.21
  nd6 options=1<PERFORMNUD>
  media: autoselect
  status: active

```

如果你的输出也类似如上，那说明它可以工作了。你已经成功地安装了你的第一个 NodeOS 应用： `ifconfig`。


### 它是可以工作了，然而我们可以用这个操作系统做什么呢？


如果我们只能拿这个用 Node.js 写的操作系统做到你在 Ubuntu 或其它 Linux 发行版上一样的（或更少的）事情，那它有什么价值？其实，整个事情中最有趣的地方是所有的东西都是 Node.js 开发的。这意味着我们可以只需要使用 Node.js 就可以[开发](http://www.toptal.com/nodejs/why-the-hell-would-i-use-node-js)我们的应用了。比如，NodeOS 里没有默认实现的 man 命令，它用于显示其它命令的帮助信息。不用担心，实现它很简单。 


![](/images/p/201601/25/174102s3pd0f26i00z15pf.jpg)


*使用 Node.js 构建一个 NodeOS 应用*


首先让我们来安装一个叫做 Hipster 的文本编辑器，以便我们可以创建和编辑文件。执行如下命令： `npm install -g hipster@0.15.0`。这个文本编辑器很简单，除了用作文本编辑之外啥也干不了，不过对于我们来说足够了。


用 Hipster 创建文件很简单，运行 `hip filename`即可，如： `hip package.json`。要保存文件请按下 `Ctrl + s` ，退出按下 `Ctrl + q`。


在这里，我们使用了一个 NodeOS 的主开发人员所开发的代码，我自己并没有真的去开发这个应用。我们例子中的原始代码可以在 [node-bin-man Git 仓库](https://github.com/groundwater/node-bin-man)中找到。


让我们回过头来创建我们的第一个 NodeOS 应用。像每个 Node.js 应用（或 NPM 包）一样，我们从创建一个 `package.json` 文件开始，内容如下：



```
{
  "name": "bin-man",
  "version": "0.0.1",
  "description": "Format and display manual pages",
  "bin": {
    "man": "man.js"
  },
  "repository": "https://github.com/groundwater/node-bin-man",
  "author": "groundwater",
  "license": "MIT",
  "dependencies": {
    "blessed": "~0.0.22"
  }
}

```

这些参数 `name`、`version`、 `author`、 `repository`、 `license`和 `description` 是其意自明的。这个 `bin` 集合是一个 JSON 的键值对对象，包含了命令名及其关联的 JavaScript 文件。在我们的例子中， `man` 命令关联到 `man.js`文件。而 `dependencies`集合包含了这个应用所需要的 NPM 包的列表。在我们的例子中，代码的作者包含了 Blessed 包，这是一个类 curses 的库，可以让 Node.js 支持高级终端界面的 API。


现在我们进入了主要的部分，实际的代码。



```
#!/usr/bin/env node

```

这个部分叫做<ruby> <a href="/article-3664-1.html">  释伴 </a> <rp>  （ </rp> <rt>  shebang </rt> <rp>  ） </rp></ruby>。NodeOS 实际上并不需要它，但是它用于告诉操作系统如何执行下面的代码。在这里的意思是，它告诉系统下面的每行代码都需要通过 `/usr/bin/env node`命令来解释执行。



```
var fs = require('fs');
var blessed = require('blessed');

```

像在 Node.js 中一样， `require()` 函数加载选定的包到内存中，并将其保存为特定的变量。



```
var arg = process.argv[2] || 'bin-man';

```

 `man` 命令的标准行为是如果没有指定要查看的命令时，就显示它自己的帮助信息。在我们的代码示例中也一样：如果没有给出第二个参数（第一个参数是 man 本身），那么该参数的默认值是 bin-man。



```
var path = process.env.HOME + "/lib/node_modules/" + arg + "/README.md";

try{
  var readme = fs.readFileSync(path, 'utf-8');
}catch(e){
  console.log('No README.md for Package ',arg);
  process.exit(-1);
}

```

在这里，程序检查给定的应用是否有一个 readme 文件。在 NodeOS 中，每个应用的安装路径是其主目录（/）下的 `lib/node_modules`。如果 `README.md` 文件存在，就将其内容保存到 `readme`变量中。否则，显示一个错误信息并退出。



```
// Create a screen object.
var screen = blessed.screen();

var box = blessed.box({
  content: readme,
  alwaysScroll:true,
  scrollable: true,
});

// Append our box to the screen.
screen.append(box);

```

Blessed 有一个非常简单的 API，要显示一个文件的内容很容易，只需要创建一个 `box` ，然后载入内容即可。



```
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

```

现在，让我们找个退出 `man` 应用的方法。我们组合了 `escape`、 `q` 或 emacs 风格的 `C-c` 来退出应用。



```
screen.key(['space','f','j','n'], function(ch, key) {
  box.scroll(box.height);
  screen.render();
});

screen.key(['down'], function(ch, key) {
  box.scroll(1);
  screen.render();
});

screen.key(['up'], function(ch, key) {
  box.scroll(-1);
  screen.render();
});

screen.key(['b','k','p'], function(ch, key) {
  box.scroll(-box.height);
  screen.render();
});

```

我们使用方向键来上滚和下滚，用 `space`、 `f`、 `j` 或 `n` 向下翻页，`b`、 `k` 或 `p` 向上翻页。



```
box.focus();
screen.render();

```

最后，我们让应用将输入焦点放到 `box` ，我们在这里创建和渲染所有内容。


把上面编辑的这个文件存放到 `/lib/node_modules/bin-man` 目录下（名字是 `man.js`），并加一个简单的 `README.md` ，类似如下：



```
# Man

Author: @groundwater

## Install

npkg install bin-man

## Usage

```
Usage: man PKGNAME

Display a packages README.md file
```

```

我们已经基本完成了我们的第一个 NodeOS 定制应用。最后剩下一小步了，我们需要创建一个 NodeOS 应用需要的配置文件。很简单，把它创建到 `/etc/bin-man/config.json` ，内容只是一个空的 JSON 对象： `{}`。


现在我们可以试试我们的新应用了。在 NodeOS 中运行 `man` ，它将展示我们之前创建的 readme 文件。


### 总结


如你所见，在 NodeOS 中实现任何东西都很简单，你只需要懂得 Node.js 即可。


NodeOS 很有潜力，我认为当实现了更多的功能之后它会成为一个伟大的操作系统。目前仍然需要很多工作，但是在整个Node.js 生态系统兴盛发展的形势下，万一哪天它很快地成为一个流行的操作系统也没什么好惊奇的。


你怎么看？发表你的评论让我们知道。