【问题标题】:How to correctly use Promise.then() in JavaScript?如何在 JavaScript 中正确使用 Promise.then()?
【发布时间】:2019-04-01 01:59:46
【问题描述】:

我正在尝试使用 Promises 一个接一个地运行一些函数,但不知何故,第二个函数要么在第一个函数之前执行,要么根本不执行。 情况是这样的:

我有以下功能:

  • 从部分文件夹加载可重用的 html 代码:
    function insertingPartials() {
        return new Promise( function(resolve,reject) {
            $('#navbar-placeholder').load('/Assets/Partials/navbar.html');
            $('#jumbotron-placeholder').load('/Assets/Partials/jumbotron.html');
            $('#footer-placeholder').load('/Assets/Partials/footer.html');

            resolve();
            reject('Error');
        });
  • 进行语言调整的工具
function languageSpecifics() {
    return new Promise( function(resolve,reject) {
        //showing correct text per html language
        $('span[lang=' + $('html')[0].lang + ']').show();
        $('div[lang=' + $('html')[0].lang + ']').show();
        //disabling the current language from the language selection menu
        $('a[lang=' + $('html')[0].lang + ']').addClass('disabled');
        //links dynamically point to the correct sub-pages
        $('.blog-link').attr('href', '/' + $('html')[0].lang + '/Blog/');
        $('.prod-link').attr('href', '/' + $('html')[0].lang + '/' + $('.prod-link span[lang=' + $('html')[0].lang + ']').text() + '/');
        $('#en').attr('href', window.location.href.replace($('html')[0].lang, 'en'));
        $('#es').attr('href', window.location.href.replace($('html')[0].lang, 'es'));
        $('#ro').attr('href', window.location.href.replace($('html')[0].lang, 'ro'));

        resolve();
        reject('Error in ' + arguments.callee.name);
    });
}
  • 将内容滑入视图:
function loadContent() {
    return new Promise( function(resolve,reject) {
        //fading content in
        $('nav').animate({top: '0'});
        $('footer').animate({bottom: '0'});
        $('.main-content').animate({right: '0'}).css('overflow', 'auto');
        //fading preloading out
        $('.spinner-border').fadeOut();
        $('#preloading').removeClass('d-flex').addClass('d-none');

        resolve();
        reject('Error in ' + arguments.callee.name);
    });
}
  • 和一个调整容器高度的工具
function setContainerHeight() {
    //setting the height of the container
    $('.container').css('height', $('body').height() - ($('nav').height() + $('footer').height()) + 'px');
}

我要做的是让函数按照我将它们放在上面的顺序执行。下面的代码输出 1,2,3,4 但函数“languageSpecifics”未执行或在“insertingPartials”之前执行,因为加载了部分,然后组件滑入视图,但看不到文本,也看不到链接指向任何地方。

$(document).ready( function() {

    console.log('1')
    insertingPartials().then( function() {
        console.log('2');
        languageSpecifics().then( function() {
            console.log('3');
            loadContent().then( function() {
                console.log('4');
                setContainerHeight();
            });
        });
    });

});

如果我在浏览器控制台中单独执行这些函数,我会得到所需的输出,并且每个承诺都会返回。如果我使用 .then() 运行它们,则承诺返回待处理并且我没有在页面上看到任何文本。 (嵌套的“.then(.then()”)和同一级别的“.then().then()”给出相同的结果)

我想知道我在这里做错了什么。 另外,如果有更好/更有效的方法来实现我在这里尝试做的事情,请提出建议。

【问题讨论】:

  • 您是否需要完成所有 3 个 load() 才能执行其他操作,或者您是否可以在每个 load() 完成后加载特定内容?
  • 第一个大问题是load()是异步的。因此,在 insertingPartials() 中,您在 3 次加载完成之前调用 resolve()。
  • 也不明白为什么除了动画服务器端什么都不做
  • 如何在服务器端执行所有操作? @charlietfl 你能在这里指出我正确的方向吗?这是一个简单的前端站点,我在本地使用 node http-server 进行测试。
  • 好的,但是 lang<html> 是已知的,然后不知道吗?

标签: javascript jquery html promise


【解决方案1】:

还不能评论。 Afaik .load() 是一个异步函数,这意味着在加载页面之前调用以下解析。您应该尝试使用 .load() 的回调参数,并且只有在所有这些都完成后才调用 resolve。

【讨论】:

    【解决方案2】:

    load() 是异步的,允许一个完整的回调,但不是一个承诺

    您可以将load() 替换为确实返回承诺的$.get(),并在所有3 个都加载后使用$.when() 来调用:

    除了需要在 dom 操作函数中使用 Promise 的 ajax 之外,没有什么异步的,您可以按首选顺序调用这些函数而无需任何 Promise....只有初始加载 Promise

    类似:

    // page load call
    $(function(){
       loadAllPartials().then(function(){
          languageSpecifics();
          contentDisplay();   
       });
    });
    
    // get single partial and insert in dom, return promise
    function loadPartial(url, selector) {
      return $.get(url).then(function(data) {
        $(selector).html(data);
      })
    }
    
    // return `$.when()` promise for loading all partials
    function loadAllPartials() {
      return $.when(
        loadPartial('/Assets/Partials/navbar.html', '#navbar-placeholder'),
        loadPartial('/Assets/Partials/jumbotron.html', '#jumbotron-placeholder'),
        loadPartial('/Assets/Partials/footer.html', '#footer-placeholder')
      )
    }
    
    // adjusted to synchronous code, no promises needed
    function contentDisplay() {
    
      //fading content in
      $('nav').animate({top: '0'});
      $('footer').animate({bottom: '0'});
      $('.main-content').animate({right: '0'}).css('overflow', 'auto');
      //fading preloading out
      $('.spinner-border').fadeOut();
      $('#preloading').removeClass('d-flex').addClass('d-none');
    
    }
    
    function languageSpecifics() {
      // store lang value once instead of searching dom each time
      var lang = $('html')[0].lang
      //showing correct text per html language
      $('span[lang=' + lang + ']').show();
      $('div[lang=' + lang + ']').show();
      //disabling the current language from the language selection menu
      $('a[lang=' + lang + ']').addClass('disabled');
      //links dynamically point to the correct sub-pages
      $('.blog-link').attr('href', '/' + lang + '/Blog/');
      $('.prod-link').attr('href', '/' + lang + '/' + $('.prod-link span[lang=' + lang + ']').text() + '/');
      $('#en').attr('href', window.location.href.replace(lang, 'en'));
      $('#es').attr('href', window.location.href.replace(lang, 'es'));
      $('#ro').attr('href', window.location.href.replace(lang, 'ro'));
    
    
    }
    

    【讨论】:

      【解决方案3】:

      如果您想要同步行为(即依次触发一个函数),请尝试async 函数和await 关键字。

      • 将您的每个函数包装在一个 Promise 中,包括一个以 ms 或 s 为单位的时间数字:

        const _A_ = () => {
          return new Promise(resolve => {
            setTimeout(() => resolve({{FUNCTION}}), {{TIME}});
          });
        }
        
      • 在所有 Promises 周围包裹一个 async 函数:

        const _Y_ = async() => {
        ... /* Promises */
        }
        
      • async函数的最后,使用关键字await依次调用每个Promise:

        const _Y_ = async() => {
        ... /* Promises */
          await _A_();
          await _B_();
          await _C_();
          await _D_();
        }
        

      以下演示不起作用,如果您想查看一个正常运行的演示,请转到此Plunker

      const main = document.forms[0];
      
      const loader = async(time = 700) => {
        const ajax1 = () => {
          return new Promise(resolve => {
            setTimeout(() => resolve($('.base ol').append($('<li>').load('comp.html #set1'))), time);
          });
        }
        const ajax2 = () => {
          return new Promise(resolve => {
            setTimeout(() => resolve($('.base ol').append($('<li>').load('comp.html #set2'))), time);
          });
        }
        const ajax3 = () => {
          return new Promise(resolve => {
            setTimeout(() => resolve($('.base ol').append($('<li>').load('comp.html #set3'))), time);
          });
        }
        const ajax4 = () => {
          return new Promise(resolve => {
            setTimeout(() => resolve($('.base ol').append($('<li>').load('comp.html #set4'))), time);
          });
        }
      
        await ajax1();
        await ajax2();
        await ajax3();
        await ajax4();
      
      }
      
      const getComp = e => {
        e.preventDefault();
        loader();
      }
      
      main.onsubmit = getComp;
      .set::before {
        content: attr(id);
        font: 400 16px/1 Consolas;
      }
      
      button {
        font: inherit;
        float: right;
      }
      <!doctype html>
      
      <html>
      
      <head>
      </head>
      
      <body>
        <form id='main'>
          <fieldset class='base'>
            <legend>Synchronous AJAX</legend>
            <ol></ol>
          </fieldset>
          <button>GO</button>
        </form>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      </body>
      
      </html>

      【讨论】:

        猜你喜欢
        • 2012-11-17
        • 2020-07-05
        • 2012-07-05
        • 1970-01-01
        • 2022-12-31
        • 2019-12-14
        • 2010-11-13
        • 1970-01-01
        • 2019-02-21
        相关资源
        最近更新 更多