Здравствуйте. Пишу код с использованием Обещаний для последовательного запуска функций. Только пару дней как разбираюсь с ними для улучшения кода (ибо раньше была ёлочка из коллбэков);
Так вот. Есть функция анимации вывода текста на экран 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();
Комментариев нет:
Отправить комментарий