【问题标题】:Alternative to using callback function in JavaScript?替代在 JavaScript 中使用回调函数?
【发布时间】:2020-09-17 11:44:00
【问题描述】:

我试图在第一个函数的滚动动画完成后调用第二个函数。我已经看到在类似情况下使用回调函数,但是它们似乎更麻烦且难以阅读。有没有更简单或更干净的方法来达到同样的效果?

$('#nav_experience').click(function scrollToExperience(){
    $('html, body').animate({
        scrollTop: $('#Experience').offset().top
    }, 500);
})

function navbarExperienceActive(){
    scrollToExperience(function(){
        $('#nav_profile').removeClass('active');
        $('#nav_education').removeClass('active');
        $('#nav_contact').removeClass('active');
        $('#nav_experience').addClass('active');
    });
}

另外我很欣赏第二个函数是相当重复的,可能有一种更优雅的方式来编写它,我对 JavaScript 比较陌生。

【问题讨论】:

  • 问题中的代码不起作用,原因有几个。 scrollToExperience 没有在navbarExperienceActive 中定义,如果它只是作为click 回调存在的那个,它永远不会调用navbarExperienceActive 传递它的回调。 (函数表达式不会将函数添加到它们出现的范围,只是函数声明。)

标签: javascript jquery callback jquery-animate


【解决方案1】:

我们过去使用回调的一种现代方法是使用 promises,当与 async 函数和 await 结合使用时特别有效。 (从概念上讲,“承诺”有很多名称——承诺、期货、延期......)

Promises 本身仍然使用回调,但通过为将来的回调提供传递 Promise 的标准化形式,它们显着改进了过去将回调作为参数传递的代码。

例如,您的scrollToExperience 可能如下所示:

function scrollToExperience(){
    return new Promise(resolve => {
        $('html, body').animate({
            scrollTop: $('#Experience').offset().top
        }, 500, resolve);
    });
}

navbarExperienceActive 可能会这样使用它:

function navbarExperienceActive(){
    scrollToExperience().then(function(){
        $('#nav_profile').removeClass('active');
        $('#nav_education').removeClass('active');
        $('#nav_contact').removeClass('active');
        $('#nav_experience').addClass('active');
    });
}

从表面上看,这并没有太大变化;您仍然必须通过回调。但是,如果navbarExperienceActive 必须将其与其他异步操作相结合,以其他方式将其链接起来等等,那么使用 Promise 会使代码库之间的操作更简单、更标准。

但如果navbarExperienceActiveasync 函数,它可以使用await

async function navbarExperienceActive(){
    await scrollToExperience();
    $('#nav_profile').removeClass('active');
    $('#nav_education').removeClass('active');
    $('#nav_contact').removeClass('active');
    $('#nav_experience').addClass('active');
}

它仍然使用promise,但代码是按照其简单的逻辑流程编写的,而不是担心它必须等待scrollToExperience完成。

async 函数总是返回一个承诺;当您在 async 函数中使用 await 时,如果您传递给它的值是一个承诺(关于“thenables”的手波详细信息),它会返回它的承诺,然后根据你awaiting(和/或遵循它的逻辑)的承诺会发生什么。


我应该注意到上面scrollToExperience返回的promise有点不寻常,因为它总是履行promise,它从不拒绝它。使用它的承诺的代码依赖于它从不拒绝它的承诺这一事实。

不过,一般来说,重要的是要确保处理承诺拒绝或将承诺链传递给其他可以处理的东西。这是async 函数让生活更简单的另一个地方:它们自动传播承诺拒绝,就像同步函数自动传播异常一样。

【讨论】:

  • (FWIW,我在新书的第 8 章中详细介绍了承诺,在第 9 章中详细介绍了 async/await。如果您愿意,请在我的个人资料中链接'感兴趣。)
  • 感谢对 Promise 的深入描述,这正是我希望的替代方法类型,我一定会看看你的书。我更改了我的 scrollToExperience() 函数以返回一个承诺并将 navbarExperienceActive() 更改为异步函数,但是在触发点击事件时似乎没有调用 navbarExperienceaActive()
  • @Biggles-2 - 你有什么设置可以调用它吗?在问题中,点击事件只调用scrollToExperience,而不是navbarExperienceaActive
  • 我以为我有,但没有奏效,我一定犯了一个愚蠢的错误或合成器错误。你会如何在点击事件中调用两者?
  • @Biggles-2 - 在您将其指定为click 处理程序的位置之外定义scrollToExperience。正如我在对该问题的评论中提到的那样,它在那里定义的方式不在范围内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
  • 2019-01-30
相关资源
最近更新 更多