local-host 2014-08-19 21:04 采纳率: 100%
浏览 35

延迟时间问题

I have the following code I've designed to load and run script at runtime. You'll note that I save it to localStorage if it isn't already there. Now it runs fine if it's stored there already, but when it's just got the text from the file it throws ReferenceError: loginLaunch is not defined, though the text seems to have been loaded (hence the console.log lines that check the length). For your convenience I've included a line, localStorage.clear();, to make it alternate between the error message that's the problem and ReferenceError: loginLaunch is not defined, which given the code below is the desired result.

I don't understand why it should work one way and not the other. If it's a timing issue I don't see how the use of the promise, loginCode, lets it through unless possibly appendChild() is asynchronous, but I'm under the impression that it isn't (mainly because it has no callback, and I tried to find out, but could not) and even then why would code before the appendChild() have an impact?

Have I messed up one of the promises? I include the contents of the file login.js at the end. I searched SO for anything relevant but without any luck except for just one post that states that appendChild is synchronous.

Please help.

var loginCode = runCode("login_1001","./js/login.js");
loginCode.done(loginLaunch());

//FUNCTIONS START HERE

function getCode(local, source) {   //This creates the promise to get the code (not to run it)
    console.log("start of loadCode");
    dfd = $.Deferred();     //This is the one to return.

    script = localStorage.getItem(local);   //Try to load from local storage.
    // console.log("script after local attempt: "+script);
    if (script) {   //If found...
        console.log("found Local code");
        dfd.resolve(script);
                                   localStorage.clear();    //Added for debugging
    } else {    //load from file.
        ajax = $.ajax({
            url : source,
            cache : false,
            dataType : "text",  //load as text initially so that we can store it locally.
        });

        ajax.done(function(fromFile){
            localStorage.setItem(local, fromFile);  //store it locally.
            //console.log("script after ajax attempt: "+script);
            dfd.resolve(fromFile);
        });

        ajax.fail(function(){
            dfd.reject("Error retrieving code. You may be disconnected");
        });

    }

    return dfd.promise();
}

function runCode(local, source) {
    dfd = $.Deferred();     //This is the one to return.

    code = getCode(local, source);      //local promise

    code.done(function(retrievedCode){
        console.log(retrievedCode.length);
        var head = document.getElementsByTagName('head')[0];    //first head section
        var el = document.createElement("script");              //named the same as the local storage
        //script.type= 'text/javascript';   Redundant — it's the default
        // el.id = local;               //Probably redundant, but if we want to manipulate it later...
        el.text = retrievedCode;
        head.appendChild(el);       //This shouldn't run anything, just make global functions that will be called later.
        console.log(el.text.length);
        dfd.resolve();              //If we need to return the node to manipulate it later we'd make the variable above and 'return' it here
    });

    return dfd.promise();
}

Here's the contents of the login.js file.

function loginLaunch(){
    dfd = $.Deferred();     //This is the one to return.

    loadElement("login.1001", "#content", "login.html");

    //After the element has been loaded we have a disconnect — i.e. there's no promise waiting, so we have to wait for the user.

}

$("#content").delegate('#loginButton','click',function(){
    console.log("Login click");

    //php to pick up the entered details and pass them to common php that also uses the 
    checkCredentials = $.ajax({
        type : "POST",
        url : "./php/credentials.php",
        data : {
            queryString : queryString
        },
        datatype : "text",                  // 1 or 0
    });

    checkCredentials.done(credentialsChecked(success));





    // MOVE THIS STUFF
    readyPublicList();

    $.when(publicListCode,loggedIn).then(runDefaultPublicList());       //Assumes successful login so it loads the code for the list window in parallel.

    //Note that it's probable that my approach to the login window may change, because it needs to be available on the fly too.


    // $("#content").html("<p>test</p>");   //Successfully tested, well it was once.
});

function loginHide(){
    $("#loginHtml").hide;
}
  • 写回答

2条回答 默认 最新

  • 7*4 2014-08-19 22:31
    关注

    You need to change at least three things. First change this:

    loginCode.done(loginLaunch());
    

    to this:

    loginCode.done(function() {loginLaunch()});
    

    You need to be passing a function reference to the .done() handler so it can be called later. The way you had it, you were calling it immediately BEFORE loginCode() was done with its work, thus it was getting called too early.

    In addition, loginLaunch doesn't exist yet so you can't pass a reference directly to it. Instead, you can pass a reference to a wrapper function that then calls loginLaunch() only after it finally exists.

    And second, you need to declare your local variables with var so they aren't implicit globals and stomp on each other. For example, you have multiple functions who call each other trying to use the same global dfd. That is a recipe for disaster. Put var in front of it to make it a local variable so it's unique to that scope.

    And third, el.text doesn't look like the right property to me for your script. Perhaps you meant to use .textContent or since you have jQuery, you can do:

    $(el).text(retrievedCode);
    

    In a couple style-related issue, ALL local variables should be declared with var before them so they are not implicit globals. This will bite you hard by causing mysterious, hard to track down bugs, even more so with async code.

    And, you can generally use the promise returned by jQuery from ajax functions rather than creating your own.

    To incorporate those improvements:

    runCode("login_1001","./js/login.js").done(loginLaunch);
    
    function getCode(local, source) {   //This creates the promise to get the code (not to run it)
        var script = localStorage.getItem(local);   //Try to load from local storage.
        if (script) {   //If found...
            localStorage.clear();    //Added for debugging
            // return a resolved promise (since there's no async here)
            return $.Deferred().resolve(script);
    
        } else {    //load from file.
            // return the ajax promise
            return $.ajax({
                url : source,
                cache : false,
                dataType : "text",  //load as text initially so that we can store it locally.
            }).then(function(fromFile){
                localStorage.setItem(local, fromFile);  //store it locally.
                return fromFile;
            });
    
        }
    }
    
    function runCode(local, source) {
        return getCode(local, source).then(function(retrievedCode){
            console.log(retrievedCode.length);
            var head = document.getElementsByTagName('head')[0];    //first head section
            var el = document.createElement("script");              //named the same as the local storage
            $(el).text(retrievedCode);
            head.appendChild(el);       //This shouldn't run anything, just make global functions that will be called later.
            console.log(el.text.length);
        });
    }
    

    FYI, if you just want to insert a script file, you don't have to manually retrieve the script with ajax yourself. You can use the src property on a script tag and let the browser do the loading for you. You can see a couple ways to do that here and here.

    评论

报告相同问题?

悬赏问题

  • ¥15 使用C#,asp.net读取Excel文件并保存到Oracle数据库
  • ¥15 C# datagridview 单元格显示进度及值
  • ¥15 thinkphp6配合social login单点登录问题
  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配