JavaScript中的回调函数

3

我知道ajax调用是异步的,但有些情况需要同步执行。例如:

loadMyProfile();
editMyProfile();

这是两个JavaScript函数,我希望loadMyProfile()函数被完全执行后再调用editMyProfile()函数。但是由于它是异步的,所以这种情况并没有发生。我听说回调函数是处理这种情况最好的方法。那么能否有人解释一下回调函数,并提供与此示例相关的示例呢?
任何帮助都将不胜感激!
谢谢, Karthik

但这并没有发生,因为它是异步的。证明它。 - Ignacio Vazquez-Abrams
JavaScript 不是异步的。当你调用 loadMyProfile() 时,它会在 editMyProfile() 开始之前完成执行。 - robbrit
我们需要看到loadMyProfile的实现才能给您更好的建议。很有可能,它执行的是异步操作,比如提交XMLHttpRequest,这才是您真正想要的。您需要钩入任何异步操作的回调函数,以便实现您所寻求的执行顺序。但是,如果没有实际看到代码,我只是在做假设。 - Jason LeBrun
@Jason,我认为你是对的...请看下面我的回答 :P - Damien-Wright
4个回答

2
我知道JavaScript是异步的。JavaScript本身并不是异步的,它没有定义任何异步特性。你展示的这两个函数调用将按顺序执行,先是loadMyProfile,然后是editMyProfile。JavaScript确实有语言特性使异步编程更容易,但它本身没有定义任何异步操作。
然而,在Web浏览器中运行的JavaScript环境中有两个主要的异步特性,我假设你正在尝试使用它们。
第一个可能最相关的是,默认情况下,ajax调用是异步的。因此,例如,如果你的loadMyProfile函数正在进行ajax调用,那么该函数将在ajax调用完成之前返回。这是XMLHttpRequest对象的一个功能(也非常有用!)。
第二个是Web浏览器中window对象可用的setTimeoutsetInterval函数。 setTimeout会在超时后异步调用一个函数。 setInterval会按照时间间隔重复调用一个函数。 回调函数指的是当其他事件发生时被调用的函数。例如,XMLHttpRequest 对象接受将在完成时调用的函数等。而你使用的与setTimeoutsetInterval一起使用的函数,就是回调函数。事件处理程序也是一种回调函数,会在DOM中发生相关事件时被调用。
看看你的例子:
loadMyProfile();
editMyProfile();

假设 loadMyProfile 确实会进行异步的 ajax 调用,从服务器加载个人资料信息并在页面上显示,例如:
function loadMyProfile() {
    issueAjaxRequest("/some/url", "some data", function() {
        // This function is the completion callback for the ajax call.
        // It gets called *after* `loadMyProfile` has already returned.
        showProfileOnPage();
    });
}

“那段代码在语法上是正确的,只是使用了虚构的函数来避免淹没你的细节。”
“现在,如果我们想要在资料加载完成后调用 editMyProfile 函数,我们需要让 loadMyProfile 函数接受一个回调函数,在资料加载完成后调用它:”
function loadMyProfile(callback) {
    issueAjaxRequest("/some/url", "some data", function() {
        // This function is the completion callback for the ajax call.
        // It gets called *after* `loadMyProfile` has already returned.
        showProfileOnPage();

        // Call the callback if any
        if (typeof callback === "function") {
            callback();
        }
    });
}

然后我们就像这样使用它:
loadMyProfile(editMyProfile);

请注意,editMyProfile 后面没有 ()。在该语句中,我没有直接调用它,而是将一个引用传递到 loadMyProfile 中,当适当的时间到来时,loadMyProfile 会调用它。

谢谢,我知道ajax调用是异步的,忘记在我的帖子中包含它了,但真的感谢你澄清了我的回调疑问。我感谢每个人的答案。 - Karthik
“语言本身并没有定义任何异步特性”这句话已经不再准确了,因为现在有了 Web Workers(使用 Web Workers - MDC)。 - Raze
@Raze:Web Workers 不是 JavaScript 的一部分。它们(就像 XMLHttpRequestsetTimeout 等)是 JavaScript 代码运行的环境的一部分(在提供它们的实现中)。在这种情况下,是指 Web 浏览器。 - T.J. Crowder
@t-j-crowder,好的,你在谈论与执行环境分离的语言。我应该注意到你说的是_The Language..._。 - Raze

1

这绝对不是异步代码。你应该确保loadMyProfile正在执行你认为它应该执行的操作。Firebug是一个非常好的工具!


0

回调的一种方法是在操作后提供要调用的函数。例如:

function init() {
    callMeFirst('callBack'); //Ask callMeFirst() to execute function callBack() after the execution
}

function callMeFirst(callBackVar) {
    //perform the operation here
    if(callBackVar != null) {
            var functionToCall = eval(callBackVar);
            functionToCall();
    }
}

function callBack() {
    alert("Who called me");
}

0

没有看到更多的代码,我会猜测loadMyProfile正在执行某种ajax请求..

因此,当运行下一个函数(editMyProfile)时,代码本身是完整的,但ajax仍在等待其响应...

如果你想等待ajax请求完成,你需要向我们展示loadMyProfile函数的代码...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接