随着前端页面越来越复杂,异步操作在前端开发中扮演越来越重要的角色。Promise 是 JavaScript 中解决异步问题的重要手段之一,但是很多人在使用 Promise 时犯了一个常见的错误 -- 在 Executor 中使用异步操作。
本文将详细探讨这个 Promise 反模式,并提供一些建议以及示例代码,帮助读者避免这个反模式。
什么是 Promise 反模式?
Promise 反模式包括在 Executor 中使用异步操作。Executor 是 new Promise((resolve, reject) => {}) 中的函数,它会在 Promise 被实例化时立即执行。Executor 函数的作用是初始化 Promise,通常它是一些异步操作的集合,比如从服务器拉取数据、打开文件等等。Executor 经常与 resolve 和 reject 函数配合使用。
Promise 反模式的代码示例:
--- ----------------- ------- -- - ------------- -- - ---------------- -- ------ ---
在上面的示例中,setTimeout 字符串会在 Promise 实例化时立即执行,它会在 1 秒后将 Promise 从等待中解决为完成,并返回一个 'done' 的值。
在 Executor 函数中使用异步操作似乎是很自然的一件事情,但是它的问题在于,它会在 Promise 已经被实例化后再去执行一些异步操作,这样容易导致一些问题的产生,比如前面述的 Promise 反模式。
Promise 反模式的问题
在 Executor 中使用异步操作会导致以下问题:
1. 难以调试
在 Executor 中使用异步操作可以造成调试困难。当程序在异步应用正在执行时,调试器指向的是异步操作。异步操作完成之后,有可能程序已经执行了好几步,导致调试器难以追踪到问题出现的位置。
2. 维护困难
在 Executor 中使用异步操作会导致代码变得难以维护。由于异步操作是在 Promise 实例化后才被执行,它们在 Promise 成功或失败之前的时间段对开发者不可见。如果异步操作出错了该怎么办?开发者只能通过 Promise 的回调函数去捕捉错误。
3. 风险加大
在 Executor 中使用异步操作还有一个风险问题 -- 异步操作会在 Promise 的状态转换之前执行。这意味着,在异步操作执行之前,Promise 可能会已经被 resolved 或 rejected。
以延迟为例。在执行一个异步操作时,开发者经常会添加一个延迟时间以防止过早的 resolve 或 reject 函数的调用。但是,如果 Executor 包含了异步操作时,Promise 的状态可能已经发生了变化,而延迟操作还没有开始执行。
这样的情况会导致非常大的风险。由于这个反模式会破坏 Promise 的基本行为,开发者可能会写出不可靠的代码。
一些类似于这些的代码就是 tip 67 from the book 97 Things Every Programmer Should Know, which says:
Don't rely on asynchronous code in your constructor or destructor.
如何避免 Promise 反模式?
为了避免上述的问题,我们应该遵守下面的三个步骤:
1. 在 Executor 中使用同步操作
我们应该只在 Executor 中使用同步操作,执行最基本的初始化或验证。如果需要异步操作,我们应该使用 Promise 函数链。这样可以确保异步操作发生在 Promise 成功或失败之后,从而便于调试和维护。
--- ----------------- ------- -- - ----- ------- - ----------------- -- --------- - ----------------- - ---- - ------------------ - ---------------- -- - -- ------- -------------- -- - ------------------- ---
在上面的示例中,我们使用同步操作执行验证,如果验证通过,则通过 resolve 函数将 Promise 的状态变为 resolved,否则通过 reject 函数将 Promise 状态变为 rejected。然后我们使用 then 函数添加要执行的异步操作。如果出现任何错误,我们也通过 catch 函数来处理错误。
这样不仅简化了代码,还可以使调试、维护和编写代码变得更容易。
2. 使用 async/await
async/await 是处理异步操作的新标准。它可以使异步代码更简洁、易读和易于调试。
----- -------- ----------- - --- - ----- ---- - ----- ------------------ ------ ------------ - ------------ - ------------------- - - --------------------- -- - ------------------ ---
在上面的示例中,我们使用 async/await 从服务器获取数据。这样可以使代码变得更简洁和易于理解,而且 async/await 的错误处理机制也很好用。
3. 避免使用延迟执行
监控托管平台 Sentry 中的团队为大家提供了一篇有效博客文章。
延迟操作是 Promise 中经常使用的技术,但我们应该避免在 Executor 中使用它。我们应该尽量避免在 Promise 页面结束之前执行异步操作。
可以用 Promise 加 setTimeout 来代替使用延时执行:
--- ----------------- ------- -- - ------------- -- - ----- ------- - ----------------- -- --------- - ----------------- - ---- - ------------------ - -- ------ ---------------- -- - -- ------- -------------- -- - ------------------- ---
这个示例使用了 setTimeout 和 Promise,但是 setTimeout 的含义不一样了。这是一种技巧,为了让 Promise 执行异步操作而不是等待异步操作,我们设定了一个无关紧要的延迟时间。
结论
在 Promise 中使用异步操作是 Promise 反模式,如果使用不当可能会导致难以调试、难以维护和风险加大的问题。为避免这些问题,并写出可靠的代码,我们应该在 Executor 中使用同步操作、尽可能使用 async/await,并避免使用延迟执行。
希望本篇文章的指导能帮助到开发者们写出可靠的前端代码~
来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/66ee565b6fbf960197215d59