玩转控制台!如何展示代码自动打印的效果

1,699 阅读4分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

ezgif.com-gif-maker.gif

首先,编程应该很有趣。把无聊的东西变成console.log好看的东西是非常令人愉快的。 如果你想先睹为快,可以查看这个GitHub 存储库

第 1 步:创建一个接收字符串并将其传递到 console.log 的函数

为了确保每一步都清晰明了,我们将从小处着手,创建一个接受字符串作为参数并将其记录到控制台的函数。

const log = (s) => {
  console.log(s);
}

第 2 步:逐一记录字符串的字符

在我们可以在各个字符的输出之间添加延迟之前,我们需要确保它们实际上是分开的。

让我们添加一个for循环,遍历字符串的每个字母并将其打印到控制台。

const log = (s) => {
  for (const c of s) {
    console.log(c);
  }
}

第 3 步:如何解决换行问题

现在,每个字母都打印在一个新行上,因为每次调用都会console.log添加一个空行。

我们将替换为console.logwhichprocess.stdout.write基本上做同样的事情,但不会在输出后添加新行。

然而,现在我们在输出的最后丢失了换行符,这仍然是可取的。我们将通过显式打印\n字符来添加它。

const log = (s) => {
  for (const c of s) {
    process.stdout.write(c);
  }
  process.stdout.write('\n');
}

第四步:实现sleep功能

在 JavaScript 中,我们不能简单地停止同步代码的执行一段时间。为了实现这一点,我们需要编写自己的函数。我们称之为睡眠。

它应该接受一个参数并返回一个在毫秒ms延迟后解析的 Promise 。

const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

第 5 步:添加延迟

所以,我们准备为我们的输出添加延迟!我们在这里需要做几件事:

  • delay为函数添加参数log
  • log通过添加关键字使函数异步async
  • 调用sleep将下一次循环迭代延迟delay毫秒的函数
const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const log = async (s, delay) => {
  for (const c of s) {
    process.stdout.write(c);
    await sleep(delay);
  }
  process.stdout.write('\n');
}

第 6 步:实施随机延迟

如果我们随机化时间,输出看起来会更好。

randomized让我们在函数中添加另一个布尔参数log。如果它是真的,那么传入的参数sleep应该在从0delay毫秒的范围内。

const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const log = async (s, delay, randomized) => {
  for (const c of s) {
    process.stdout.write(c);
    await sleep((randomized ? Math.random() : 1) * delay);
  }
  process.stdout.write('\n');
}

我使用了三元运算符,但您可以将其替换为常规if语句:

if (randomized) {
  sleep(Math.random * delay);
} else {
  sleep(delay);
}

第 7 步:使日志可配置

现在,我们已经实现了几乎所有我们想要的东西。但是调用它不是很干净,因为delay每次我们想在控制台打印一些东西时都必须传递和随机化标志。

log('Hello, world!', 100, true);
log('What's up?', 100, true);
log('How are you?', 100, true);

如果我们可以有一个可以用单个参数调用的可配置日志,那就太好了——我们想要输出的字符串。

为此,我们必须重写我们的代码。这是计划:

  • 将所有当前功能包装到一个函数funkylog中,该函数接受具有 2 个字段的对象,delay并且randomized
  • funkylog应该返回匿名箭头函数。它的实现应该与log我们在步骤 1 到 6 中实现的相同
  • 参数delay并且randomized应该从log函数中删除,因为现在它们将从funkylog
const funkylog = ({ delay, randomized }) => {
  const sleep = (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms));
  };
    
  return async (s) => {
    for (const c of s) {
      process.stdout.write(c);
      await sleep((randomized ? Math.random() : 1) * delay);
    }
    process.stdout.write('\n');
  }
};

第 8 步:添加画龙点睛

让我们来看看我们得到了什么:

const log = funkylog({ delay: 100, randomized: true });

log('Hello, world!');
log('What's up?');
log('How are you?');
  • 我们可以使用该函数创建一个可配置的记录器funkylog
  • 我们可以选择我们想要的任何延迟
  • 使用记录器不需要我们delay每次调用它时都通过

我们可以做的另一项改进是为delay参数提供默认值。

const funkylog = ({ delay = 100, randomized }) => {
    ..
    ..

所以,现在我们可以在funkylog没有任何参数的情况下创建它,它仍然可以工作!

const log = funkylog();

console.log('Hello, world!');

改进思路

正如我从一开始就说过的,首先,编程应该是有趣的。

做进一步的改进funkylog,是很有趣的事情!例如,你可以通过着色来增加输出的趣味性。可以使用npm模块chalk

然后,一旦你实现了不同的颜色,你可以添加另一个标志,该标志会在字符串中的单词之间添加额外的延迟。