Как правильно использовать Promise.then () в JavaScript? - PullRequest
0 голосов
/ 31 марта 2019

Я пытаюсь запускать некоторые функции одну за другой, используя Promises, но почему-то вторая функция либо выполняется раньше первой, либо не выполняется вообще.Ситуация такова:

У меня есть следующие функции:

  • Функция, которая загружает HTML-код многократного использования из папки Partials:
    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» не выполняется или выполняется до «insertPartials», потому что загружаются частичные компоненты, а затем компоненты передвигаются в поле зрения, но текст не может быть виден, и при этомссылки указывают куда угодно.

$(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 ]

2 голосов
/ 31 марта 2019

Не можете комментировать.Afaik .load () является асинхронной функцией, что означает следующее разрешение вызывается перед загрузкой страниц.Вы должны попытаться использовать параметр обратного вызова .load () и разрешение вызовов только после того, как все они завершены.

1 голос
/ 31 марта 2019

load() является асинхронным и допускает полный обратный вызов, но не обещание

Вы можете заменить load() на $.get(), который возвращает обещание, и использовать $.when() для вызова после загрузки всех трех:

Нет ничего асинхронного, кроме ajax, который потребовал бы использования обещаний в ваших функциях манипуляции с dom, и вы можете просто вызывать эти функции в предпочтительном порядке без каких-либо необходимых обещаний ... только первоначальное обещание загрузки

Что-то вроде:

// 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'));


}
1 голос
/ 31 марта 2019

Если вы хотите синхронного поведения (т. Е. Запускать одну функцию за другой по порядку), попробуйте async function и await ключевое слово.

  • Оберните каждую из ваших функций в Promise, включая число времени в мс или с:

    const _A_ = () => {
      return new Promise(resolve => {
        setTimeout(() => resolve({{FUNCTION}}), {{TIME}});
      });
    }
    
  • Оберните async функцию вокруг всех Обетований:

    const _Y_ = async() => {
    ... /* Promises */
    }
    
  • В конце функции async вызывайте каждое Promise с ключевым словом await:

    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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...