I'm trying to make a custom typewriter effect on my site using a javascript function. In order to add a delay between the typing of each letter, I've implemented a staggered setTimeout
for each run of the for loop, so each iteration is delayed by an extra 300ms compared to the previous one. I need special characters (' ' '<', '>') to be typed as single characters rather than as individual letters, so I have a few else if
conditions. This produces the desired effect when setTimeout
is excluded. However, adding the delay results in spelling out the individual letters of this code after printing out the whole character. How can I fix this?
function type(fullTxt, current = '') {
for (let i = current.length, j = 0; i < fullTxt.length; i , j ) {
setTimeout(function() {
if (fullTxt.substring(i, i 6) === ' ') {
console.log(fullTxt.substring(0, i 6));
i = i 5;
} else if (fullTxt.substring(i, i 4) === '<') {
console.log(fullTxt.substring(0, i 4));
i = i 3;
} else if (fullTxt.substring(i, i 3) === '>') {
console.log(fullTxt.substring(0, i 3));
i = i 2;
} else {
console.log(fullTxt.substring(0, i 1));
}
console.log(j); //included just to ensure j is counting properly
console.log(i); //included to check progress of loop
console.log(fullTxt.length); //included to check endpoint of for loop
}, j * 300);
}
}
type('hello ');
Expected output:
// h
// 0
// 0
// 11
// he
// 1
// 1
// 11
// hel
// 2
// 2
// 11
// hell
// 3
// 3
// 11
// hello
// 4
// 4
// 11
// hello
// 5
// 10
// 11
CodePudding user response:
You could put the setTimeout
on only the console.log
rather than around the entire if
statement.
function type(fullTxt, current = '') {
for (let i = current.length, j = 0; i < fullTxt.length; i , j ) {
if (fullTxt.substring(i, i 6) === ' ') {
setTimeout(function() {
console.log(fullTxt.substring(0, i 6));
}, j * 300);
i = i 5;
} else if (fullTxt.substring(i, i 4) === '<') {
setTimeout(function() {
console.log(fullTxt.substring(0, i 4));
}, j * 300);
i = i 3;
} else if (fullTxt.substring(i, i 3) === '>') {
setTimeout(function() {
console.log(fullTxt.substring(0, i 3));
}, j * 300);
i = i 2;
} else {
setTimeout(function() {
console.log(fullTxt.substring(0, i 1));
}, j * 300);
}
setTimeout(function() {
console.log(j); //included just to ensure j is counting properly
console.log(i); //included to check progress of loop
console.log(fullTxt.length); //included to check endpoint of for loop
}, j * 300);
}
}
type('hello ');
CodePudding user response:
you can achieve this using async
function
async function type(fullTxt, current = '') {
for (let i = current.length, j = 0; i < fullTxt.length; i , j ) {
await waitFor(j*300);
if (fullTxt.substring(i, i 6) === ' ') {
console.log(fullTxt.substring(0, i 6));
i = i 5;
} else if (fullTxt.substring(i, i 4) === '<') {
console.log(fullTxt.substring(0, i 4));
i = i 3;
} else if (fullTxt.substring(i, i 3) === '>') {
console.log(fullTxt.substring(0, i 3));
i = i 2;
} else {
console.log(fullTxt.substring(0, i 1));
}
console.log(j); //included just to ensure j is counting properly
console.log(i); //included to check progress of loop
console.log(fullTxt.length); //included to check endpoint of for loop
}
}
type('hello ');
here is waitFor
function
function waitFor(ms){
return new Promise(resolve=> setTimeout(resolve,ms))
}
CodePudding user response:
The safer now is to use async/await
, calling a Promise
, this way, your loop is actually waiting for the one before to complete.
Also this makes stuffs easy to write, or later modify.
Timeout set to 2000
ms for the demo.
async function type(fullTxt, current = '') {
for (let i = current.length, j = 0; i < fullTxt.length; i , j ) {
await wait(2000) // Wait for 2000ms
if (fullTxt.substring(i, i 6) === ' ') {
console.log(fullTxt.substring(0, i 6));
i = i 5;
} else if (fullTxt.substring(i, i 4) === '<') {
console.log(fullTxt.substring(0, i 4));
i = i 3;
} else if (fullTxt.substring(i, i 3) === '>') {
console.log(fullTxt.substring(0, i 3));
i = i 2;
} else {
console.log(fullTxt.substring(0, i 1));
}
console.log(j); //included just to ensure j is counting properly
console.log(i); //included to check progress of loop
console.log(fullTxt.length); //included to check endpoint of for loop
}
}
// Generic Promise function
function wait(delayInMS) {
return new Promise((resolve) => setTimeout(resolve, delayInMS));
}
type('hello ');