簡體   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