link 更多 Deferreds 示例
Deferreds 在 Ajax 背后被使用,但这并不意味着它们不能用于其他地方。本节描述了 Deferreds 有助于抽象异步行为并解耦代码的情形。
link 缓存
link 异步缓存
对于异步任务来说,缓存可能会有些苛刻,因为您必须确保对于给定的键,任务只执行一次。因此,代码必须以某种方式跟踪入站任务。
|
1
2
|
|
缓存机制必须确保 URL 只被请求一次,即使脚本尚未被缓存。这展示了一些逻辑,用于跟踪绑定到给定 URL 的回调,以便缓存系统正确处理已完成和入站的请求。
|
1
2
3
4
5
6
7
8
9
10
|
|
每个 URL 缓存一个 promise。如果给定 URL 还没有 promise,则创建一个 deferred 并发出请求。当请求完成时,deferred 被解决(使用 defer.resolve);如果发生错误,deferred 被拒绝(使用 defer.reject)。如果 promise 已经存在,回调被附加到现有的 deferred;否则,首先创建 promise,然后附加回调。这种解决方案的巨大优势在于它将透明地处理已完成和入站的请求。另一个优势是基于 deferred 的缓存将优雅地处理失败。promise 最终会被拒绝,可以通过提供一个错误回调来测试。
|
1
|
|
link 通用异步缓存
也可以使代码完全通用,构建一个缓存工厂,当键尚未在缓存中时,它将抽象出要执行的实际任务。
|
1
2
3
4
5
6
7
8
9
10
11
|
|
现在请求逻辑被抽象掉了,$.cachedGetScript() 可以重写如下:
|
1
2
3
|
|
这将起作用,因为每次调用 $.createCache() 都会创建一个新的缓存存储库并返回一个新的缓存检索函数。
link 图像加载
缓存可用于确保同一图像不会被多次加载。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
|
同样,以下代码片段
|
1
2
|
|
将起作用,无论 my-image.png 是否已加载,或者它是否正在加载过程中。
link 缓存数据 API 响应
在页面的生命周期内被认为是不可变的 API 请求也是完美的候选者。例如,以下代码
|
1
2
3
4
5
6
7
8
9
10
11
|
|
将允许您在 Twitter 上执行搜索并同时缓存它们。
|
1
2
|
|
link 计时
这种基于 deferred 的缓存不限于网络请求;它也可以用于计时目的。
例如,您可能需要在给定时间后在页面上执行一个操作,以吸引用户对他们可能不知道的特定功能的注意力,或者处理超时(例如测验问题)。虽然 setTimeout() 对于大多数用例都很好,但它不能处理稍后请求计时器的情况,即使它理论上已经过期了。我们可以使用以下缓存系统来处理这种情况:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
|
新的 $.afterDOMReady() 辅助方法在 DOM 准备就绪后提供适当的计时,同时确保使用最少的计时器。如果延迟已过期,任何回调都会立即被调用。
link 一次性事件
虽然 jQuery 提供了所有可能需要的事件绑定,但处理只需要处理一次的事件可能会变得有点麻烦。
例如,您可能希望有一个按钮,第一次点击时打开一个面板,之后保持打开状态,或者在第一次点击该按钮时执行特殊的初始化操作。处理这种情况时,通常会得到这样的代码:
|
1
2
3
4
5
6
7
8
9
|
|
然后,稍后,您可能希望执行操作,但前提是面板已打开:
|
1
2
3
4
5
|
|
这是一个高度耦合的解决方案。如果您想添加其他操作,您必须编辑绑定代码或只是复制所有内容。如果您不这样做,您唯一的选择是测试 buttonClicked,并且您可能会丢失该新操作,因为 buttonClicked 变量可能为 false,并且您的新代码可能永远不会执行。
使用 deferreds 我们可以做得更好(为了简化起见,以下代码只适用于单个元素和单个事件类型,但可以轻松推广到具有多种事件类型的完整集合):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
|
代码工作原理如下:
- 检查元素是否已经为给定事件附加了 deferred:
- 如果没有,则创建它,并使其在事件第一次触发时得到解决:
- 然后将给定的回调附加到 deferred 并返回 promise:
虽然代码肯定更冗长,但它使得以一种模块化和解耦的方式处理手头的问题变得更简单。但让我们首先定义一个辅助方法:
|
1
2
3
|
|
然后逻辑可以重构如下:
|
1
2
3
4
|
|
如果稍后只有在面板打开时才执行操作:
|
1
2
3
4
5
|
|
如果面板尚未打开,则不会丢失任何内容,操作只会推迟到按钮被点击。
link 组合辅助方法
所有上述示例单独看可能显得有些有限。然而,当您将它们混合在一起时,promise 的真正力量就会发挥作用。
link 首次点击时请求面板内容并打开该面板
以下是当点击时打开面板的按钮代码。它通过网络请求其内容,然后淡入内容。使用前面定义的辅助方法,它可以定义为:
|
1
2
3
4
5
6
7
8
9
|
|
link 首次点击时在面板中加载图像并打开该面板
另一个可能的目标是让面板淡入,前提是按钮已被点击并且所有图像都已加载。
为此的 HTML 代码看起来像这样:
|
1
2
3
4
5
6
|
|
我们使用 data-src 属性来跟踪真实的图像位置。使用我们的 promise 辅助方法处理我们的用例的代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
|
这里的诀窍是跟踪所有 $.loadImage() promise。我们稍后使用 $.when() 将它们与面板 .slideDown() 动画结合起来。因此,当按钮第一次被点击时,面板将向下滑动,图像将开始加载。一旦面板完成向下滑动并且所有图像都已加载,那么,也只有到那时,面板才会淡入。
link 在特定延迟后加载页面上的图像
为了在整个页面上实现延迟图像显示,可以在 HTML 中使用以下格式。
|
1
2
3
4
|
|
它所说的非常简单:
- 加载
image1.png并立即显示第三个图像,第一个图像在一秒后显示。 - 加载
image2.png并在第二个图像一秒后显示,第四个图像两秒后显示。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
|
为了延迟图像本身的加载:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
|
在这里,在延迟满足后,图像才被加载。当您想限制页面加载时的网络请求数量时,这很有意义。