繁体   English   中英

实现与 node.js 兼容的客户端“要求”function

[英]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源代码。

参见: https : //github.com/substack/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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM