diff --git a/node_modules/fresh/index.js b/node_modules/fresh/index.js index d154f5a..e0c2857 100644 --- a/node_modules/fresh/index.js +++ b/node_modules/fresh/index.js @@ -30,108 +30,123 @@ module.exports = fresh * @public */ +// 判断缓存中的资源是否新鲜的函数,接收请求头和响应头作为参数 function fresh (reqHeaders, resHeaders) { - // fields - var modifiedSince = reqHeaders['if-modified-since'] - var noneMatch = reqHeaders['if-none-match'] + // 从请求头中获取 if-modified-since 字段的值,用于后续判断资源是否有修改 + var modifiedSince = reqHeaders['if-modified-since']; + // 从请求头中获取 if-none-match 字段的值,用于基于实体标签(ETag)验证资源是否变化 + var noneMatch = reqHeaders['if-none-match']; // unconditional request - if (!modifiedSince && !noneMatch) { - return false + // 如果 if-modified-since 和 if-none-match 字段都不存在,说明是无条件请求,直接返回 false,表示资源不是新鲜的,需重新获取资源 + if (!modifiedSince &&!noneMatch) { + return false; } // Always return stale when Cache-Control: no-cache // to support end-to-end reload requests // https://tools.ietf.org/html/rfc2616#section-14.9.4 - var cacheControl = reqHeaders['cache-control'] + // 从请求头中获取 cache-control 字段的值,用于判断是否有 no-cache 指令 + var cacheControl = reqHeaders['cache-control']; + // 如果 cache-control 字段存在且匹配表示 no-cache 的正则表达式(这里假设 CACHE_CONTROL_NO_CACHE_REGEXP 在外部已定义好),则返回 false,意味着要忽略缓存,重新获取资源,遵循相关网络协议标准 if (cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)) { - return false + return false; } // if-none-match - if (noneMatch && noneMatch !== '*') { - var etag = resHeaders['etag'] + // 如果 if-none-match 字段存在且不等于通配符 *,则进行基于 ETag 的验证 + if (noneMatch && noneMatch!== '*') { + // 从响应头中获取 etag(实体标签)的值,用于和请求头中的 if-none-match 进行匹配对比 + var etag = resHeaders['etag']; + // 如果响应头中没有 etag,则返回 false,即资源不是新鲜的 if (!etag) { - return false + return false; } - var etagStale = true - var matches = parseTokenList(noneMatch) + // 先假设基于 ETag 的验证是不通过的(资源是陈旧的),后续通过循环对比来更新这个状态 + var etagStale = true; + // 调用 parseTokenList 函数解析 if-none-match 字段的值为一个令牌列表,方便后续逐个对比 + var matches = parseTokenList(noneMatch); for (var i = 0; i < matches.length; i++) { - var match = matches[i] + var match = matches[i]; + // 将列表中的每个值与 etag 进行比较(考虑了弱验证等不同格式匹配情况,如 W/ 开头的弱验证格式),只要有匹配的就将 etagStale 设为 false,表示资源是新鲜的(基于 ETag 验证通过) if (match === etag || match === 'W/' + etag || 'W/' + match === etag) { - etagStale = false - break + etagStale = false; + break; } } + // 如果经过遍历对比后,基于 ETag 的验证还是不通过(etagStale 为 true),则返回 false,即资源不是新鲜的 if (etagStale) { - return false + return false; } } // if-modified-since + // 如果 if-modified-since 字段存在,则进行基于资源最后修改时间的验证 if (modifiedSince) { - var lastModified = resHeaders['last-modified'] - var modifiedStale = !lastModified || !(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince)) + // 从响应头中获取 last-modified(资源最后修改时间)的值 + var lastModified = resHeaders['last-modified']; + // 判断资源是否陈旧(modifiedStale),如果 lastModified 不存在或者通过 parseHttpDate 函数解析后的 lastModified 时间大于 modifiedSince 时间(即资源在 if-modified-since 所指定的时间之后有修改),就认为资源是陈旧的(modifiedStale 为 true) + var modifiedStale =!lastModified ||!(parseHttpDate(lastModified) <= parseHttpDate(modifiedSince)); + // 如果资源是陈旧的(modifiedStale 为 true),则返回 false,即资源不是新鲜的 if (modifiedStale) { - return false + return false; } } - return true + // 如果经过前面所有的验证条件都通过了,最后返回 true,表示资源是新鲜的,可以使用缓存 + return true; } -/** - * Parse an HTTP Date into a number. - * - * @param {string} date - * @private - */ - +// Parse an HTTP Date into a number. +// 将一个 HTTP 日期格式的字符串解析为时间戳(数字形式),该函数是私有函数(可能只在内部使用) function parseHttpDate (date) { - var timestamp = date && Date.parse(date) + // 尝试使用 Date.parse 方法解析传入的日期字符串,将解析结果赋给 timestamp 变量 + var timestamp = date && Date.parse(date); // istanbul ignore next: guard against date.js Date.parse patching + // 通过条件判断,如果 timestamp 的类型是 number,就返回该时间戳,否则返回 NaN,处理 Date.parse 可能出现的解析失败情况,同时告诉测试框架(如 Istanbul)忽略下面这行代码的覆盖情况(可能因外部对 Date.parse 修改等特殊情况不好测试) return typeof timestamp === 'number' - ? timestamp - : NaN + ? timestamp + : NaN; } -/** - * Parse a HTTP token list. - * - * @param {string} str - * @private - */ - +// Parse a HTTP token list. +// 解析一个类似 HTTP 令牌列表格式的字符串,该函数是私有函数(可能只在内部使用) function parseTokenList (str) { - var end = 0 - var list = [] - var start = 0 + var end = 0; + var list = []; + var start = 0; // gather tokens + // 遍历字符串中的每个字符,根据字符的编码来判断如何划分令牌(token) for (var i = 0, len = str.length; i < len; i++) { switch (str.charCodeAt(i)) { case 0x20: /* */ + // 如果字符编码是空格(0x20),且当前开始位置和结束位置相同(说明连续的空格开头情况),就更新开始和结束位置为下一个字符位置 if (start === end) { - start = end = i + 1 + start = end = i + 1; } - break - case 0x2c: /* , */ - list.push(str.substring(start, end)) - start = end = i + 1 - break + break; + case 0x2c: /*, */ + // 如果字符编码是逗号(0x2c),就将从 start 到 end 位置的子字符串作为一个令牌添加到 list 数组中,并更新 start 和 end 位置为下一个字符位置 + list.push(str.substring(start, end)); + start = end = i + 1; + break; default: - end = i + 1 - break + // 对于其他字符情况,就更新 end 位置到下一个字符 + end = i + 1; + break; } } // final token - list.push(str.substring(start, end)) + // 将最后一个划分出来的令牌(从 start 到 end 位置的子字符串)添加到 list 数组中 + list.push(str.substring(start, end)); - return list + // 返回解析好的令牌列表数组,用于后续对类似 if-none-match 等字段值的进一步处理 + return list; } diff --git a/node_modules/merge-descriptors/index.js b/node_modules/merge-descriptors/index.js index 573b132..5caa94d 100644 --- a/node_modules/merge-descriptors/index.js +++ b/node_modules/merge-descriptors/index.js @@ -32,29 +32,37 @@ var hasOwnProperty = Object.prototype.hasOwnProperty */ function merge(dest, src, redefine) { + // 检查目标对象(dest)是否存在,如果不存在则抛出类型错误,表明目标对象参数是必需的 if (!dest) { - throw new TypeError('argument dest is required') + throw new TypeError('argument dest is required'); } + // 检查源对象(src)是否存在,如果不存在则抛出类型错误,表明源对象参数是必需的 if (!src) { - throw new TypeError('argument src is required') + throw new TypeError('argument src is required'); } + // 如果redefine参数未被传入(即值为undefined),则将其默认设置为true if (redefine === undefined) { // Default to true - redefine = true + redefine = true; } + // 遍历源对象(src)自身的所有可枚举属性名(不包括继承属性) Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName(name) { + // 如果redefine为false,并且目标对象(dest)已经拥有当前遍历到的属性名对应的属性 + // 那么跳过该属性的处理,直接进入下一次循环 if (!redefine && hasOwnProperty.call(dest, name)) { // Skip desriptor - return + return; } - // Copy descriptor - var descriptor = Object.getOwnPropertyDescriptor(src, name) - Object.defineProperty(dest, name, descriptor) - }) + // 获取源对象(src)中当前属性名对应的属性描述符(包括属性值、可写性、可枚举性、可配置性等信息) + var descriptor = Object.getOwnPropertyDescriptor(src, name); + // 使用获取到的属性描述符,在目标对象(dest)上定义同名属性,实现将源对象的属性复制到目标对象上 + Object.defineProperty(dest, name, descriptor); + }); - return dest -} + // 返回合并后的目标对象(dest),此时它已经包含了从源对象复制过来的属性(根据redefine规则) + return dest; +} \ No newline at end of file