Reputation: 803
I'm trying to execute an async
function twice one after another. But the problem is that they are executing together. But, what I want is that the 2nd execution must be start after the execution of first is completed.
PS, there are many questions on SO, with same title, like this one JavaScript: execute async function one by one. But none of them solve my problem.
Please, check the Fiddle
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index);
}, speed);
}
}
$('.intro').fadeIn(function() {
const greet = new Promise(function(resolve, reject) {
typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
@keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Here, I'm trying to print
two lines of text inside two different <h1>
tags. For that, I'm calling function typeWriter(...)
twice, once for each <h1>
. I'm trying to print
two lines, one after completion of previous one, i.e., print Hello !!
in first call and after it finishes then print I'm Learning Programming
in second line, but it is not happening. The problem is they are executing together.
On further searching for the solution, I found this question JavaScript: execute async function one by one, and follow answer given by @DavidHedlund, but It doesn't work for me. Sorry, if I'm making any mistake.
Please take a look of the fiddle that I tried from @DavidHedlund answer. In this case, only Hello !!
is printed.
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index);
}, speed);
}
}
$('.intro').fadeIn(function() {
function executeTasks() {
var tasks = Array.prototype.concat.apply([], arguments);
var task = tasks.shift();
task(function() {
if (tasks.length > 0)
executeTasks.apply(this, tasks);
});
}
function createTask(param) {
let element = param[0];
let msg = param[1];
let speed = param[2];
return function(callback) {
setTimeout(function() {
if (typeof callback == 'function') typeWriter(element, msg, speed);
}, 1);
}
}
var t1 = createTask(['#sayHello', "Hello !!", 200]);
var t2 = createTask(['#myName', "I'm Anshuman Gupta", 200]);
executeTasks(t1, t2);
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
@keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Thank you!!
Upvotes: 0
Views: 518
Reputation: 1594
So, whats happening here is, the typeWriter()
method is using a setTimeout()
, which works on a threaded model (that is setTimeout()
will not block the thread, instead will return immediately). That is why, the typeWriter()
method returns immediately, and therefore the corresponding promise resolves.
Try this code
$(document).ready(function() {
function typeWriter(element, msg, speed) {
return new Promise (function (resolve, reject) {
var recursive = function (element, msg, speed, index) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
recursive(element, msg, speed, index);
}, speed)
} else {
resolve();
}
}
recursive(element, msg, speed, 0)
})
}
$('.intro').fadeIn(function() {
typeWriter('#sayHello', "Hello !!", 200).then(function() {
return typeWriter('#myName', "I'm learning programming", 200);
});
});
})
Upvotes: 1
Reputation: 4010
The problem is you do not wait for the recursion function to finish and then call resolve.
const greet = new Promise(function(resolve, reject) {
typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
Try this:
const timeout = (speed) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, speed);
});
}
$(document).ready(function() {
async function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
await timeout(speed);
await typeWriter(element, msg, speed, index);
}
}
$('.intro').fadeIn(function() {
const greet = new Promise(async function(resolve, reject) {
await typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
});
});
Upvotes: 1
Reputation: 3888
Alternatively, you could use await
if that seems simpler for you.
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
return new Promise((resolve, reject) => {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index).then(resolve).catch(reject);
}, speed);
} else {
resolve();
}
});
}
async function typeStuff() {
console.log("Hi");
await typeWriter('#sayHello', "Hello !!", 200);
await typeWriter('#myName', "I'm learning programming", 200);
}
$('.intro').fadeIn(function() {
typeStuff();
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
@keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Explanation: in your code, you called resolve
immediately after calling typeWriter
. The issue is that typeWriter
does not "block," meaning it sets a timeout to execute code in the future and immediately returns. You can avoid this my making typeWriter
a promise. Then, you can either use await
(which is cleaner but less supported by browsers) or typeWriter(...).then(function() { /* Do more stuff */ })
(they are essentially equivalent).
Upvotes: 1