初识JS Promise 对象
<style>.artBox { font: normal 18px/1.5 sans-serif; overflow: auto; position: relative; }
.artBox p { margin: 10px 0; }
.artBox h1, .artBox h2 { margin: 8px 0; }
.artBox code, .artBox pre { background: rgba(0,128,128,.25); padding: 2px 6px; tab-size: 4; }
.artBox pre { padding: 10px 20px; white-space: pre-wrap; word-wrap: break-word; }
.artBox pre code { padding: 0; background: none; }
.artBox blockquote { margin: 10px 20px; padding: 2px 15px; border-left: 3px solid skyblue; background: rgba(240,248,255,.65); }
.artBox table { border-collapse: collapse; white-space: pre-wrap; box-sizing: border-box; }
.artBox th, .artBox td { padding: 8px 10px; border: 1px solid #999; }
.artBox th { text-align: center; background: #eee; }
</style>
<div class="artBox">
<p>在 Discuz! 论坛中使用JS最简洁的方式是ES导入,美中不足的是它无法与评分刷新机制完美适配,因此可以退而求其次采用回调函数加载JS资源,它解决了前者的痛点问题。</p>
<p>回调函数理论上可以加载多个JS资源,问题是容易陷入“厄运金字塔”困境,俗称“回调地狱”。加载一两个JS文档,回调函数是完全胜任的,多了令人头疼。仅从结构上看,考虑如下代码:</p>
<pre><code>// 假设已经有了一个 loadJs() 函数
loadJs(f1) {
loadJs(f2) {
loadJs(f3) {
loadJs(f4) {
// ... 这里是业务核心代码
}
}
}
}</code></pre>
<p>四个JS文件都需要全部加载完毕,业务核心代码才能出场,它处在躺平金字塔的最右侧抑或地狱的最底层。结构层面的代码无限缩进并非问题所在,致命的应该是业务逻辑问题:每一个被成功加载后可能都有各自的业务逻辑,业务代码需要分散穿插其中,分散且凌乱;其中的一个资源加载失败,局面就更不可控。</p>
<p>因此,Promise 对象应运而生,它会使得代码结构“扁平化”、代码逻辑清晰化。试看:</p>
<pre><code>// 假设已经有了一个返回 promise 的 loadJs() 函数
loadJs(f1)
.then(()=> loadJs(f2))
.then(() => loadJs(f3))
.then(loadJs(f4))
.then(()=> {
// ... 这里是业务逻辑
});</code></pre>
<p>每一个成功加载的JS如果有对应于它的业务逻辑,均可在 .then 后面加入代码块,如果没有就像上述代码那样顺延下去,直至最后一个资源加载完毕,业务核心代码最后展开。向下扩展的代码结构使得代码的结构自身“扁平化”、更易于阅读,代码逻辑也因此更明晰。</p>
<p>那么,如何使用 Promise 对象编写加载JS资源的函数呢?请看:</p>
<pre><code>function loadJs(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load error for ${src}`));
document.head.append(script);
});
}</code></pre>
<blockquote>
<p>Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。</p>
<p>Promise 是 JavaScript 中用于处理异步操作的对象,它代表一个异步操作的最终完成(或失败)及其结果值。</p>
<p>Promise 有三种状态:</p>
<p>💠 pending:初始状态,既不是成功,也不是失败状态</p>
<p>💠 fulfilled:意味着操作成功完成</p>
<p>💠 rejected:意味着操作失败</p>
<p>简单来说,Promise 是一个“承诺”,表示将来某个时间点会返回一个结果:可能是成功的结果,也可能是失败的原因。必须会有返回,所以是“真诚承诺”。</p>
</blockquote>
<p>可以像前面那样直接调用上述函数,也可以这样:</p>
<pre><code>var promise = loadJs('./yourfile.js');
promise.then(
script => tzInit(), // JS文件加载后执行业务函数
err => console.log(`Error: ${err.message}`) // 加载失败返回错误信息
);</code></pre>
<p>promise 是 Promise 对象的一个实例,来自于 loadJs 函数。Promise对象还允许使用 try/catch/finally 结构来实现更加复杂、严谨的业务逻辑。</p>
<p>【题外话】</p>
<blockquote>
<p>Promise 其实是一个古老的概念,于1976年提出,它与未来有关(承诺都是针对未来的时间点,虽然未来已来)。JS于2015年在其推出的 ES6 中集成了此对象,它解决了回调可能出现的平躺厄运,也能以无限的链式调用制造新的then地狱,因此次年,它妈妈又生了一窝代号为 ES7 的孩纸,里面的小老弟 async/await 才是异步终极的解决方案。</p>
</blockquote>
</div> Promise 音频处理案例(2024年2月下旬发的帖子):
Promise处理音频自动播放实例 - 马黑黑教程专版 - 花潮论坛 - Powered by Discuz!
该案例就是一个经典的 Promise 应用实例,特别是错误处理做了两个分支:音频有效但不支持自动播放、音频无效。
audio 控件的 play 事件本身就是一个 Promise 对象(有人也称之为类),充分利用其返回值,可以从容处理各种可能的问题。
马黑黑 发表于 2026-3-17 20:14
Promise 音频处理案例(2024年2月下旬发的帖子):
原来黑黑那么早就已经介绍了Promise的使用了啊,对这东西太陌生,完全没记住{:4_173:} Promise 使得代码逻辑清晰,更易于阅读和检查,真不错。
感谢黑黑,总是带来很多知识,虽然现在没记住,但先了解一下也很不错,以后用到肯定会记住的{:4_187:} 红影 发表于 2026-3-18 08:56
原来黑黑那么早就已经介绍了Promise的使用了啊,对这东西太陌生,完全没记住
这个东东有点抽象 红影 发表于 2026-3-18 09:00
Promise 使得代码逻辑清晰,更易于阅读和检查,真不错。
感谢黑黑,总是带来很多知识,虽然现在没记住,但 ...
真正使用到了并在实践中做尝试才会记住,否则就是简单了解一下便了 马黑黑 发表于 2026-3-18 09:25
这个东东有点抽象
非常实用呢。 马黑黑 发表于 2026-3-18 09:26
真正使用到了并在实践中做尝试才会记住,否则就是简单了解一下便了
现在的我也只能是了解一下,没本事使用呢{:4_173:} 红影 发表于 2026-3-18 12:04
现在的我也只能是了解一下,没本事使用呢
别说你,就是经常使用JS工作得人,页未必百分百会用上 Promise 红影 发表于 2026-3-18 12:03
非常实用呢。
那是相当实用的,不过如果回调可以解决问题,且不会陷入回调地狱,用回调更简单 谢谢老师经典讲授~不知为何,一看到这个Promise ,就联想到了玩频谱的痛,为何要有这样的策略呢?
“async/await 才是异步终极的解决方案。”async/await 是 Promise 的 “语法糖”,本质还是 Promise呀? 杨帆 发表于 2026-3-18 22:04
谢谢老师经典讲授~不知为何,一看到这个Promise ,就联想到了玩频谱的痛,为何要有这样的策略呢?
“asy ...
关于音视频自动播放限制策略:
这是出于特定需求,核心是避免打扰,还有流量等等问题。这种理念,或许国人不太能接受,但应该能理解。
而基于其它层面,策略仍然是需要的。比如进程执行的异步需求:读取数据需要时间,但不能因为它而停下所有的其它进程,所以,当进程一需要进程二提供的数据,进程二很耗时,这时,就需要这个 Promise 对象,具体而言,进程一等待进程二的数据,期间进程三、四等等照常运行,进程二执行完毕可以提供数据了,进程一就在这个事件节点抓住自己的机会“插队”运行;又比如限制需求:由于安全等种种原因,浏览器总会对某些东东进行各种限制,这时,JS需要通过 Promise 对象(类)找到正在运行的进程是否被限制或放行,从而决定该如何处理。
策略不是想当然的,都是基于现实需要和现实状况而制定。
关于 async/await 是 promise 的语法糖:
这种说法只能说基本正确。本质上,async/await 也依赖 Promise 对象,但二者并不完全等同,否则制定者就是白痴。
“语法糖”的说法低估了 async/wait 所带来的工程价值。客观而言,async/await 不仅是语法上的简化,更是对异步编程模式的重大改进,显著提升了代码的可读性、可维护性和开发体验。因此,可以更全面地理解为:async/await 是基于 Promise 的、更高级的异步编程语法抽象。
本帖最后由 杨帆 于 2026-3-19 21:29 编辑
马黑黑 发表于 2026-3-19 20:15
关于音视频自动播放限制策略:
这是出于特定需求,核心是避免打扰,还有流量等等问题。这种理念,或许 ...
感谢老师全面、系统、专业的权威解答,有豁然开朗之感,对音视频自动播放限制策略的制定及async/await 与 Promise的关系有了进一步的理解,由衷感谢{:4_180:} 杨帆 发表于 2026-3-19 21:27
感谢老师全面、系统、专业的权威解答,有豁然开朗之感,对音视频自动播放限制策略的制定及async/await 与 ...
{:4_191:}
页:
[1]