23、JavaScript异步编程与日期处理全解析

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应用,处理复杂的异步任务和精确的日期时间操作。希望大家在实际开发中能够熟练掌握这些技巧,提升开发效率和代码质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值