Dynamically loading a script changes its behaviour

2019-07-29 07:43发布

I wanted paperjs to load after a button is pressed to turn on animations but it seems the paperscript doesn't work if paper is loaded after page load.

If you comment out the setTimeout and uncomment the direct $.getScript - paperjs will fire the alert('hi'). I don't get it.

<html>
    <head>
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script>
            $(document).ready(function () {
                var paperUrl = 'http://cdnjs.cloudflare.com/ajax/libs/paper.js/0.22/paper.js';
                $("#jq").text("jQuery is now loaded.")
                var lateLoad = function() {
                    $.getScript(paperUrl, function() {
                        $("#pp").text("Paperjs is now loaded.");
                    });
                };
                //setTimeout(lateLoad, 100);
                $.getScript(paperUrl, function() {
                    $("#pp").text("Paperjs is now loaded.");
                });
            });
        </script>
    </head>
    <body>
        <script type="text/paperscript" canvas="myCanvas">
            $('body').css({"background-color": "#999"});
            alert('hi!');
        </script>
        <p id="jq">jQuery NOT loaded yet.</p>
        <p id="pp">Paperjs NOT loaded yet.</p>
    </body>
</html>

I'm using Chrome 23.0.1271.97 m on Windows 7 x64. Anybody have an idea what's going on here?

3条回答
干净又极端
2楼-- · 2019-07-29 08:12

Move your paperscript code into an external file (i.e. pstest.js) and modify your lateLoad to:

var lateLoad = function() {
    $.getScript('http://cdnjs.cloudflare.com/ajax/libs/paper.js/0.22/paper.js',
    function() {
      $("#pp").text("Paperjs is now loaded.");
      $.getScript("pstest.js");
    } )
}
查看更多
Rolldiameter
3楼-- · 2019-07-29 08:15

I think I figured out a workaround as well - paper.PaperScript.load() or to elaborate:

<html>
    <head>
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script>
            $(document).ready(function () {
                $("#jq").text("jQuery is now loaded.")
                var paperUrl = 'http://cdnjs.cloudflare.com/ajax/libs/paper.js/0.22/paper.js';
                var lateLoad = function() {
                    $.getScript(paper_url, function() { 
                        $("#pp").text("Paperjs is now loaded.");
                        paper.PaperScript.load(); // <-- The fix!
                    });
                };
                setTimeout(lateLoad, 1000);
                //$.getScript(paperUrl, function() {
                //    $("#pp").text("Paperjs is now loaded.");
                //});
            });
        </script>
    </head>
    <body>
        <script type="text/paperscript" canvas="myCanvas">
            $('body').css({"background-color": "#999"});
            alert('hi!');
        </script>
        <p id="jq">jQuery NOT loaded yet.</p>
        <p id="pp">Paperjs NOT loaded yet.</p>
    </body>
</html>

That causes paperscript to scan for all the paperscripts. I found it at https://github.com/paperjs/paper.js/blob/master/src/core/PaperScript.js#L270 while googling for "paperscript" in the github repo. Though it still doesn't explain why paper doesn't do the load() on its own when dynamically loaded.

EDIT - I understand what went wrong. It's related to https://github.com/jquery/jquery/blob/master/src/core.js#L768 because paperjs doesn't check if the window loaded event had already fired i.e document.readyState === "complete". I submitted a pull request to paperjs https://github.com/paperjs/paper.js/pull/156

查看更多
狗以群分
4楼-- · 2019-07-29 08:25

I think it is easier to load it via require.js. All you need is a require.config object, defined in e.g. main.js:

requirejs.config({
    paths : {   
        'jquery' : "path/to/jquery"
        'paper' : "path/to/paper"
    },
    shim: {
        'jquery' : {
            exports: 'jQuery'
        },
        'paper' : {
            exports: 'paper'
        }
    }
});

You will need to load require.js with the above config via the data-main attribute:

<script data-main="scripts/main.js" src="scripts/require.js"></script>

Then you define a module (e.g. 'paperStuff') where your paper logic will be:

define(['jquery', 'paper'], function($, paper) {
   // do some cool stuff
});

When you want to load your paperStuff, you just do

var paperStuff = require('paperStuff');
...
查看更多
登录 后发表回答