blog icon indicating copy to clipboard operation
blog copied to clipboard

认识fibjs

Open ngot opened this issue 10 years ago • 25 comments

认识fibjs

fibjs开源至今差不多半年了,越来越多的人知道fibjs。响马在前些日子的南京源创会上做的fibjs分享,更是让fibjs推广进入了一个高潮,就连外国友人都开始密切关注fibjs的动态。下面,我们就来探讨一下fibjs的一些问题。

fibjs是什么?

  • fibjs不是前端开发框架,不同于Jquery,Angular等运行在浏览器的JS框架,fibjs运行在服务端。
  • fibjs不是Node.js的一个包,和NPM里面的fiber扩展包也没有关系。
  • fibjs是基于协程和V8,运用C++语言开发的JS运行平台,和Node.js一样,都是服务端JS环境。
  • fibjs由西祠胡同创始人,孢子社区创始人,响马历时两年多开发完成。

又一个轮子?

很多人会问,既然已经有了Node.js,为什么还要再造fibjs这个大轮子?难道只是为了造轮子而造轮子吗?

其实,实际原因不是这样。要说fibjs的诞生,不得不说说孢子社区的开发史。

在早期阶段,孢子社区的后端是运用响马开发的VBS运行环境开发的,后来考虑到前后端代码复用,方便招聘开发人员等原因,决定后端转向JS平台。当时,不选择Node.js的原因是认为异步开发模式不是一个适合大规模部署的方式,会给开发和维护带来很大问题。

既然,Node.js不是一个我们认为的好的选择,那就自己造轮子吧。最初的技术选型(详情参见点我)考虑了,v8,JavaScriptCore 和 SpiderMonkey三个JS引擎。

最终选择了 v8 作为基础核心。原因是:

  • 支持多线程重入,协程的堆栈本质是线程,所以要支持协程必须要支持多堆栈重入;
  • 不支持多线程并发,虽然 isolate 支持多堆栈现场,但是 isolate 内部却为无锁环境,因此不能接受多线程同时运行,必须在一个线程退出后,另一线程才可进入;

在选择了V8后(不是Node.js用了V8,咱就要用V8,选择什么都是有原因),再开发协程环境并和V8结合工作,再补上其他基础模块,就是fibjs了。

总的来说,造轮子最初目的是为了自身满足需求。

fibjs名字由来?

fib是fiber的简称,fiber就是纤程的意思。JS就是Javascript语言。连起来就是用fiber技术构建起来的JS平台,简单而又直白。

fibjs logo含义

  • fibjs
  • 去除回调,去除层层的 }}}}}}}}}}}}}}}}}}}}}}}}};
  • Javscript
  • 跨平台,支持Mac OSX, Linux, FreeBSD, Windows

fibjs特点

  • 同步编写异步代码

    node.js的回调写法,肯定很多人见识过,层层回调简直就是项目的灾难。虽然,可以通过Asyc,Promise,Generator等手段,在形式上简化回调写法,但是本质上没有变,始终无法靠直觉写出简洁优美的代码。还是少废话,直接看代码。

    我们来看一个文件_异步_读取的例子:

    Node.js CallBack版本

        var fs = require("fs");
        fs.readFile('file', function(err, data) {
            if (err) throw err;
            console.log(data.toString());
        });
    
    

    采用CO库改进的Node.js版本

        var fs = require("fs");
        var co = require("./co");
    
        function read(file) {
            return function(fn) {
                fs.readFile(file, function(err, data) {
                    if (err) return fn(err);
                    fn(null, data);
                });
            }
        }
    
        co(function *() {
            var a = yield read('file');
            console.log(a.toString());
        })();
    
    

    fibjs版本

        var fs = require("fs");
        try {
            var file = fs.readFile('file');
            console.log(file);
        } catch (e) {
            console.log(e.number);
        }
    
    

    从上面的代码对比,可以看出,fibjs的同步写法非常简洁,而且可以利用try catch来捕获异常,而node.js必须依赖回调来处理异步,就算采用了Generator,在代码简洁和错误处理上Node.js还是没有fibjs来的简单明了。

  • 高性能,整体比Node.js快接近8倍

    相比较Node.js,fibjs具有明显的性能优势,测试案例:

  • 前后统一语言 这个优点还是非常诱人的,前端和后端不需要跨语言开发,许多代码库可以共享,更有利于开发人员往全栈方向发展。

fibjs发展史

  • 2012年2月,项目启动
  • 2012年9月,开始在孢子社区生产环境试运行
  • 2013年初,向外公开fibjs信息
  • 2014年5月,项目推送Github,彻底开源
  • 2014年10月,南京源创会,首次开讲,引起业界轰动
  • 还在继续...

应用案例

如何安装fibjs

  • 如果你是Mac OSX用户,现在可以直接

        brew install fibjs
    

    感谢@艾斯昆帮忙提交到Homebrew

  • 如果你是有NPM环境的Linux或者Mac用户,可以

        npm install fibjs -g
    

    感谢笔者(也就是写这篇文字的家伙,并且他还偷懒不支持windows)的贡献

  • 如果以上两点条件都不具备或者安装不成功,还可以直接点击下面链接下载笔者编译好的可执行程序来体验。

    注意OSX和Linux用户,直接下载的文件不具有执行权限,执行:

    ```
        chmod 777 fibjs
    ```
    就能够正常运行了。
    
  • 如果,以上三步都失败了(够悲催的),那就到fibjs主页下载代码,手动编译。

文档翻译计划

因为fibjs在外国友人中得名气越来越大,英文文档的需求日益迫切,所以响马开展了fibjs文档的翻译工作,文档项目地址:https://github.com/xicilion/fibjs_docs,欢迎认领翻译。

参考资料

ngot avatar Nov 02 '14 06:11 ngot

strong

Hi-Rube avatar Nov 02 '14 07:11 Hi-Rube

Looking forward to it!

vlux avatar Nov 02 '14 07:11 vlux

awsome!!

friskfly avatar Nov 02 '14 09:11 friskfly

太棒了 希望像fibjs seajs 这些国人开发的好东西更多的走向国际,让老外也来看我们的中文文档啊哈哈

yeso avatar Nov 02 '14 09:11 yeso

太厉害~

riskers avatar Nov 02 '14 09:11 riskers

错别字:在代码简洁和错误处理上Node.js还是没有ibjs来的简单明了。

JokerQyou avatar Nov 02 '14 11:11 JokerQyou

@JokerQyou 谢谢指正,马上修改

ngot avatar Nov 02 '14 11:11 ngot

awsome

cloudmonkeypeng avatar Nov 03 '14 14:11 cloudmonkeypeng

虽然不写js,但可以肯定fibjs才是走上了正道。

skoowoo avatar Nov 03 '14 14:11 skoowoo

和 Python 有竞争关系吧,不过这个方向很棒。之前想过需要这种东西的,只是技术过多不好实施

hanzhou avatar Nov 04 '14 03:11 hanzhou

个人愚见,用读文件来展示node和fibjs的差异不太适合,没用过node的readFileSync 吗。为什么不用纤程来做例子?如果为了同步而自己实现一套,想不出为什么要选js语言,有哪位写js的完全不用回调的? 另外,有点担忧生态圈,npm上大部分工具,例如数据库连接,都是异步的,用fiber就相当于得自己维护一套同步的第三方工具,成本略大。 node只是提供了异步的io给开发者做选择,如果要用同步,不理解为什么要选用js呢?我想到的只有一个吸引力的地方,那就是v8的高性能。 另外,我相信,支持fibjs的,大部分是搞后台出身的

jetzhliu avatar Nov 04 '14 17:11 jetzhliu

@jetzhliu 第一个问题,我说了是异步读取,仔细读文章。第二个问题,这就是纤程的例子。第三个问题,大多数人都用回调,是因为没得选择,有了选择谁还用回调。第四个问题,fibjs也是异步的,只是写法上同步,维护数据库驱动真的难么?而且,npm的库,那质量真的能用吗? 生态不慢慢推动发展,难道是等来的吗?第五个问题,为什么用js,请再读文章,不懂你是怎么读出来的选择js,就一定是因为V8高性能。 拜托,好好读完文章大哥。

ngot avatar Nov 04 '14 23:11 ngot

没人为fpm提点意见么,,, T T

Hi-Rube avatar Nov 09 '14 03:11 Hi-Rube

学习成本高吗

mingyun avatar Nov 09 '14 04:11 mingyun

@mingyun 会写代码就能用,五分钟上手

ngot avatar Nov 09 '14 08:11 ngot

有非阻塞式IO的例子吗?事件-回调这一对是比较反人类,但是现在还没见过不反人类又高效的非阻塞实现呢。

notxx avatar Nov 10 '14 05:11 notxx

@notxx http://baoz.cn/fibjs

Hi-Rube avatar Nov 10 '14 07:11 Hi-Rube

看了一下孢子社区,对于用fib包装上下文然后把阻塞的fib置入等待,等阻塞完成了再切回来这个想法表示容易理解,因为和自己开一堆线程再进行调度是差不多的思路;对于开了一堆fib结果效率还能比nodejs高表示钦佩,因为这个我做不到。 更深入的对fib的调度效率怎么样,异步IO的细节,我还是去孢子社区挖答案吧

notxx avatar Nov 10 '14 08:11 notxx

支持@ngot 的看法

zhaomingliang avatar May 23 '15 05:05 zhaomingliang

没能营造更好生态的fibjs,为何以一种高高在上鄙视node的态度存在?看了楼主对@jetzhliu 的回复,感觉楼主发文、回应总带有强烈主观情绪,排斥异见的态度让人感觉并不成熟可靠。除了你眼中的“懂fibjs”的用户,更多的是在选择“更友好的开发生态”的用户。建议楼主深思,不要觉得批判你们的人是在怀疑你们的技术。

tommyfok avatar Nov 10 '15 15:11 tommyfok

没想到一年前发的评论还有人 @tommyfok 评论,不过我那时候对js真的是不了解,作者对我的回复也大部分没错。。。

不过,我觉得异步就应该有异步的写法,像co的yield或者ES7的async和await就很好,在写法上就给我们提个醒(这里要开始异步调用啦),而fibjs在写法上模糊了同步和异步的界限,对于刚接触异步的同学来说反而不好(个人愚见)。当然,这可能是理念上的不同的,不值得争辩。

另外,如果是多个异步操作并发执行的话,我不太了解fibjs是怎么的写法,但感觉应该要使用一些自身的API,而co只需要yield一个数组或者对象就可以,直观上要方便而且很容易理解。

还有,现在大部分npm上的主流框架和数据库驱动都支持回调和Promise的方式,也证明了他们对于co这种处理方式的认同。有时候习惯是一股很大的力量,npm上有很多糟粕,但完全抛弃npm的仓库转投fibjs也是个很艰难的决定。

最后,我觉得fibjs能做到效率上比node高是很值得称赞的,也给国人脸上增色。而且看到别人的东西做不好就自己挽起袖子开干也是程序员的优良品质~~

jetzhliu avatar Nov 10 '15 16:11 jetzhliu

@jetzhliu 关于哪个好这里就不做讨论了,就像当年争论哪个是全宇宙最好的语言(php获胜)一样意义不大,只是希望国人的好东西要有更理性和包容的推广方式。:smile:

tommyfok avatar Nov 11 '15 02:11 tommyfok

这不是轮子,是火箭🚀

luoshaohua avatar Jun 01 '18 10:06 luoshaohua

fibjs有一个问题:没法方便的写两个并发异步。 比如,在用await时的这句代码,就不好翻译成fibjs: a = await Promise.all([promise1, promise2])

luoshaohua avatar Jun 04 '18 07:06 luoshaohua

@luoshaohua

  1. fibjs 完全支持 JS 的特性,所以这样的写法在 fibjs 中依然可以使用的:
a = await Promise.all([promise1, promise2])
  1. 还可以这么玩
const util = require('util');

async function asyncFn() {
    return await Promise.all([promise1, promise2]);
}
const syncFn = util.sync(asyncFn);// convert to sync function
syncFn();

以上两种写法都不是推荐的写法,因为太丑了,而且性能也不好。

  1. 我们推荐的写法是如下这样:
const co = require('coroutine');
co.parallel([fn1, fn2, fn3, ...]);

上面的 fn 函数,就是普通的 Javascript 函数,不需要任何的特殊处理(不需要 Callback, Promise, Aysnc等)。

parallel 能够并发的执行 fn1, fn2, fn3 等一系列函数。效果类似于 Promise.all ,但是比Promise.all更简洁,性能更好,消耗的 CPU 与 内存更好。

更多并发相关操作参看文档: http://fibjs.org/docs/manual/module/ifs/coroutine.md.html#parallel

ngot avatar Jun 04 '18 08:06 ngot