[英]Implementation of a client-side 'require' function compatible with node.js
决定将我所有的 Javascript 库实现为与 node.js 兼容的模块后,我现在已经将一个简单的“要求”function 放在一起,以便在事物的客户端使用。 我确实意识到已经有很多非常好的实现,但大多数看起来相当笨拙,所以我只是选择 go 与“自己动手”的方法。
这是我的“require.js”文件:
/*
A client-side script loading class designed to be compatible with node.js
*/
function require(filename)
{
try
{
var
script = null,
ajax = new XMLHttpRequest(),
index = filename.toLowerCase().indexOf('.js');
if(index <= 0 || index != filename.length - 3)
filename += '.js';
ajax.onload = function()
{
script = this.responseText;
};
ajax.open('GET', filename, false);
ajax.send();
return _isolate_script_(script);
}
catch(error)
{
return null;
}
}
function _isolate_script_(_script_)
{
return (new Function
(
'var exports = {}, module = {exports : null}; '
+ _script_ +
'; return module.exports || exports;'
)).call();
}
示例模块('example.js'):
/*
Example of a multiple-class export file
*/
exports.metallic = function(value)
{
return (Math.sqrt(4 + value * value) + value) / 2;
}
exports.inverse_metallic = function(value)
{
return exports.metallic(-value);
}
模块使用者('main.js')的示例:
function main()
{
var
example = require('example');
if(example != null)
{
var
value = Math.floor(Math.random() * 100) + 1;
alert
(
'example.metallic(' + value + ') = ' + example.metallic(value)
+ '\n' +
'example.inverse_metallic(' + value + ') = ' + example.inverse_metallic(value)
);
}
else
alert('Error: cannot load "example"');
}
最后,调用我们的页面逻辑的基本 HTML 文件:
<!DOCTYPE html>
<html>
<head>
<script src = 'require.js'></script>
<script src = 'main.js'></script>
</head>
<body onload = "main()"></body>
</html>
所以我的具体问题只是我是否正确地实现了所有东西,而且框架和用例是否看起来足够干净?
看来您正在尝试重新实现Browserify :
浏览器没有定义require方法,但是Node.js有。 使用Browserify可以编写使用require的代码,就像在Node中使用它一样。
如果您想自己实现类似的功能,请查看Browserify源代码。
我将自己回答。
主要问题是,较旧的浏览器有时会因同步ajax请求而冻结。 简单地在自己的线程中启动整个“ main”功能似乎是一个很好的解决方案。 也就是说,如果在加载脚本时出现一些不可预见的问题,则页面本身可能没有响应,但是浏览器至少应不受影响。 换句话说,与此类似:
<!DOCTYPE html>
<html>
<head>
<script src = 'require.js'></script>
<script src = 'main.js'></script>
</head>
<body onload = "setInterval(main)"></body>
</html>
关于吞吐量,我现在已经用大量数据(〜100 MB)对其进行了测试,对于代码是通过脚本标签还是通过ajax调用加载,似乎对性能没有太大影响。 所有主要浏览器都在两种不同的操作系统上运行,结果几乎相同。 因此,除非我看到令人信服的证据,否则我将假设这是规则,而不是例外。
话虽这么说,我当然仍然对可能的任何评论或批评持开放态度。
如果您还想要模块缓存,请尝试以下操作:
let parent = "";
let cache = {};
/**
* Load a JavaScript text synchronously.
*
* @param url The url.
*/
function cludge(url) {
/* resolve and check */
if (parent !== "")
url = new URL(url, parent).href;
let map = cache[url];
if (map !== undefined)
return map;
map = {};
cache[url] = map;
/* load and execute */
let back = parent;
try {
parent = url;
let request = new XMLHttpRequest();
request.open('GET', url, false);
request.send();
let fun = new Function("exports", "require", request.responseText);
fun(map, cludge);
} finally {
parent = back;
}
return map;
}
但是名称解析不像 nodejs 那样复杂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.