FE_You_dont_know
FE_You_dont_know copied to clipboard
JS之最佳实践(1)
Programs are meant to be read by humans and only incidentally for computers to execute.
—— Donald Knuth
今天在微信群里看到一个问题:
如何实现一个函数,使得 repeat(() => {console.log('1')}, 5, 2000) 每两秒执行一次打印,总共五次?
这个问题当然不难,使用定时器就可以了,基本上会写JS的同学都能解决这个问题。在ES2017之前,实现方法也有很多,但现在都9102年了,如果是我来实现的话,基本上毫不犹豫写下面的代码:
function wait(millisecond) {
return new Promise((resolve) => {
setTimeout(resolve, millisecond);
});
}
async function repeat(task, count = 1, millisecond = 0) {
while(count--) {
await wait(millisecond);
task();
}
}
为什么这样写呢?因为这个代码结构极其简单,while循环基本上学过程序开发的新手都能理解,只要再了解一下async/await的语义(实际上猜都能猜到),就能彻底明白代码的含义:
while(count--) {
await wait(millisecond);
task();
}
循环count次,每次wait若干毫秒,这个代码逻辑简单到不需要任何注释。
使用也非常方便,因为它自身是async的函数,返回promise,所以如果我们需要等待执行完成后执行其他任务,只需要放到async function中并加上await:
(async function() {
await repeat(taskA, 5, 2000);
taskB();
}());
反之,如果我们希望任务同步执行,只需要去掉await。
repeat(taskA, 5, 2000);
taskB();
如果我们希望A、B都重复若干次,且A、B先后依次执行:
await repeat(taskA, 5, 2000);
await repeat(taskB, 5, 2000);
如果我们希望A、B都重复若干次,且并行执行:
await Promise.all([repeat(taskA, 5, 2000), repeat(taskB, 5, 2000)])
如果我们希望taskA、taskB也可以是异步方法,可以稍微修改一下repeat实现:
async function repeat(task, count = 1, millisecond = 0) {
while(count--) {
await wait(millisecond);
await task();
}
}
总之,代码是给人阅读的,在ES2017之后,JavaScript支持了async function,请大家在处理异步操作时,使用async function,这样能够写出简洁的,让人非常容易阅读和理解的代码来。
关于async/await的最佳实践,大家还有什么想法,欢迎在issue中讨论。
异常处理
async function asyncMethod() {
try {
// normal: todo
} catch (error) {
// error: todo
}
}
async function asyncMethod() {
try {
loading = true; // 数据请求态
} catch (error) {
console.log(error);
} finally {
loading = false; // 数据请求完成
}
}
- 这种处理是必要的,但在遇到的大多数代码仅仅只是打印了错误。
- 强烈建议部署前端异常监控,如:在 catch 内部署特定异常监控代码等...
- 可通过高阶函数或webpack插件在转译时注入。但这种处理方式多少有失灵活。
- 还有没有更好的实现方式去处理异常呢❓
@cllemon 异常该怎么处理就怎么处理。在catch内部署异常监控(catch之后log然后rethrow)是不必要的,因为你可以用onerror、onunhandledrejection 之类的来统一处理。唯一的例外是老ie/edge不支持跨源脚本onerror时不得已为之。