什么应用可以中断微信备份网络中断语音

Javascript内存泄漏 - 文章 - 伯乐在线
& Javascript内存泄漏
1.什么是内存泄漏?
内存泄漏是指分配给应用的内存不能被重新分配,即使在内存已经不被使用的时候。正常情况下,垃圾回收器在DOM元素和event处理器不被引用或访问的时候回收它们。但是,IE的早些版本(IE7和之前)中内存泄漏是很容易出现的,因为内存管理器不能正确理解Javascript生命周期而且在周期被打破(可以通过赋值为null实现)前不会回收内存。
2.为什么你需要注意它?
在大型Web应用程序中内存泄漏是一种常见的意外编程错误。内存泄漏会降低Web应用程序的性能,直到浪费的内存超过了系统所能分配的,应用程序将不能使用。作为一Web开发者,开发一个满足功能要求的应用程序只是第一步,性能要求和Web应用程序的成功是同样重要的,更何况它可能会导致应用程序错误或浏览器崩溃。
3.Javascript中出现内存泄漏的主要原因是什么?
1)循环引用
一个很简单的例子:一个DOM对象被一个Javascript对象引用,与此同时又引用同一个或其它的Javascript对象,这个DOM对象可能会引发内存泄漏。这个DOM对象的引用将不会在脚本停止的时候被垃圾回收器回收。要想破坏循环引用,引用DOM元素的对象或DOM对象的引用需要被赋值为null。
2)Javascript闭包
因为Javascript范围的限制,许多实现依赖Javascript不包,请查看我的前面的文章如果你想了解更多闭包方面的问题。
闭包可以导致内存泄漏是因为内部方法保持一个对外部方法变量的引用,所以尽管方法返回了内部方法还可以继续访问在外部方法中定义的私有变量。对Javascript程序员来说最好的做法是在页面重载前断开所有的事件处理器。
3)DOM插入顺序
当2个不同范围的 DOM 对象连添加到一起的时候一个临时的对象会被创建。这个DOM对象改变范围到document时,那个临时对象就没用了。也就是说, DOM 对象应该按照从当前页面存在的最上面的 DOM 元素开始往下直到剩下的 DOM 元素的顺序添加,这样它们就总是有同样的范围,不会产生临时对象。
4)如何检测?
内存泄漏对开发者来说一般很难检测因为它们是由一些大量代码中的意外的错误引起的,但它在系统内存不足前并不影响程序的功能。这就是为什么会有人在很长时间的测试期中收集应用程序性能指标来测试性能。
最简单的检测内存泄漏的方式是用任务管理器检查内存使用情况。在Chrome浏览器的新选项卡中打开应用并查看内存使用量是不是越来越多。还有其他的调试工具提供内存监视器,比如Chrome开发者工具。这是谷歌开者这网站中的的特性的教程。
1. /memory/leak.html
2. /en-us/library/Bb250448
3. /developerworks/web/library/wa-memleak/
更新: 23:27
此文摘要发布至微博后,: “ 其实1和2是同一个原因,而且此文漏掉一种情况,老朽很久前写过一篇旧文 ”,如下。 */
什么是内存泄露
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。在C++中,因为是手动管理内存,内存泄露是经常出现的事情。而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使用的情况下几乎不会发生内存泄露。浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。
内存泄露Quick View
不同的浏览器中存在各种内存泄露方式,目前发现的主要是这样几种:
已经确认存在泄漏的浏览器:IE6.0 FF2.0
含有DOM对象的循环引用将导致大部分当前主流浏览器内存泄露 这里有两个简单的概念
引用:a.属性=b,a就引用了b
循环引用:简单来说假如a引用了b,b又引用了a,a和b就构成了循环引用。
a和b循环引用:
JavaScript
var a=new O
var b=new O
var a=new Object;var b=new Object;a.r=b;b.r=a;
a循环引用自己:
var a=new O
var a=new Object;a.r=a;
循环引用很常见且大部分情况下是无害的,但当参与循环引用的对象中有DOM对象或者ActiveX对象时,循环引用将导致内存泄露。我们把例子中的任何一个new Object替换成document.getElementById或者document.createElement就会发生内存泄露了。
尽管这看起来非常容易理解,但是因为有closure的参与而使事情变得复杂,有些closure导致的循环引用很难被察觉。下面是一个非常常见的动态绑定事件:
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
function bindEvent(){&&&&var obj=document.createElement("XXX");&&&&obj.onclick=function(){&&&&&&&&//Even if it's a empty function&&&&}}
这个bindEvent执行时100%会发生内存泄露,Someone 可能会问,哪里出现了循环引用? 关于closure和scope chain参与的循环引用比较复杂,此处暂不深入讨论。有一个简单的判断方式:函数将间接引用所有它能访问的对象。obj.onclick这个函数中 可以访问外部的变量obj 所以他引用了obj,而obj又引用了它,因此这个事件绑定将会造成内存泄露。在中介绍了2种方式解决类似的问题一个是obj=null,另一个是把onclick的函数写在bindEvent外,重复人家的我就不说了。简单贴下代码:
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
obj.onclick=onclickH
function onclickHandler(){
//do something
function bindEvent(){&&&&var obj=document.createElement("XXX");&&&&obj.onclick=onclickHandler;}function onclickHandler(){&&&&//do something}
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
function bindEvent(){&&&&var obj=document.createElement("XXX");&&&&obj.onclick=function(){&&&&&&&&//Even if it's a empty function&&&&}&&&&obj=null;}
这两个方法都打断了循环引用,可以解决问题,但是似乎对代码表达能力造成了一定破坏,假设有这么一个问题:
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
var var0="OOXX";//Here is a variable
obj.onclick=function(){
alert(var0);//I want to visit var2 here!
//bindEvent must return obj!
function bindEvent(){&&&&var obj=document.createElement("XXX");&&&&var var0="OOXX";//Here is a variable&&&&obj.onclick=function(){&&&&&&&&alert(var0);//I want to visit var2 here!&&&&}&&&&return obj;//bindEvent must return obj!}
好了,这下两种办法都不行了,假如我把函数写外面去,var0肯定访问不了,假如我把obj弄成null,还怎么return它呢?这并不是空想的需要,这实际 上是一个用JS定制DOM控件的简单抽象:创建DOM元素、设置私有属性、绑定事件。所以,我们必须update一下两个方法。首先,方法1,为了让函数 能访问某些变量,我们可以通过一个Builder函数来订制onclick的外部闭包:
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
var var0="OOXX";//Here is a variable
obj.onclick= onclickBuilder(var0);//想访问谁就把谁传进去!!
//bindEvent must return obj!
function onclickBuilder(var0)//这里跟上面对应上就行了 最好参数名字也对应上
return function(){
alert(var0);
12345678910111213
function bindEvent(){&&&&var obj=document.createElement("XXX");&&&&var var0="OOXX";//Here is a variable&&&&obj.onclick= onclickBuilder(var0);//想访问谁就把谁传进去!!&&&&return obj;//bindEvent must return obj!}function onclickBuilder(var0)//这里跟上面对应上就行了 最好参数名字也对应上{&&&&return function(){&&&&&&&&alert(var0);&&&&}}
第二个办法,这个来自51js的chpn同学,让obj=null在return 之后执行!!
JavaScript
function bindEvent()
var obj=document.createElement("XXX");
var var0="OOXX";//Here is a variable
obj.onclick=function(){
alert(var0);//I want to visit var2 here!
//bindEvent must return obj!
} finally {
12345678910111213
function bindEvent(){&&&&try{&&&&&&&&var obj=document.createElement("XXX");&&&&&&&&var var0="OOXX";//Here is a variable&&&&&&&&obj.onclick=function(){&&&&&&&&&&&&alert(var0);//I want to visit var2 here!&&&&&&&&}&&&&&&&&return obj;//bindEvent must return obj!&&&&} finally {&&&&&&&&obj=null;&&&&}}
某些DOM操作
这是IE系列的特有问题 简单的来说就是在向不在DOM树上的DOM元素appendChild,可能会发生内存泄露(只是可能,具体原因不明,似乎十分复杂,下面例子中去掉onClick也可以避免泄露)。所以appendChild的顺序可能影响内存泄露,来自微软的例子:
&script language="JScript"&
function LeakMemory()
var hostElement = document.getElementById("hostElement");
// Do it a lot, look at Task Manager for memory response
for(i = 0; i & 5000; i++)
var parentDiv =
document.createElement("&div onClick='foo()'&");
var childDiv =
document.createElement("&div onClick='foo()'&");
// This will leak a temporary object
parentDiv.appendChild(childDiv);
hostElement.appendChild(parentDiv);
hostElement.removeChild(parentDiv);
parentDiv.removeChild(childDiv);
parentDiv =
childDiv =
hostElement =
function CleanMemory()
var hostElement = document.getElementById("hostElement");
// Do it a lot, look at Task Manager for memory response
for(i = 0; i & 5000; i++)
var parentDiv =
document.createElement("&div onClick='foo()'&");
var childDiv =
document.createElement("&div onClick='foo()'&");
// Changing the order is important, this won't leak
hostElement.appendChild(parentDiv);
parentDiv.appendChild(childDiv);
hostElement.removeChild(parentDiv);
parentDiv.removeChild(childDiv);
parentDiv =
childDiv =
hostElement =
&button onclick="LeakMemory()"&Memory Leaking Insert&/button&
&button onclick="CleanMemory()"&Clean Insert&/button&
&div id="hostElement"&&/div&
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
&/html&&&&&&&head&&&&&&&&&&&script language="JScript"&&&&&&&&&&function LeakMemory()&&&&&&&&&{&&&&&&&&&&&&&var hostElement = document.getElementById("hostElement");&&&&&&&&&&&&&// Do it a lot, look at Task Manager for memory response&&&&&&&&&&&&&for(i = 0; i & 5000; i++)&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&var parentDiv =&&&&&&&&&&&&&&&&&&&&&document.createElement("&div onClick='foo()'&");&&&&&&&&&&&&&&&&&var childDiv =&&&&&&&&&&&&&&&&&&&&&document.createElement("&div onClick='foo()'&");&&&&&&&&&&&&&&&&&// This will leak a temporary object&&&&&&&&&&&&&&&&&parentDiv.appendChild(childDiv);&&&&&&&&&&&&&&&&&hostElement.appendChild(parentDiv);&&&&&&&&&&&&&&&&&hostElement.removeChild(parentDiv);&&&&&&&&&&&&&&&&&parentDiv.removeChild(childDiv);&&&&&&&&&&&&&&&&&parentDiv = null;&&&&&&&&&&&&&&&&&childDiv = null;&&&&&&&&&&&&&}&&&&&&&&&&&&&hostElement = null;&&&&&&&&&}&&&&&&&&&function CleanMemory()&&&&&&&&&{&&&&&&&&&&&&&var hostElement = document.getElementById("hostElement");&&&&&&&&&&&&&// Do it a lot, look at Task Manager for memory response&&&&&&&&&&&&&for(i = 0; i & 5000; i++)&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&var parentDiv =&&&&&&&&&&&&&&&&&&&&&document.createElement("&div onClick='foo()'&");&&&&&&&&&&&&&&&&&var childDiv =&&&&&&&&&&&&&&&&&&&&&document.createElement("&div onClick='foo()'&");&&&&&&&&&&&&&&&&&// Changing the order is important, this won't leak&&&&&&&&&&&&&&&&&hostElement.appendChild(parentDiv);&&&&&&&&&&&&&&& parentDiv.appendChild(childDiv);&&&&&&&&&&&&&&&&&hostElement.removeChild(parentDiv);&&&&&&&&&&&&&&&&&parentDiv.removeChild(childDiv);&&&&&&&&&&&&&&&&&parentDiv = null;&&&&&&&&&&&&&&&&&childDiv = null;&&&&&&&&&&&&&}&&&&&&&&&&&&&hostElement = null;&&&&&&&&&}&&&&&&&&&&/script&&&&&&&/head&&&&&&&body&&&&&&&&&&&button onclick="LeakMemory()"&Memory Leaking Insert&/button&&&&&&&&&&&button onclick="CleanMemory()"&Clean Insert&/button&&&&&&&&&&&div id="hostElement"&&/div&&&&&&&/body&&&/html&
而在IE7中,貌似为了改善内存泄露,IE7采用了极端的解决方案:离开页面时回收所有DOM树上的元素,其它一概不管。但是这不仅没起到任何作用,反而 使问题变得更加复杂。对这类问题,除了自觉一点绕开这些恶心的东西,多用innerHTML这种无用的建议之外。我想可以通过覆盖 document.createElement来略为改善:
首先我们定义一个看不见的元素当作垃圾箱,所有新创建的元素都扔进垃圾箱里,这样保证了所有DOM元素都在DOM树上,IE7就可以正确回收了,另一方面也能避免所谓的”appendChild顺序不对导致内存泄露”。
JavaScript
function MemoryFix(){
var garbageBox=document.createElement("div");
garbageBox.style.display="none";
document.body.appendChild(garbageBox);
var createElement=document.createE
document.createElement=function(){
var obj=Function.prototype.apply.apply(createElement,[document,arguments]);
garbageBox.appendChild(obj);
123456789101112131415161718192021
function MemoryFix(){&&&&&var garbageBox=document.createElement("div");&&&&&garbageBox.style.display="none";&&&&&document.body.appendChild(garbageBox);&&&&&var createElement=document.createElement;&&&&&document.createElement=function(){&&&&&&&&&var obj=Function.prototype.apply.apply(createElement,[document,arguments]);&&&&&&&&&garbageBox.appendChild(obj);&&&&&&&&&return obj;&&&&&}&}
自动类型装箱转换
别不相信,下面的代码在ie系列中会导致内存泄露
JavaScript
var s=”lalala”;
alert(s.length);
var s=”lalala”;alert(s.length);
s本身是一个string而非object,它没有length属性,所以当访问length时,JS引擎会自动创建一个临时String对象封装s,而这个对象一定会泄露。这个bug匪夷所思,所幸解决起来相当容易,记得所有值类型做.运算之前先显式转换一下:
JavaScript
var s="lalala";
alert(new String(s).length);
var s="lalala";alert(new String(s).length);
寒冬的原文:浏览器中的内存泄露
可能感兴趣的话题
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线JavaScript的内存释放问题详解
投稿:hebedich
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了JavaScript的内存释放问题详解的相关资料,需要的朋友可以参考下
本文详细的讲解了JavaScript及IE浏览器对内存的管理和释放的时机和方法,希望对前端开发人员有所帮助。
一个内存释放的实例
&SCRIPT LANGUAGE="JavaScript"&
strTest = "1";
for ( var i = 0; i & 25; i ++ )
strTest += strT
alert(strTest);
delete strT
CollectGarbage();
CollectGarbage,是IE的一个特有属性,用于释放内存的,使用方法嘛应该是,将该变量或引用对象,设置为null或delete,然后在进行释放动作
在做CollectGarbage前,要必需清楚的两个必备条件:
引用- 一个对象在其生存的上下文环境之外,即会失效。
- 一个全局的对象在没有被执用(引用)的情况下,即会失效。
//---------------------------------------------------------
// JavaScript对象何时失效
//---------------------------------------------------------
function testObject() {
var _obj1 = new Object();
function testObject2() {
var _obj2 = new Object();
return _obj2;
testObject();
testObject2()
var obj3 = testObject2();
var obj4 = testObject2();
var arr = [obj4];
在这四个示例中:
- “示例1”在函数testObject()中构造了_obj1,但是在函数退出时,它就已经离开了函数的上下文环境,因此_obj1失效了;
- “示例2”中,testObject2()中也构造了一个对象_obj2并传出,因此对象有了“函数外”的上下文环境(和生存周期),然而由于函数的返回值没有被其它变量“持有”,因此_obj2也立即失效了;
- “示例3”中,testObject2()构造的_obj2被外部的变量obj3持用了,这时,直到“obj3=null”这行代码生效时,_obj2才会因为引用关系消失而失效。
- 与示例3相同的原因,“示例4”中的_obj2会在“arr=[]”这行代码之后才会失效。
但是,对象的“失效”并不等会“释放”。在JavaScript运行环境的内部,没有任何方式来确切地告诉用户“对象什么时候会释放”。这依赖于JavaScript的内存回收机制。——这种策略与.NET中的回收机制是类同的。
在前面的Excel操作示例代码中,对象的所有者,也就是"EXCEL.EXE"这个进程只能在“ActiveX Object实例的释放”之后才会发生。而文件的锁,以及操作系统的权限凭证是与进程相关的。因此如果对象仅是“失效”而不是“释放”,那么其它进程处理文件和引用操作系统的权限凭据时就会出问题。
——有些人说这是JavaScript或者COM机制的BUG。其实不是,这是OS、IE和JavaScript之间的一种复杂关系所导致的,而非独立的问题。
Microsoft公开了解决这种问题的策略:主动调用内存回收过程。
在(微软的)JScript中提供了一个CollectGarbage()过程(通常简称GC过程),GC过程用于清理当前IE中的“失效的对象失例”,也就是调用对象的析构过程。
在上例中调用GC过程的代码是:
//---------------------------------------------------------
// 处理ActiveX Object时,GC过程的标准调用方式
//---------------------------------------------------------
function writeXLS() {
excel.Quit();
setTimeout(CollectGarbage, 1);
第一行代码调用excel.Quit()方法来使得excel进程中止并退出,这时由于JavaScript环境执有excel对象实例,因此excel进程并不实际中止。
第二行代码使excel为null,以清除对象引用,从而使对象“失效”。然而由于对象仍旧在函数上下文环境中,因此如果直接调用GC过程,对象仍然不会被清理。
第三行代码使用setTimeout()来调用CollectGarbage函数,时间间隔设为'1',只是使得GC过程发生在writeXLS()函数执行完之后。这样excel对象就满足了“能被GC清理”的两个条件:没有引用和离开上下文环境。
GC过程的使用,在使用了ActiveX Object的JS环境中很有效。一些潜在的ActiveXObject包括XML、VML、OWC(Office Web Componet)、flash,甚至包括在JS中的VBArray。从这一点来看,ajax架构由于采用了XMLHTTP,并且同时要满足“不切换页面”的特性,因此在适当的时候主动调用GC过程,会得到更好的效率用UI体验。
事实上,即使使用GC过程,前面提到的excel问题仍然不会被完全解决。因为IE还缓存了权限凭据。使页的权限凭据被更新的唯一方法,只能是“切换到新的页面”,
因此事实上在前面提到的那个SPS项目中,我采用的方法并不是GC,而是下面这一段代码:
//---------------------------------------------------------
// 处理ActiveX Object时采用的页面切换代码
//---------------------------------------------------------
function writeXLS() {
excel.Quit();
// 下面代码用于解决IE call Excel的一个BUG, MSDN中提供的方法:
// setTimeout(CollectGarbage, 1);
// 由于不能清除(或同步)网页的受信任状态, 所以将导致SaveAs()等方法在
// 下次调用时无效.
location.reload();
delete 运算符在手册上的说明
引用从对象中删除一个属性,或从数组中删除一个元素。
delete expression
expression 参数是一个有效的 JScript 表达式,通常是一个属性名或数组元素。
如果 expression 的结果是一个对象,且在 expression 中指定的属性存在,而该对象又不允许它被删除,则返回 false。
在所有其他情况下,返回 true。
最后之最后,关于GC的一个补充说明:在IE窗体被最小化时,IE将会主动调用一次CollectGarbage()函数。这使得IE窗口在最小化之后,内存占用会有明显改善
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具带你了解基于JavaScript 的操作系统详解-js教程-PHP中文网QQ群微信公众号带你了解基于JavaScript 的操作系统详解带你了解基于JavaScript 的操作系统详解:我想大多数人听说过 Node.js,但是你听说过 NodeOS 吗?没错,NodeOS,一个用 Node.js 写的操作系统。好吧,实话说,NodeOS 用 Linux 内核来处理各种底层任务,比如硬件通讯什么的,但是除此之外,使用的都是 Node.js。NodeOS 的开发始于两年前,创建者的目的很简单,他只是好奇,“是否有可能仅使用 Node.js 创建一个操作系统呢?”是否有可能仅使用 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 的方法如下:一台运行 Mac OSX 或 Linux 计算机,也许 Windows 也可以,但是我没试过。Docker。当你安装好 Docker 之后,运行一个 NodeOS 实例是很容易的。你只需要执行如下命令就可以了, Docker 会为你完成这魔法般的一切:sudo docker run -t -i nodeos/nodeos最容易、最快捷的体验 NodeOS 的方法是通过 Docker。当你运行了上述命令,Docker 会自动从仓库下载 NodeOS 的镜像,并将其安装到一个虚拟环境中。安装好之后,会打开一个连接到 NodeOS 的 SSH 会话。不用 docker 呢?有些情况下你也许不能使用 Docker 来体验,或者是你想体验一下最新版本的 NodeOS 。在写作本文时,NodeOS 的镜像已经是两个月前生成的了,而开发版本则是六天前更新的。所以,如果你希望使用最新版本,你应该从源代码开始。这也不算很难,但是要花费一些时间。你需要:一台运行 Linux 的计算机。你可以在 OS X 上编译它,但是跨平台编译需要花费很多时间,对于 Windows 也如此。Linux 编译构建相关的工具(make、g++、gcc、autoconf)。Qemu。时间,真的需要很多。如果万事俱备,你就可以从源代码开始编译了:下载项目源代码:bash git clone :NodeOS/NodeOS.git。使用下列命令编译: cd NodeOS 并 npm install。我逐字引用了其官方文档的话:“拿上爆米花去看场电影吧,不开玩笑,真的。”,是的,它需要很多时间,做些有意思的事情去吧。执行 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:1%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 就可以开发我们的应用了。比如,NodeOS 里没有默认实现的 man 命令,它用于显示其它命令的帮助信息。不用担心,实现它很简单。使用 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 仓库中找到。让我们回过头来创建我们的第一个 NodeOS 应用。像每个 Node.js 应用(或 NPM 包)一样,我们从创建一个 package.json 文件开始,内容如下:{
&name&: &bin-man&,
&version&: &0.0.1&,
&description&: &Format and display manual pages&,
&man&: &man.js&
&repository&: &/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这个部分叫做释伴(shebang)。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&;
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: 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 生态系统兴盛发展的形势下,万一哪天它很快地成为一个流行的操作系统也没什么好惊奇的。你怎么看?发表你的评论让我们知道。以上就是带你了解基于JavaScript 的操作系统详解的详细内容,更多请关注php中文网其它相关文章!523点赞收藏分享:&猜你喜欢12345678910
:独家原创,永久免费的PHP教程,PHP技术学习阵地!Copyright
All Rights Reserved | 皖B2-QQ群:关注微信公众号

我要回帖

更多关于 微信语音通话中断原因 的文章

 

随机推荐