同步 ajax 调用 - 在调用前显示 div

synchronous ajax call - show div before call

我需要在同步 ajax 调用之前显示覆盖我整个屏幕的 div。

但似乎我尝试做的任何事情都不会导致 DOM 被修改为在 ajax 调用之前显示此 div。屏幕变为 "frozen",仅在执行 ajax 调用后才显示 div。

我已经尝试了 "thousands" 的方法,但似乎只有在修改 DOM 之后才 ajax 运行(显示 div) .

HTML

[...]
<body>
    <div id="loadingDiv" style="display: none; width: 100%; height: 100%; background-color: #004000; position: absolute; z-index:10000;"></div>
[...]

javascript

[...]
$("#loadingDiv").css("display", "block");
var ajaxOp;
$.ajax({
    type: someType,
    url: someUrl,
    data: someData,
    dataType: someDataType,
    async: false,
    success: function (someArg) {
        ajaxOp = someArg;
    },
    error: function (someArg0, someArg1, someArg2) {
        // do something
    }
});
return ajaxOp;
[...]

注意 I: 我正在使用 JQuery.
注意二:"ajaxOp"不能"undefined".


更新: 希望它有助于理解,应@Felipe Dutra Ferreira 的要求,我在下面的更新中对这个问题做了更多解释......

真实案例:我有一个包含多个遗留代码的应用程序,这些代码使用一个函数 libray js,该函数反过来进行 ajax 调用(我们称之为 "certainfunction")。我们正在尝试更新此应用程序,以便它在 ajax 调用期间显示 "loading screen"(而不仅仅是在这些调用期间显示 "lock" 和 UI)。因此,处理此问题的最简单方法是在 "certainfunction" 调用之后和 运行 调用 ajax 之前显示 "loading screen"。另请注意,"certainfunction" returns 来自 ajax 调用的输出和此输出将是 "undefined" 一旦此调用未同步执行,即代码只能在之后继续此 ajax 调用有一个输出。

我已经为你写了以下内容。

请查看我的 GITHUB

中的以下示例

MyGithubLink


因为我有一个完整的示例,我已尽力帮助您。 在这里您将看到 Jquery 回调方法和承诺框架的使用,这似乎是您遇到的问题。请回复我,让我知道这是否是最终解决方案,因为我决心帮助您。

点击JSBin查看我的示例=> https://jsbin.com/xeloful/edit?html,output

<body onload="myFunction()" style="margin:0;"></body>

我想提请您注意... 如果您仍然需要帮助,请与我们联系...或者如果这没有帮助...

或者您可以 运行 Whosebug 上的代码片段。下面我使用 $(myFunction) 而不是 onload="myFunction()",这对于 jQuery 用户来说更为传统。点击下面的"Run Snippet"查看结果。

function showPage() {
    document.getElementById("loader").style.display = "none";
    document.getElementById("myDiv").style.display = "block";
};

function myFunction() {
    //Showing a Div prior to call as promised...
    $("#redSquare").fadeIn(3000).fadeOut(3000, function () {

        //Making the following API Call that will receive a random email from a random user...
        $.ajax({
            url: 'https://randomuser.me/api/',
            dataType: 'json',
            success: showPage
        }).done(function (res, req) {
            //Spitting out information about the HTTP call made...
            console.log(res);
            console.log(req);
            //Storing the email in the following variable...
            var RandomEmail = res.results[0].email;
            //Displaying the email in the console...
            console.log(RandomEmail);
            //Injecting the following email to the DOM
            document.getElementById("randomEmail").innerHTML = RandomEmail;
        });
    });
}

//When the body loads, render this function as seen in the body HTML tag with the onload... This is the jQuery way to do it...
$(myFunction);
#redSquare {
    display: none;
    width: 100vw;
    height: 100vh;
    background-color: crimson;
}

/* Center the loader */
#loader {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 1;
    width: 150px;
    height: 150px;
    margin: -75px 0 0 -75px;
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid #3498db;
    width: 120px;
    height: 120px;
    -webkit-animation: spin 2s linear infinite;
    animation: spin 2s linear infinite;
}


@-webkit-keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
    }

    100% {
        -webkit-transform: rotate(360deg);
    }
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

/* Add animation to "page content" */
.animate-bottom {
    position: relative;
    -webkit-animation-name: animatebottom;
    -webkit-animation-duration: 1s;
    animation-name: animatebottom;
    animation-duration: 1s
}

@-webkit-keyframes animatebottom {
    from {
        bottom: -100px;
        opacity: 0
    }

    to {
        bottom: 0px;
        opacity: 1
    }
}

@keyframes animatebottom {
    from {
        bottom: -100px;
        opacity: 0
    }

    to {
        bottom: 0;
        opacity: 1
    }
}

#myDiv {
    display: none;
    text-align: center;
}

#randomEmail {
    color: white;
    background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="redSquare">
    <!--Making this Appear for 3 Seconds prior to Ajax...-->
</div>

<div id="loader"></div>

<div style="display:none;" id="myDiv" class="animate-bottom">
    <h2>Tada!</h2>
    <p>Some text in my newly loaded page..</p>
    <h1>
        RandomEmail: <span id="randomEmail"></span>
    </h1>
</div>

一个解决方法是使用下面的函数,当我们进行同步调用("ajax")时,允许在系统上显示一个"loading screen"。它可以很容易地适应遗留代码。

意识到 "ajax" 阻止了对 "DOM" 的修改,即使它是在本次调用之前执行的。只有在涉及之前的一些同步 ajax 调用的进程的第一次使用时,这种方法才有效。基本上,它会在执行所需的 function/method("appFunc")之前创建一个时间 window(50 毫秒)来更新 DOM。只有在需要在执行后立即使用同步 ajax 调用输出的情况下,使用此函数才有意义。

使用示例:<button type="button" onclick="opSyncLoading(login, [this.form])">

  • 在这个例子中我们利用用户操作的"eventuality"创建一个时间window到线程并显示"loading screen"。请注意,"login" 函数不会 return 任何类型的输出。请注意,在 "login" 函数之后发生的所有事情都将以 "SYNC" 方式完成。
  • 这个限制是因为 JS/DOM 只有一个 "thread" 来处理所有事情,也就是说,没有办法用 "sleep" 等待,例如,因为不存在任何类型的有效并行性。一种解决方案可能是使用 "web worker",但这超出了所提出问题的范围。
  • 必须避免使用同步 "ajax" 调用,因为它会对 JS 的操作和 HTML 响应能力造成副作用,而且会被视为不良做法。它的使用应仅限于遗留代码或绝对必要的情况。

提示: 请注意,如果 "loading screen" 上有动画 gif,它将 "locked" 直到 "ajax" 调用完成,但是在某些现代浏览器中不会发生此问题。在极端情况下,如果图像加载到 iframe () 中,图像可能会保持 "animated"。

function opSyncLoading(appFunc, appFuncArgs) {
    if (typeof appFuncArgs === "undefined" || appFuncArgs === "") {
        appFuncArgs = [];
    }
    $("#loadingDiv").fadeIn(500, setTimeout(function () {

        // NOTE: Passing unknown arguments in quantity and nature to a callback function. By Questor
        // [Ref.:  ]
        appFunc.apply(this, appFuncArgs);

    }, 50));
}

谢谢! =D