先要明白的是,javascript和python都是解释型语言,它们的运行是需要具体的runtime的。
在本文叙述中,假定:
例如,python调用js,python就是主语言,js是副语言
适用于:
(因为与我的项目需求不太符合,所以了解的不太多)
首先,该方法的前提是两种语言都要有安装好的runtime,且能通过命令行调用runtime运行文件或一串字符脚本。例如,装好cpython后我们可以通过 python a.py 来运行python程序,装好Node.js之后我们可以通过 node a.js 或者 node -e "some script" 等来运行JS程序。
当然,最简单的情况下,如果我们只需要调用一次副语言,也没有啥交互(或者最多只有一次交互),那直接找个方法调用CLI就OK了。把给副语言的输入用stdin或者命令行参数传递,读取命令的输出当作副语言的输出。
例如,python可以用 subprocess.Popen , subprocess.call , subprocess.check_output 或者 os.system 之类的,Node.js可以用 child_process 里的方法, exec 或者 fork 之类的。 需要注意的是,如果需要引用其他包,Node.js需要注意在 node_modules 所在的目录下运行指令,python需要注意设置好PYTHONPATH环境变量。
# Need to set the working directory to the directory where `node_modules` resides if necessary
>>> import subprocess
>>> a, b = 1, 2
>>> print(subprocess.check_output(["node", "-e", f"console.log({a}+{b})"]))
b'3\n'
>>> print(subprocess.check_output(["node", "-e", f"console.log({a}+{b})"]).decode('utf-8'))
3// Need to set PYTHONPATH in advance if necessary
const a = 1;
const b = 2;
const { execSync } = require("child_process");
console.log(execSync(`python -c "print(${a}+${b})"`));
//<Buffer 33 0a>
console.log(execSync(`python -c "print(${a}+${b})"`).toString());
//3
//如果有复杂的交互,要传递复杂的对象,有的倒还可以序列化,有的根本不能序列化,咋办?
这基本要利用 进程间通信(IPC) ,通常情况下是用 管道(Pipe) 。在 stdin , stdout 和 stderr 三者之中至少挑一个建立管道。
假设我用 stdin 从python向js传数据,用 stderr 接收数据,模式大约会是这样的:
(以下伪代码仅为示意,没有严格测试过,实际使用建议直接用库)
如果是通过这种原理javascript调用python,方法也差不多,javascript方是Node.js的话,用的是 child_process 里的指令。
是一个非常有趣的 非主流前端领域,这个领域要探索的是如何用工程手段解决前端开发和部署优化的综合问题,入行到现在一直在学习和实践中。
在我的印象中,facebook是这个领域的鼻祖,有兴趣、有梯子的同学可以去看看facebook的页面源代码,体会一下什么叫工程化。
接下来,我想从原理展开讲述,多图,较长,希望能有耐心看完。
让我们返璞归真,从原始的前端开发讲起。上图是一个"可爱"的index.html页面和它的样式文件a.css,用文本编辑器写代码,无需编译,本地预览,确认OK,丢到服务器,等待用户访问。前端就是这么简单,好好玩啊,门槛好低啊,分分钟学会有木有!
然后我们访问页面,看到效果,再查看一下网络请求,200!不错,太™完美了!那么,研发完成。。。。了么?
等等,这还没完呢!对于大公司来说,那些变态的访问量和性能指标,将会让前端一点也不"好玩"。
看看那个a.css的请求吧,如果每次用户访问页面都要加载,是不是很影响性能,很浪费带宽啊,我们希望最好这样:
利用304,让浏览器使用本地缓存。但,这样也就够了吗?不成!304叫协商缓存,这玩意还是要和服务器通信一次,我们的优化级别是变态级,所以必须彻底灭掉这个请求,变成这样:
强制浏览器使用本地缓存(cache-control/expires),不要和服务器通信。好了,请求方面的优化已经达到变态级别,那问题来了:你都不让浏览器发资源请求了,这缓存咋更新?
很好,相信有人想到了办法:通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。好像这样:
下次上线,把链接地址改成新的版本,就更新资源了不是。OK,问题解决了么?!当然没有!大公司的变态又来了,思考这种情况:
页面引用了3个css,而某次上线只改了其中的a.css,如果所有链接都更新版本,就会导致b.css,c.css的缓存也失效,那岂不是又有浪费了?!
重新开启变态模式,我们不难发现,要解决这种问题,必须让url的修改与文件内容关联,也就是说,只有文件内容变化,才会导致相应url的变更,从而实现文件级别的精确缓存控制。
什么东西与文件内容相关呢?我们会很自然的联想到利用 数据摘要要算法 对文件求摘要信息,摘要信息与文件内容一一对应,就有了一种可以精确到单个文件粒度的缓存控制依据了。好了,我们把url改成带摘要信息的:
这回再有文件修改,就只更新那个文件对应的url了,想到这里貌似很完美了。你觉得这就够了么?大公司告诉你:图样图森破!
唉~~~~,让我喘口气
现代互联网企业,为了进一步提升网站性能,会把静态资源和动态网页分集群部署,静态资源会被部署到CDN节点上,网页中引用的资源也会变成对应的部署路径:
好了,当我要更新静态资源的时候,同时也会更新html中的引用吧,就好像这样:
这次发布,同时改了页面结构和样式,也更新了静态资源对应的url地址,现在要发布代码上线,亲爱的前端研发同学,你来告诉我,咱们是先上线页面,还是先上线静态资源?
但是,大公司超变态,没有这样的"绝对低峰期",只有"相对低峰期"。So,为了稳定的服务,还得继续追求极致啊!
这个奇葩问题,起源于资源的 覆盖式发布,用 待发布资源 覆盖 已发布资源,就有这种问题。解决它也好办,就是实现 非覆盖式发布。
看上图,用文件的摘要信息来对资源文件进行重命名,把摘要信息放到资源文件发布路径中,这样,内容有修改的资源就变成了一个新的文件发布到线上,不会覆盖已有的资源文件。上线过程中,先全量部署静态资源,再灰度部署页面,整个问题就比较完美的解决了。
所以,大公司的静态资源优化方案,基本上要实现这么几个东西:
全套做下来,就是相对比较完整的静态资源缓存控制方案了,而且,还要注意的是,静态资源的缓存控制要求在 前端所有静态资源加载的位置都要做这样的处理 。是的,所有!什么js、css自不必说,还要包括js、css文件中引用的资源路径,由于涉及到摘要信息,引用资源的摘要信息也会引起引用文件本身的内容改变,从而形成级联的摘要变化,大概示意图就是:
好了,目前我们快速的学习了一下前端工程中关于静态资源缓存要面临的优化和部署问题,新的问题又来了:这™让工程师怎么写码啊!!!
要解释优化与工程的结合处理思路,又会扯出一堆有关模块化开发、资源加载、请求合并、前端框架等等的工程问题,以上只是开了个头,解决方案才是精髓,但要说的太多太多,有空再慢慢展开吧。
总之,前端性能优化绝逼是一个工程问题!
以上不是我YY的,可以观察 百度 或者 facebook 的页面以及静态资源源代码,查看它们的资源引用路径处理,以及网络请中静态资源的缓存控制部分。再次赞叹facebook的前端工程建设水平,跪舔了。
建议前端工程师多多关注前端工程领域,也许有人会觉得自己的产品很小,不用这么变态,但很有可能说不定某天你就需要做出这样的改变了。而且,如果我们能把事情做得更极致,为什么不去做呢?
另外,也不要觉得这些是运维或者后端工程师要解决的问题。如果由其他角色来解决,大家总是把自己不关心的问题丢给别人,那么前端工程师的开发过程将受到极大的限制,这种情况甚至在某些大公司都不少见!
yHTML 是个快速 HTML 解析器,使用线程来实现一个类似纯 C99库,无任何外部依赖。
MyHTML 当前版本是 1.0.1,扩展了一个 MyCSS 开源库。MyCSS 是个快速的 CSS 解析器,GitHub 地址:
MyHTML 主要特性:
异步解析,构建树和指数
和 HTML5 规范完全一致
两个 API – 高和低水平
操作元素:添加,修改,删除和其他
操作元素属性:添加,修改,删除和其他
支持 39 种字符编码 encoding.spec.whatwg.org
支持字符编码检测
支持单模解析
支持无 POSIX 线程构建
支持片段解析
支持 parsing by chunks
无外部依赖
C99 支持
通过了所有 html5lib-tests
MyCSS— Fast C/C++ CSS Parser (Cascading Style Sheets Parser)
X_USER_DEFINED, UTF_8, UTF_16LE, UTF_16BE, BIG5, EUC_KR, GB18030, IBM866, ISO_8859_10, ISO_8859_13, ISO_8859_14, ISO_8859_15, ISO_8859_16, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, ISO_8859_6, ISO_8859_7, ISO_8859_8, KOI8_R, KOI8_U, MACINTOSH, WINDOWS_1250, WINDOWS_1251, WINDOWS_1252, WINDOWS_1253, WINDOWS_1254, WINDOWS_1255, WINDOWS_1256, WINDOWS_1257, WINDOWS_1258, WINDOWS_874, X_MAC_CYRILLIC, ISO_2022_JP, GBK, SHIFT_JIS, EUC_JP, ISO_8859_8_IUTF-8, UTF-16LE, UTF16BE 和 russian windows-1251, koi8-r, iso-8859-5, x-mac-cyrillic, ibm866
Make
make
MyHTML_OPTIMIZATION_LEVEL=-O2set compiler optimization level. Default: -O2
MyHTML_BUILD_WITHOUT_THREADS=YESbuild without POSIX Threads. Default: NO
示例
make MyHTML_BUILD_WITHOUT_THREADS=NO
cp lib/* /usr/local/lib cp -r include/* /usr/local/include
CMake
在 myhtml/project 目录:
cmake .make sudo make install
MyHTML_OPTIMIZATION_LEVEL=-O2set compiler optimization level. Default: -O2
CMAKE_INSTALL_LIBDIR=libset path to install created library. Default: lib
MyHTML_BUILD_SHARED=ONbuild shared library. Default: ON
MyHTML_BUILD_STATIC=ONbuild static library. Default: ON
MyHTML_INSTALL_HEADER=OFFinstall header files. Default OFF
MyHTML_BUILD_WITHOUT_THREADS=YESbuild without POSIX Threads. Default: NO
MyHTML_EXTERN_MALLOC=my_malloc_funcset extern malloc function. Default: UNDEFINED
MyHTML_EXTERN_REALLOC=my_realloc_funcset extern realloc function. Default: UNDEFINED
MyHTML_EXTERN_CALLOC=my_calloc_funcset extern calloc function. Default: UNDEFINED
MyHTML_EXTERN_FREE=my_free_funcset extern free function. Default: UNDEFINED
示例
cmake . -DCMAKE_INSTALL_LIBDIR=lib64 -DMyHTML_INSTALL_HEADER=ON
程序构建示例
构建共享库
gcc -Wall -Werror -O2 -lmyhtml your_program.c -o your_program
构建静态库
gcc -Wall -Werror -O2 your_program.c /path/to/libmyhtml_static.a -o your_program
简单示例
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <myhtml/api.h>int main(int argc, const char * argv[]) { char html = "<div><span>HTML</span></div>"; // basic init myhtml_t* myhtml = myhtml_create; myhtml_init(myhtml, MyHTML_OPTIONS_DEFAULT, 1, 0); // first tree init myhtml_tree_t* tree = myhtml_tree_create; myhtml_tree_init(tree, myhtml); // parse html myhtml_parse(tree, MyHTML_ENCODING_UTF_8, html, strlen(html)); // release resources myhtml_tree_destroy(tree); myhtml_destroy(myhtml); return 0; }MyHTML 遵循 LGPL 开源授权协议.
微信订阅号:开源派 (opensourcepie)
↓点击阅读原文,查看相关链接
*请认真填写需求信息,我们会在24小时内与您取得联系。