10月阅读周·JavaScript异步编程设计快速响应的网络应用:生成Promise对象篇

举报
叶一一 发表于 2024/10/21 09:19:35 2024/10/21
【摘要】 背景去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。没有计划的阅读,收效甚微。新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。这个“玩法”虽然常见且板正,但是有效,已经坚持阅读九个月。已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScri...

背景

去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。

没有计划的阅读,收效甚微。

新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。

这个“玩法”虽然常见且板正,但是有效,已经坚持阅读九个月。

已读完书籍《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》、《你不知道的JavaScript(下卷)》、《数据结构与算法JavaScript描述》、《WebKit技术内幕》、《前端架构:从入门到微前端》、《秒懂算法:用常识解读数据结构与算法》、《JavaScript权威指南》

当前阅读周书籍《JavaScript异步编程设计快速响应的网络应用》

生成Promise对象

假设我们提示用户应敲击 Y键或 N键。为此要做的第一件事就是生成一个$.Deferred实例以代表用户做出的决定。

var promptDeferred = new $.Deferred();
promptDeferred.always(function () {
  console.log('A choice was made:');
});
promptDeferred.done(function () {
  console.log('Starting game……');
});
promptDeferred.fail(function () {
  console.log('No game today.');
});

(注:always 关键字仅适用于jQuery 1.6+。)

大家可能会奇怪:为什么本节叫做“生成 Promise 对象”,却要生成一个Deferred(延迟)实例?别担心,Deferred就是Promise!更准确地说,Deferred是Promise的超集,它比Promise多了一项关键特性:可以直接触发。纯Promise实例只允许添加多个调用,而且必须由其他什么东西来触发这些调用。

使用resolve(执行)方法和reject(拒绝)方法均可触发Deferred对象。

$('#playGame')
  .focus()
  .on('keypress', function (e) {
    var Y = 121,
      N = 110;
    if (e.keyCode === Y) {
      promptDeferred.resolve();
    } else if (e.keyCode === N) {
      promptDeferred.reject();
    } else {
      return false; // 这里的Deferred 对象保持着挂起状态
    }
  });

输出:

A choice was made:
Starting game...

大家看懂是怎么回事了吗?执行了Deferred(即对Deferred对象调用了resolve方法)之后,即运行该对象的always(恒常)回调和done(已完成)回调。(会按照绑定回调的次序来运行回调,这可不是巧合哦!)

刷新页面,敲击N键。

A choice was made:
Noe game today.

这样,拒绝了Deferred(即对Deferred对象调用了reject方法)之后,即运行该对象的 always 回调和 fail(失败)回调。注意,始终会按照绑定回调的次序来运行回调。如果最后绑定的是always回调,则控制台的输出行顺序会反过来。

再试着反复敲击 Y键和 N键。第一次做出选择之后,就再也没有反应了!这是因为Promise只能执行或拒绝一次,之后就失效了。我们断言,Promise 对象会一直保持挂起状态,直到被执行或拒绝。对Promise对象调用state(状态)方法,可以查看其状态是"pending"、"resolved",还是"rejected"。(到 jQuery 1.7才添加了 state 方法,此前的版本使用的是isResolved和isRejected。)

如果正在进行的一次性异步操作的结果可以笼统地分成两种(如成功/失败,或接受/拒绝),则生成Deferred对象就能直观地表达这次任务。

成纯Promise对象

CommonJS的Promises/A规范及其实现中使用了一种更合理的说法:Promise对象已履行(关键字为fulfill)或已拒绝,这两种情况都称Promise已执行。3.7节会对此作进一步阐述。

var promptPromise = promptDeferred.promise();

promptPromise 只是 promptDeferred 对象的一个没有resolve/reject方法的副本。我们把回调绑定至Deferred或其下辖的Promise并无不同,因为这两个对象本质上分享着同样的回调。它们也分享着同样的state(返回的状态值为"pending"、"resolved"或"rejected")。这意味着,对同一个Deferred对象生成多个Promise对象是毫无意义的。事实上,jQuery给出的只不过是同一个对象。

var promise1 = promptDeferred.promise();
var promise2 = promptDeferred.promise();
console.log(promise1 === promise2); // true

而且,对一个纯Promise对象再调用promise方法,产生的只不过是一个指向相同对象的引用。

console.log(promise1 === promise1.promise()); // true

总结

使用promise方法的唯一理由就是“封装”。如果传递promptPromise对象,但保留promptDeferred 对象为己所用,则可以肯定的是,除非是你自己想触发那些回调,否则任何回调都不会被触发。

每个Deferred对象都含有一个Promise对象,而每个Promise对象都代表着一个 Deferred对象。有了 Deferred对象,就可以控制其状态,而有了纯 Promise 对象,只能读取其状态及附加回调。


作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏️ | 留言📝

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。