JavaScript异步编程与日期处理全解析
异步编程的奥秘
在JavaScript的世界里,异步编程是核心内容之一。它通过回调函数来管理异步执行,不过回调函数存在一些问题,比如可能会被多次调用。而Promise的出现,很好地解决了这个问题,虽然它并没有取代回调函数,因为Promise本身也需要 then 和 catch 回调。
下面是异步编程的一些关键要点总结:
- 异步执行靠回调:JavaScript使用回调函数来处理异步操作。
- Promise不替代回调:Promise虽然强大,但仍依赖 then 和 catch 回调。
- 避免多次调用:Promise能避免回调被多次调用。
- 多次调用考虑事件:若需要回调多次执行,可结合事件与Promise。
- 超时保护:Promise不能保证一定会解决,但可包裹在超时函数中保护。
- 链式组合:Promise可链式调用,方便组合操作。
- 结合生成器:Promise能与生成器运行器结合,实现同步语义。
- 并行处理:编写生成器函数时,用 Promise.all 并行执行部分算法。
- 别造轮子:使用 co 或 Koa 作为生成器运行器,用 Q 转换Node风格回调为Promise。
- 异常处理:生成器运行器支持 try/catch 异常处理。
graph LR
A[异步编程] --> B[回调函数]
A --> C[Promise]
C --> D[避免多次调用]
C --> E[链式组合]
C --> F[结合生成器]
A --> G[生成器运行器]
G --> H[异常处理]
另外,不建议自己编写生成器运行器, co 生成器运行器功能丰富且健壮。如果在构建网站,可考虑使用 Koa ,它能与 co 配合,让你像在 theFutureIsNow 函数中一样使用 yield 编写Web处理程序。
以下是添加了异常处理的 theFutureIsNow 函数示例:
function* theFutureIsNow() {
let data;
try {
data = yield Promise.all([
nfcall(fs.readFile, 'a.txt'),
nfcall(fs.readFile, 'b.txt'),
nfcall(fs.readFile, 'c.txt'),
]);
} catch(err) {
console.error("Unable to read one or more input files: " + err.message);
throw err;
}
yield ptimeout(60*1000);
try {
yield nfcall(fs.writeFile, 'd.txt', data[0]+data[1]+data[2]);
} catch(err) {
console.error("Unable to write output file: " + err.message);
throw err;
}
}
日期与时间的处理
在实际应用中,处理日期和时间是常见需求,但JavaScript的 Date 对象存在一些不足。它最初由Netscape程序员Ken Smith实现,本质上是将Java的 java.util.Date 移植到了JavaScript中。
日期、时间的表示涉及到秒、时区、时间戳和Unix纪元等概念。在JavaScript里,所有 Date 实例都以自Unix纪元(1970年1月1日00:00:00 UTC)以来的毫秒数存储。可以使用 valueOf() 方法查看其数值表示。
构建 Date 对象有四种方式:
| 构建方式 | 示例 | 说明 |
| ---- | ---- | ---- |
| 无参 | new Date() | 返回当前日期对象 |
| 字符串解析 | new Date('June 14, 1903') | 尝试解析字符串为日期 |
| 指定本地日期 | new Date(2015, 0) | 指定具体日期,月份从0开始 |
| Unix时间戳 | new Date(0) | 根据Unix时间戳创建日期 |
不过,JavaScript的 Date 对象无法指定时区,它总是将对象内部存储为UTC,并根据操作系统的本地时间格式化。
为了更好地处理日期,引入了 Moment.js 库。它有带时区支持和不带时区支持两种版本。
- Web项目 :可从CDN引用,如:
<script src="//cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.4.0/moment-timezone.min.js"></script>
- Node项目 :使用
npm install --save moment-timezone安装,然后在脚本中引用:
const moment = require('moment-timezone');
在构建日期时,服务器端和浏览器端有不同的建议:
- 服务器端 :建议使用UTC或明确指定时区。使用 Date.UTC 方法创建UTC日期,或使用 moment.tz 创建特定时区的日期。
// 创建UTC日期
const d = new Date(Date.UTC(2016, 4, 27));
// 创建特定时区日期
const d = moment.tz([2016, 3, 27, 9, 19], 'America/Los_Angeles').toDate();
- 浏览器端 :JavaScript默认行为通常合适,若需处理其他时区日期,可使用
Moment.js。
在传输日期时,可使用JSON或日期的数值。JSON序列化日期时,虽然不能无缝对称处理,但可通过 new Date() 恢复日期。
const before = { d: new Date() };
const json = JSON.stringify(before);
const after = JSON.parse(json);
after.d = new Date(after.d);
显示日期时,JavaScript的 Date 对象内置格式化选项有限且不灵活,而 Moment.js 的 format 方法能满足各种日期格式化需求。
const d = new Date(Date.UTC(1930, 4, 10));
// Date对象内置方法
d.toLocaleDateString(); // "5/9/1930"
// Moment.js方法
moment(d).format("YYYY-MM-DD"); // "1930-05-09"
如果需要访问 Date 实例的各个组件,可使用相应方法:
const d = new Date(Date.UTC(1815, 9, 10));
d.getFullYear(); // 1815
d.getMonth(); // 9 - October
d.getDate(); // 9
d.getDay(); // 1 - Monday
综上所述,掌握异步编程和日期处理的技巧,能让你在JavaScript开发中更加得心应手。无论是处理复杂的异步操作,还是精确地操作日期和时间,合理运用这些知识和工具都能帮助你高效完成任务。
JavaScript异步编程与日期处理全解析
异步编程深入探讨
在异步编程里,生成器运行器发挥着重要作用。虽然自己编写生成器运行器是个不错的练习,但其中存在诸多细微之处和改进空间,所以最好不要重复造轮子。 co 生成器运行器功能完备且稳定,若你在构建网站, Koa 是个不错的选择,它能与 co 协同工作,让你使用 yield 编写Web处理程序,就像在 theFutureIsNow 函数中那样。
生成器运行器的另一个重要优势是支持 try/catch 异常处理。在回调和Promise中,异常处理存在问题,比如在回调内部抛出的异常无法在回调外部捕获。而生成器运行器在保持异步执行的同时,实现了同步语义,从而能与 try/catch 配合使用。以下是添加了异常处理的 theFutureIsNow 函数:
function* theFutureIsNow() {
let data;
try {
data = yield Promise.all([
nfcall(fs.readFile, 'a.txt'),
nfcall(fs.readFile, 'b.txt'),
nfcall(fs.readFile, 'c.txt'),
]);
} catch(err) {
console.error("Unable to read one or more input files: " + err.message);
throw err;
}
yield ptimeout(60*1000);
try {
yield nfcall(fs.writeFile, 'd.txt', data[0]+data[1]+data[2]);
} catch(err) {
console.error("Unable to write output file: " + err.message);
throw err;
}
}
这个函数展示了如何在生成器函数中使用 try/catch 来处理可能出现的错误。在读取文件和写入文件的操作中,都添加了异常处理,当出现错误时,会输出相应的错误信息并抛出错误。
日期处理的更多细节
Moment.js 是一个强大的日期处理库,它能满足各种日期操作需求。下面我们来详细了解一些使用场景和操作步骤。
日期比较
在实际应用中,经常需要比较两个日期的先后顺序。使用 Moment.js 可以轻松实现这一点。
const moment = require('moment-timezone');
const date1 = moment('2023-10-01');
const date2 = moment('2023-10-10');
if (date1.isBefore(date2)) {
console.log('date1 is before date2');
} else if (date1.isAfter(date2)) {
console.log('date1 is after date2');
} else {
console.log('date1 is the same as date2');
}
日期计算
Moment.js 还支持日期的加减运算。例如,计算某个日期之后或之前的日期。
const moment = require('moment-timezone');
const currentDate = moment();
const futureDate = currentDate.clone().add(7, 'days');
const pastDate = currentDate.clone().subtract(3, 'months');
console.log('Future date:', futureDate.format('YYYY-MM-DD'));
console.log('Past date:', pastDate.format('YYYY-MM-DD'));
日期范围判断
判断一个日期是否在某个范围内也是常见需求。
const moment = require('moment-timezone');
const startDate = moment('2023-09-01');
const endDate = moment('2023-10-31');
const targetDate = moment('2023-10-15');
if (targetDate.isBetween(startDate, endDate)) {
console.log('Target date is within the range');
} else {
console.log('Target date is outside the range');
}
以下是一个总结 Moment.js 常用方法的表格:
| 操作 | 方法 | 示例 |
| ---- | ---- | ---- |
| 日期比较 | isBefore 、 isAfter 、 isSame | date1.isBefore(date2) |
| 日期计算 | add 、 subtract | currentDate.add(7, 'days') |
| 日期范围判断 | isBetween | targetDate.isBetween(startDate, endDate) |
graph LR
A[Moment.js操作] --> B[日期比较]
A --> C[日期计算]
A --> D[日期范围判断]
B --> E[isBefore]
B --> F[isAfter]
B --> G[isSame]
C --> H[add]
C --> I[subtract]
D --> J[isBetween]
总结
在JavaScript开发中,异步编程和日期处理是非常重要的两个方面。异步编程通过回调函数、Promise和生成器运行器等机制,实现了高效的异步操作,同时通过 try/catch 实现了良好的异常处理。日期处理方面,JavaScript原生的 Date 对象存在一些局限性,而 Moment.js 库则提供了丰富的功能,无论是日期的构建、传输、显示,还是比较、计算和范围判断等操作,都能轻松应对。
通过合理运用这些知识和工具,我们能够更加高效地开发JavaScript应用,处理复杂的异步任务和精确的日期时间操作。希望大家在实际开发中能够熟练掌握这些技巧,提升开发效率和代码质量。
超级会员免费看

被折叠的 条评论
为什么被折叠?



