Страницы

Поиск по вопросам

суббота, 13 июля 2019 г.

Promises. Не работает последовательность

Здравствуйте. Пишу код с использованием Обещаний для последовательного запуска функций. Только пару дней как разбираюсь с ними для улучшения кода (ибо раньше была ёлочка из коллбэков); Так вот. Есть функция анимации вывода текста на экран Animal():
function Animal(string) { var a = ''; //variable which will be entered character by character string var i= 0;//Letter counter var p = document.createElement('p'); $('body').scrollTop($('body').append(p).height()); return new Promise(function (resolve) { Anima(); function Anima() {//Function of Animation a+=string[i]; i++; $('p').last().text(a); var timer = setTimeout(Anima, 100); if(i==string.length){ clearTimeout(timer); resolve(); }; }; }); };
И функция AnimalPause() для изображения пауз(выводится на экран строка из точек и сразу же удаляется):
function AnimalPause(string) { var a = ''; //variable which will be entered character by character string var i= 0;//Letter counter var p = document.createElement('p'); $('body').scrollTop($('body').append(p).height()); return promise = new Promise(function (resolve) { Anima(); function Anima() {//Function of Animation a+=string[i]; i++; $('p').last().text(a); var timer = setTimeout(Anima, 100); if(i==string.length){ clearTimeout(timer); $('p').last().remove(); resolve(); }; }; }); };
Все сделал, вроде бы. И, если выводить последовательно строки через .then() - всё работает. И, если выводить последовательно строки с использованием цикла - тоже всё работает:
Animal('..........') .then(() => Animal('---Hello! CONSOLE v 1.0.1 is working!---')) .then(() => Animal('To see all commands u can use type -help')) .then(() => Animal('DONE'))
или так:
var chain = Promise.resolve(); pause.forEach(function(txt){ chain = chain.then(() => AnimalPause(txt))});
var pause = [ '...', '.....', '....', '.........' ];
Но если через .then() Последовательно выводить текст, потом задержку, потом - текст, рушится: (Задержка выводится после того, как выведется текст):
function Hello() { var chain = Animal('..........') .then(() => Animal('---Hello! CONSOLE v 1.0.1 is working!---')) .then(() => Animal('To see all commands u can use type -help')) .then(function() { return Pause(chain); // pause.forEach(function(txt){ // chain = chain.then(() => AnimalPause(txt))}) }) .then(() => Animal('DONE'))
}; Hello();
function Pause (chain) { return new Promise(function(resolve) { pause.forEach(function(txt){ chain = chain.then(() => AnimalPause(txt))}); resolve(); }) }
Почему? Ну..и как исправить? :)
По совету @Grundy в комментарии скидываю код для тестирования
var pause = [ '...', '.....', '....', '.........' ]; function Animal(string) { var a = ''; //variable which will be entered character by character string var i = 0; //Letter counter var p = document.createElement('p'); $('body').scrollTop($('body').append(p).height()); return new Promise(function(resolve) { Anima(); function Anima() { //Function of Animation a += string[i]; i++; $('p').last().text(a); var timer = setTimeout(Anima, 100); if (i == string.length) { clearTimeout(timer); resolve(); }; }; }); }; function AnimalPause(string) { var a = ''; //variable which will be entered character by character string var i = 0; //Letter counter var p = document.createElement('p'); $('body').scrollTop($('body').append(p).height()); return promise = new Promise(function(resolve) { Anima(); function Anima() { //Function of Animation a += string[i]; i++; $('p').last().text(a); var timer = setTimeout(Anima, 100); if (i == string.length) { clearTimeout(timer); $('p').last().remove(); resolve(); }; }; }); }; function Pause(chain) { return new Promise(function(resolve) { pause.forEach(function(txt) { chain = chain.then(() => AnimalPause(txt)) }); resolve(); }) }; function Hello() { var chain = Animal('..........') .then(() => Animal('---Hello! CONSOLE v 1.0.1 is working!---')) .then(() => Animal('To see all commands u can use type -help')) .then(function() { return Pause(chain); //Вы заметите, что строка пауз выводится после вывода на экран строки "DONE". Должно быть наоборот }) .then(() => Animal('DONE')) }; Hello();


Ответ

Если пройтись по коду, то можно отметить, что функция Animal отличается от AnimalPause только тем, что в последней в итоге удаляется добавленный элемент.
Исходя из этого можно передавать созданный p в resolve функции Animal и удалять его если надо. При этом AnimalPause выродится в следующее
function AnimalPause(string) { return Animal(string).then(p => p.remove()); };
Далее идет основная ошибка: функция Pause, которая добавляет продолжения для
var chain = Animal(...)
Но при этом не возвращает итоговый Promise, а просто переводит себя в состояние готово, именно поэтому выполнения вывода паузы откладывается до следующей цепочки.
Вместо этого нужно вернуть Promise собранный на основе массива pause с помощью функции reduce
function Pause(pause) { return pause.reduce((chain, txt) => chain.then(() => AnimalPause(txt)), Promise.resolve()); };
В этом случае возвращенный Promise будет встроен в существующую цепочку и вызван в нужном порядке.

Пример в сборе:
var pause = [ '...', '.....', '....', '.........' ]; function Animal(string) { var a = ''; //variable which will be entered character by character string var i = 0; //Letter counter var p = document.createElement('p'); $('body').scrollTop($('body').append(p).height()); return new Promise(function(resolve) { Anima(); function Anima() { //Function of Animation a += string[i]; i++; p.textContent = a; var timer = setTimeout(Anima, 100); if (i == string.length) { clearTimeout(timer); resolve(p); }; }; }); }; function AnimalPause(string) { return Animal(string).then(p => p.remove()); }; function Pause(pause) { return pause.reduce((chain, txt) => chain.then(() => AnimalPause(txt)), Promise.resolve()); }; function Hello() { var chain = Animal('..........') .then(() => Animal('---Hello! CONSOLE v 1.0.1 is working!---')) .then(() => Animal('To see all commands u can use type -help')) .then(() => Pause(pause)) .then(() => Animal('DONE')) }; Hello();

Комментариев нет:

Отправить комментарий