25-深入理解 JavaScript 异步生成器的实现
笔记+分享
在现代 JavaScript 中,async
/await
已经成为处理异步任务的常见选择,但在某些不支持原生 async/await
的环境中,我们可能需要通过生成器(Generators)来实现异步逻辑。本文将详细剖析一个 JavaScript 异步生成器控制器的实现过程,帮助您深入理解其工作原理。
背景介绍:生成器和异步生成器
生成器是 JavaScript 中的一种函数类型,调用生成器函数时返回一个迭代器对象,可以通过 next
方法一步步执行,并根据需要暂停和恢复执行。异步生成器类似,但它可以在暂停的间隙等待异步操作完成,再继续执行。
代码结构分析
以下是代码的结构。我们将逐步解释各个函数的作用,以帮助理解其整体设计。
1. 类型检测函数 t
function t(r) {
return (
(t = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator
? function (t) { return typeof t; }
: function (t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t;
}
),
t(r)
);
}
解释
t
是一个类型检测函数,用于判断传入变量 r
的类型,特别是检查是否为 Symbol
类型。通过闭包保存类型检测方法,它在后续调用时直接调用已缓存的检测逻辑,避免重复判断。
2. 异步生成器控制器 r
function r() {
"use strict";
r = function () { return n; };
var e, n = {}, o = Object.prototype, i = o.hasOwnProperty, a = "function" == typeof Symbol ? Symbol : {}, c = a.iterator || "@@iterator", u = a.asyncIterator || "@@asyncIterator", l = a.toStringTag || "@@toStringTag";
function f(t, r, e) { // 定义属性方法
return Object.defineProperty(t, r, { value: e, enumerable: !0, configurable: !0, writable: !0 }), t[r];
}
function s(t, r, e, n) { // 创建生成器实例
var o = r && r.prototype instanceof v ? r : v,
i = Object.create(o.prototype),
a = new _(n || []);
return (i._invoke = function (t, r, e) {
var n = "suspendedStart";
return function (o, i) {
if ("executing" === n) throw new Error("Generator is already running");
if ("completed" === n) {
if ("throw" === o) throw i;
return { value: void 0, done: !0 };
}
for (e.method = o, e.arg = i; ;) {
var a = e.delegate;
if (a) {
var c = m(a, e);
if (c) {
if (c === d) continue;
return c;
}
}
if ("next" === e.method) e.sent = e._sent = e.arg;
else if ("throw" === e.method) {
if ("suspendedStart" === n) throw ((n = "completed"), e.arg);
e.dispatchException(e.arg);
} else "return" === e.method && e.abrupt("return", e.arg);
n = "executing";
var u = p(t, r, e);
if ("normal" === u.type) {
if (((n = e.done ? "completed" : "suspendedYield"), u.arg === d)) continue;
return { value: u.arg, done: e.done };
}
"throw" === u.type && ((n = "completed"), (e.method = "throw"), (e.arg = u.arg));
}
};
})(t, e, a), i;
}
function p(t, r, e) { // 捕获执行异常
try {
return { type: "normal", arg: t.call(r, e) };
} catch (t) {
return { type: "throw", arg: t };
}
}
n.wrap = s;
return n;
}
解释
r
是核心的异步生成器控制器。它包含多种方法来处理生成器的各个状态,确保生成器能够正确地执行异步逻辑。
f
函数:简化Object.defineProperty
,用于定义对象属性。s
函数:生成器控制器的创建函数,通过_invoke
方法控制生成器的执行,确保其按顺序执行。p
函数:使用try-catch
捕获执行时的错误并返回,保证异常能在生成器的异步处理中正确处理。
3. 定义属性的帮助函数 h
function h(t, r, e) {
Object.defineProperty(t, r, { value: e, enumerable: !0, configurable: !0, writable: !0 });
}
解释
h
是简化的 Object.defineProperty
,为对象 t
定义属性 r
,其值为 e
。此函数使代码在定义属性时更加简洁和通用。
4. 创建生成器实例的核心函数 s
function s(t, r, e, n) {
var o = r && r.prototype instanceof v ? r : v,
i = Object.create(o.prototype),
a = new _(n || []);
return (i._invoke = function (t, r, e) {
var n = "suspendedStart";
return function (o, i) {
if ("executing" === n) throw new Error("Generator is already running");
if ("completed" === n) {
if ("throw" === o) throw i;
return { value: void 0, done: !0 };
}
for (e.method = o, e.arg = i; ;) {
var a = e.delegate;
if (a) {
var c = m(a, e);
if (c) {
if (c === d) continue;
return c;
}
}
if ("next" === e.method) e.sent = e._sent = e.arg;
else if ("throw" === e.method) {
if ("suspendedStart" === n) throw ((n = "completed"), e.arg);
e.dispatchException(e.arg);
} else "return" === e.method && e.abrupt("return", e.arg);
n = "executing";
var u = p(t, r, e);
if ("normal" === u.type) {
if (((n = e.done ? "completed" : "suspendedYield"), u.arg === d)) continue;
return { value: u.arg, done: e.done };
}
"throw" === u.type && ((n = "completed"), (e.method = "throw"), (e.arg = u.arg));
}
};
})(t, e, a), i;
}
解释
- 生成器实例:
i
是生成器实例,通过闭包保存并控制生成器的执行顺序。 _invoke
方法:控制生成器的执行状态,如suspendedStart
、executing
和completed
,确保生成器不会被重复执行。
5. 执行异步生成器的核心部分
function () {
var t = this, r = arguments;
return new Promise(function (o, i) {
var a = n.apply(t, r);
function c(t) {
e(a, o, i, c, u, "next", t);
}
function u(t) {
e(a, o, i, c, u, "throw", t);
}
c(void 0);
});
})();
解释
最后,这段匿名函数通过 Promise
包装生成器,使其具有异步行为。c
和 u
方法分别对应生成器的 next
和 throw
操作,确保生成器的 next
方法能继续执行。
总结
本文解析了一个 JavaScript 异步生成器控制器的实现。通过这种控制器,您可以在不支持 async
/await
的环境中,管理基于生成器的异步操作。这一实现方式不仅提高了代码兼容性,还帮助我们更深入地理解了异步生成器的内部工作机制。