JS 中 Promise 编写技巧~
2023-09-18 01:26:27
对于一个合格的前端工程师来说,Promise 那可是咱 Javascript 中的浪漫,每天都用,虽然每天都用,但是小伙伴们不确定自己对 Promise 的了解是否完整?你是不是有时候觉得一些地方有点懵,但是又不确定这是因为自己粗心,还是 Promise 本身就在使用上有些盲区呢?
1. 不要在 Promise 中使用 catch
来处理同步错误
catch
块是用来处理异步错误的。如果在 Promise 中使用 catch
来处理同步错误,就会导致代码难以理解和维护。例如:
function foo() {
throw new Error('This is a synchronous error');
}
foo().catch(err => {
console.log(err.message);
});
这段代码会导致错误消息 'This is a synchronous error'
被打印两次。一次是通过 throw
语句,另一次是通过 catch
块。
为了避免这种问题,应该在同步代码中使用 try...catch
语句来处理同步错误。例如:
try {
foo();
} catch (err) {
console.log(err.message);
}
2. 不要在 Promise 中返回一个新的 Promise
如果在 Promise 中返回一个新的 Promise,就会导致代码难以理解和维护。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
foo().then(result => {
console.log(result);
});
这段代码会导致 'Hello world!'
被打印两次。一次是通过 resolve
函数,另一次是通过 then
方法。
为了避免这种问题,应该在 Promise 中直接返回一个值,而不是返回一个新的 Promise。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
foo().then(result => {
console.log(result);
}).then(result => {
console.log(result);
});
3. 不要在 Promise 中使用 finally
块来处理错误
finally
块是用来处理 Promise 的最终状态的。如果在 Promise 中使用 finally
块来处理错误,就会导致代码难以理解和维护。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('This is an error'));
}, 1000);
});
}
foo().then(result => {
console.log(result);
}).catch(err => {
console.log(err.message);
}).finally(() => {
console.log('This will always be called');
});
这段代码会导致 'This is an error'
被打印两次。一次是通过 reject
函数,另一次是通过 finally
块。
为了避免这种问题,应该在 Promise 中直接处理错误,而不是在 finally
块中处理错误。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('This is an error'));
}, 1000);
});
}
foo().then(result => {
console.log(result);
}).catch(err => {
console.log(err.message);
});
4. 不要在 Promise 中使用竞争条件
竞争条件是指两个或多个并发执行的进程试图访问同一个共享资源,从而导致数据不一致的情况。在 Promise 中,竞争条件可能会导致意外的结果。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
function bar() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Goodbye world!');
}, 1000);
});
}
Promise.all([foo(), bar()]).then(results => {
console.log(results);
});
这段代码会导致 ['Goodbye world!', 'Hello world!']
被打印,而不是 ['Hello world!', 'Goodbye world!']
。这是因为 bar()
函数的执行速度比 foo()
函数的执行速度快,导致 bar()
函数的返回值先被打印出来。
为了避免这种问题,应该使用 Promise.race()
方法来处理竞争条件。Promise.race()
方法会返回最先完成的 Promise 的返回值。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
function bar() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Goodbye world!');
}, 1000);
});
}
Promise.race([foo(), bar()]).then(result => {
console.log(result);
});
这段代码会导致 'Hello world!'
被打印,而不是 'Goodbye world!'
。这是因为 foo()
函数的执行速度比 bar()
函数的执行速度快,导致 foo()
函数的返回值先被打印出来。
5. 不要在 Promise 中使用不必要的代码
Promise 中不必要的代码会增加代码的复杂性,并使代码难以理解和维护。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
foo().then(result => {
console.log(result);
}).then(result => {
console.log(result);
}).then(result => {
console.log(result);
});
这段代码会导致 'Hello world!'
被打印三次。这是因为 then()
方法会返回一个新的 Promise,而新的 Promise 也会调用 then()
方法。
为了避免这种问题,应该在 Promise 中使用 finally()
方法来处理最终状态。finally()
方法不会返回一个新的 Promise,因此不会导致不必要的代码执行。例如:
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello world!');
}, 1000);
});
}
foo().then(result => {
console.log(result);
}).finally(() => {
console.log('This will be called regardless of the Promise state');
});
这段代码会导致 'Hello world!'
被打印一次,然后 'This will be called regardless of the Promise state'
被打印一次。