美文网首页
Node.js 应用开发规约

Node.js 应用开发规约

作者: 勇往直前888 | 来源:发表于2018-05-11 11:27 被阅读46次

Best Practise

数组如下方法的 callback 中强制要求 return 声明

数组有很多用于 filtering/mapping/folding 的方法,如果在这些方法的 callback 函数中没有 return,通常会导致程序出错
Array.from
Array.prototype.every
Array.prototype.filter
Array.prototype.find
Array.prototype.findIndex
Array.prototype.map
Array.prototype.reduce
Array.prototype.reduceRight
Array.prototype.some
Array.prototype.sort

// Bad
var indexMap = myArray.reduce(function(memo, item, index) {
    memo[item] = index;
}, {});

var foo = Array.from(nodes, function(node) {
    if (node.tagName === "DIV") {
        return true;
    }
});

var bar = foo.filter(function(x) {
    if (x) {
        return true;
    } else {
        return;
    }
});

// Good
var indexMap = myArray.reduce(function(memo, item, index) {
    memo[item] = index;
    return memo;
}, {});

var foo = Array.from(nodes, function(node) {
    if (node.tagName === "DIV") {
        return true;
    }
    return false;
});

var bar = foo.map(node => node.getAttribute("id"));

var 声明的变量,避免在声明其的块级作用域外部使用

// Bad
function doIf() {
    if (true) {
        var build = true;
    }

    console.log(build);
}

function doIfElse() {
    if (true) {
        var build = true;
    } else {
        var build = false;
    }
}

function doTryCatch() {
    try {
        var build = 1;
    } catch (e) {
        var f = build;
    }
}

// Good
function doIf() {
    var build;

    if (true) {
        build = true;
    }

    console.log(build);
}

function doIfElse() {
    var build;

    if (true) {
        build = true;
    } else {
        build = false;
    }
}

function doTryCatch() {
    var build;
    var f;

    try {
        build = 1;
    } catch (e) {
        f = build;
    }
}

花括号使用规约

允许无括号的单行 if、else if、else、for、while、do,其他的表达式强制使用花括号

// Bad
if (foo)
  doSomething();
else
  doSomethingElse();

if (foo) foo(
  bar,
  baz);

// Good
if (foo) foo++; else doSomething();

if (foo) foo++;
else if (bar) baz()
else doSomething();

do something();
while (foo);

while (foo
  && bar) baz();

if (foo) {
    foo++;
}

if (foo) { foo++; }

while (true) {
    doSomething();
    doSomethingElse();
}

Switch 表达式中强制要求 default 声明

// Bad
switch (a) {
    case 1:
        /* code */
        break;
}

// Good
switch (a) {
    case 1:
        /* code */
        break;

    default:
        /* code */
        break;
}

switch (a) {
    case 1:
        /* code */
        break;

    // no default
}

尽可能使用 . 获取属性

// Bad
var x = foo["bar"];

// Good
var x = foo.bar;

var x = foo[bar];    // Property name is a variable, square-bracket notation required

var x = foo['class']; // 保留的关键字

使用 === 或 !== 取代 == 或 !=

// Bad
a == b
foo == true
bananas != 1
value == undefined
typeof foo == 'undefined'
'hello' != 'world'
0 == 0
true == true
foo == null

// Good
a === b
foo === true
bananas !== 1
value === undefined
typeof foo === 'undefined'
'hello' !== 'world'
0 === 0
true === true
foo === null

禁止使用 alert

// Bad
alert("here!");

confirm("Are you sure?");

prompt("What's your name?", "John Doe");

// Good
customAlert("Something happened!");

customConfirm("Are you sure?");

customPrompt("Who are you?");

function foo() {
    var alert = myCustomLib.customAlert;
    alert();
}

禁止使用 caller/callee

// Bad
function foo(n) {
    if (n <= 0) {
        return;
    }

    arguments.callee(n - 1);
}

[1,2,3,4,5].map(function(n) {
    return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});

// Good
function foo(n) {
    if (n <= 0) {
        return;
    }

    foo(n - 1);
}

[1,2,3,4,5].map(function factorial(n) {
    return !(n > 1) ? 1 : factorial(n - 1) * n;
});

Switch case/default 中禁止在非块级作用域中声明

声明语法包括:let、const、function、class,不允许在 case/default 中使用,除非 case/default 使用花括号产生了块级作用域

// Bad
switch (foo) {
    case 1:
        let x = 1;
        break;
    case 2:
        const y = 2;
        break;
    case 3:
        function f() {}
        break;
    default:
        class C {}
}

// Good
switch (foo) {
    case 1: {
        let x = 1;
        break;
    }
    case 2: {
        const y = 2;
        break;
    }
    case 3: {
        function f() {}
        break;
    }
    default: {
        class C {}
    }
}

else 表达式之前禁止 return

// Bad

function foo() {
    if (x) {
        return y;
    } else {
        return z;
    }
}

function foo() {
    if (x) {
        return y;
    } else if (z) {
        return w;
    } else {
        return t;
    }
}

function foo() {
    if (x) {
        return y;
    } else {
        var t = "foo";
    }

    return t;
}

// Two warnings for nested occurrences
function foo() {
    if (x) {
        if (y) {
            return y;
        } else {
            return x;
        }
    } else {
        return z;
    }
}

// Good

function foo() {
    if (x) {
        return y;
    }

    return z;
}

function foo() {
    if (x) {
        return y;
    } else if (z) {
        var t = "foo";
    } else {
        return w;
    }
}

function foo() {
    if (x) {
        if (z) {
            return y;
        }
    } else {
        return z;
    }
}

关于空函数

以下语法式允许的:

  • arrowFunctions
const foo = () => {};
  • functions
function foo() {}

const foo = function() {};

const obj = {
  foo: function() {}
};
  • methods
const obj = {
  foo() {}
};

class A {
  foo() {}

  static foo() {}
}

以下语法是不允许的:

  • generatorFunctions
function* foo() {}
const foo = function*() {};
  • generaotrMethods
const obj = {
  foo: function*() {},
  *foo() {},
};
  • getters/setters
const obj = {
  get foo() {},
  set foo(value) {},
};
  • constructors
class A {
  construtor() {}
}
  • mixed
const obj = {
  bar: 123,
  foo: () => this.bar,
  *foo() {},
};

禁止无意义的解构赋值

const {} = foo;
const [] = foo;
const {a: {}} = foo;
const {a: []} = foo;
function foo({}) {}
function foo([]) {}
function foo({a: {}}) {}
function foo({a: []}) {}

禁止使用 eval 表达式

eval 表达式存在安全隐患,也会让应用变得容易受攻击

禁止直接修改内建对象的 prototype 属性

// Bad
Object.prototype.a = "a";
Object.defineProperty(Array.prototype, "times", { value: 999 });

禁止在不使用 this 的情况下使用 bind

bind 方法用于改变函数的 this 对象,如果使用了 bind 方法,但是在函数中又没有使用 this,则认定为无效的 bind

// Bad
var x = function () {
    foo();
}.bind(bar);

禁止无嵌套循环结构下的 label 标识位

// Bad
A: while (a) {
    break A;
}

Switch case 中使用 break/throw 等中断循环结构

// Bad
switch(foo) {
    case 1:
        doSomething();

    case 2:
        doSomething();
}

// Good
switch(foo) {
    case 1:
        doSomething();
        break;

    case 2:
        doSomething();
}

switch(foo) {
    case 1:
        doSomething();
        throw new Error("Boo!");

    case 2:
        doSomething();
}

浮点数表示

以下为错误的浮点数表示方式:

var num = .5;
var num = 2.;
var num = -.7;

以下为正确的浮点数表示方式:

var num = 0.5;
var num = 2.0;
var num = -0.7;

使用函数作为 setTimeout、setInterval、execScript 等语句的参数,而不是使用字符串

// Bad
setTimeout("alert('Hi!');", 100);

setInterval("alert('Hi!');", 100);

execScript("alert('Hi!')");

window.setTimeout("count = 5", 10);

window.setInterval("foo = bar", 10);

// Good
setTimeout(function() {
    alert("Hi!");
}, 100);

setInterval(function() {
    alert("Hi!");
}, 100);

禁止使用 label 结合 break、continue 来控制多层循环

禁止使用非必要的块级作用域

// Bad
{}

if (foo) {
    bar();
    {
        baz();
    }
}

function bar() {
    {
        baz();
    }
}

{
    function foo() {}
}

{
    aLabel: {
    }
}

// Good
while (foo) {
    bar();
}

if (foo) {
    if (bar) {
        baz();
    }
}

function bar() {
    baz();
}

{
    let x = 1;
}

{
    const y = 1;
}

{
    class Foo {}
}

aLabel: {
}

禁止在循环体中声明函数

循环体中声明的函数形成闭包,容易造成程序运行结果超出预期

// Bad
for (var i=10; i; i--) {
    (function() { return i; })();
}

while(i) {
    var a = function() { return i; };
    a();
}

do {
    function a() { return i; };
    a();
} while (i);

let foo = 0;
for (let i=10; i; i--) {
    // Bad, function is referencing block scoped variable in the outer scope.
    var a = function() { return foo; };
    a();
}

// Good
var a = function() {};

for (var i=10; i; i--) {
    a();
}

for (var i=10; i; i--) {
    a();
}

for (var i=10; i; i--) {
    var a = function() {}; // OK, no references to variables in the outer scopes.
    a();
}

for (let i=10; i; i--) {
    var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
    a();
}

var foo = 100;
for (let i=10; i; i--) {
    var a = function() { return foo; }; // OK, all references are referring to never modified variables.
    a();
}

禁止多余的空格

// Bad
var a =  1;

if(foo   === "bar") {}

a <<  b

var arr = [1,  2];

a ?  b: c

// Good
var a = 1;

if(foo === "bar") {}

a << b

var arr = [1, 2];

a ? b: c

禁止多行形式的字符串

// Bad
var x = "Line 1 \
         Line 2";

// Good
var x = "Line 1\n" +
        "Line 2";

禁止重新声明内置对象

// Bad
Object = null
undefined = 1

禁止使用函数构造器 new Function

// Bad
var x = new Function("a", "b", "return a + b");

禁止使用构造器的方式创建原始类型:string、number、boolean

使用构造器的方式创建原始数据类型,会造成使用困扰,如下示例:

var stringObject = new String("Hello world");
console.log(typeof stringObject);       // "object"

var text = "Hello world";
console.log(typeof text);               // "string"

var booleanObject = new Boolean(false);
if (booleanObject) {    // all objects are truthy!
    console.log("This executes");
}

因此,禁止使用构造器的方式创建以上原始数据类型

禁止使用八进制字面量

八进制的方式表示的字面量,由于以 0 开头,容易造成 Javascript 运行混乱,不建议使用八进制字面量

// Bad
var num = 071;
var result = 5 + 07;

// Good
var num  = "071";

禁止使用字符串的八进制转义序列,应该使用 Unicode 转义序列替代

// Bad
var foo = "Copyright \251";

// Good
var foo = "Copyright \u00A9";   // unicode

禁止使用 proto

ECMAScript 3.1 标准中已经废弃了该属性,请使用 getPrototypeOf() 方法替代

// Bad
var a = obj.__proto__;

var a = obj["__proto__"];

// Good
var a = Object.getPrototypeOf(obj);

禁止重复声明变量

// Bad
var a = 3;
var a = 10;

// Good
var a = 3;
a = 10;

禁止在 return 表达式中使用赋值运算符

// Bad
function doSomething() {
    return foo = bar + 2;
}

function doSomething() {
    return foo += 2;
}

// Good
function doSomething() {
    return foo == bar + 2;
}

function doSomething() {
    return foo === bar + 2;
}

function doSomething() {
    return (foo = bar + 2);
}

禁止使用 javascript: 表达式

// Bad
location.href = "javascript:void(0)";

禁止自赋值

// Bad
foo = foo;

[a, b] = [a, b];

[a, ...b] = [x, ...b];

({a, b} = {a, x});

// Good
foo = bar;
[a, b] = [b, a];

// This pattern is warned by the `no-use-before-define` rule.
let foo = foo;

// The default values have an effect.
[foo = 1] = [foo];

禁止自比较

// Bad
var x = 10;
if (x === x) {
    x = 20;
}

禁止使用逗号操作符

// Bad
foo = doSomething(), val;

0, eval("doSomething();");

do {} while (doSomething(), !!test);

for (; doSomething(), !!test; );

if (doSomething(), !!test);

switch (val = foo(), val) {}

while (val = foo(), val < 42);

with (doSomething(), val) {}

// Good
foo = (doSomething(), val);

(0, eval)("doSomething();");

do {} while ((doSomething(), !!test));

for (i = 0, j = 10; i < j; i++, j--);

if ((doSomething(), !!test));

switch ((val = foo(), val)) {}

while ((val = foo(), val < 42));

禁止使用未被使用的 label

// Bad
A: var foo = 0;

B: {
    foo();
}

C:
for (let i = 0; i < 10; ++i) {
    foo();
}

// Good
A: {
    if (foo()) {
        break A;
    }
    bar();
}

B:
for (let i = 0; i < 10; ++i) {
    if (foo()) {
        break B;
    }
    bar();
}

禁止不必要的字符串链接操作

// Bad
var a = `some` + `string`;
var a = '1' + '0';
var a = '1' + `0`;
var a = `1` + '0';
var a = `1` + `0`;

// Good
var c = a + b;
var c = '1' + a;
var a = 1 + '1';
var c = 1 - 2;
// when the string concatenation is multiline
var c = "foo" +
    "bar";

禁止使用 with 表达式

// Bad
with (point) {
    r = Math.sqrt(x * x + y * y); // is r a member of point?
}

// Good
const r = ({x, y}) => Math.sqrt(x * x + y * y);

禁止 Yoda 表达式

// Bad
if ("red" === color) {
    // ...
}

// Good
if (color === "red") {
    // ...
}

严格模式

只允许全局的方式声明严格模式,即在一个脚本最上面添加:

"use strict";

function foo() {}

变量

禁止使用 delete 操作符删除变量

delete 操作符只建议在删除对象属性的时候使用

// Bad
var x;
delete x;

禁止使用跟同作用域下的变量名一样的 label 名

// Bad
var x = foo;
function bar() {
x:
  for (;;) {
    break x;
  }
}

// Good
function foo() {
  var q = t;
}

function bar() {
q:
  for(;;) {
    break q;
  }
}

禁止将受限制的关键字作为变量名

受限制的关键字,如 NaN、Infinity、undefined、eval、arguments 等

// Bad
function NaN(){}

!function(Infinity){};

var undefined;

try {} catch(eval){}

// Good
var Object;

function f(a, b){}

禁止使用未声明的变量

// Bad
var a = someFunction();
b = 10;

// Good
var a = someFunction();
var b;
b = 10;

禁止声明未使用的变量

禁止先使用、后声明的方式使用变量

Error

尾随逗号

建议在多行情况下,永远在最后一个元素或属性后面添加逗号;单行情况下不需要在最后一行添加逗号;

// Bad

var foo = {
    bar: "baz",
    qux: "quux"
};

var foo = { bar: "baz", qux: "quux", };

var arr = [1,2,];

var arr = [1,
    2,];

var arr = [
    1,
    2
];

foo({
  bar: "baz",
  qux: "quux"
});

// Good

var foo = {
    bar: "baz",
    qux: "quux",
};

var foo = {bar: "baz", qux: "quux"};
var arr = [1,2];

var arr = [1,
    2];

var arr = [
    1,
    2,
];

foo({
  bar: "baz",
  qux: "quux",
});

禁止在判断条件中使用赋值语句

如果条件表达式中需要使用赋值语句,请使用 () 将赋值语句包裹起来

// Bad
function setHeight(someNode) {
     do {
         someNode.height = "100px";
     } while (someNode = someNode.parentNode);
}

// Good
function setHeight(someNode) {
     do {
         someNode.height = "100px";
     } while ((someNode = someNode.parentNode));
}

禁止在判断条件中使用常量表达式

// Bad
if (false) {
    doSomethingUnfinished();
}

if (void x) {
    doSomethingUnfinished();
}

for (;-2;) {
    doSomethingForever();
}

while (typeof x) {
    doSomethingForever();
}

do {
    doSomethingForever();
} while (x = -1);

var result = 0 ? a : b;

// Good
if (x === 0) {
    doSomething();
}

for (;;) {
    doSomethingForever();
}

while (typeof x === "undefined") {
    doSomething();
}

do {
    doSomething();
} while (x);

var result = x !== 0 ? a : b;

线上代码禁止使用 debugger

禁止在函数形参中重复声明变量

// Bad
function foo(a, b, a) {
    console.log("value of the second a:", a);
}

var bar = function (a, b, a) {
    console.log("value of the second a:", a);
};

// Good
function foo(a, b, c) {
    console.log(a, b, c);
}

var bar = function (a, b, c) {
    console.log(a, b, c);
};

禁止在对象字面量中添加相同的 key

// Bad
var foo = {
    bar: "baz",
    bar: "qux"
};

var foo = {
    "bar": "baz",
    bar: "qux"
};

var foo = {
    0x1: "baz",
    1: "qux"
};

// Good
var foo = {
    bar: "baz",
    quxx: "qux"
};

禁止存在相同的 case 表达式

// Bad
var a = 1,
    one = 1;

switch (a) {
    case 1:
        break;
    case 2:
        break;
    case 1:         // duplicate test expression
        break;
    default:
        break;
}

switch (a) {
    case one:
        break;
    case 2:
        break;
    case one:         // duplicate test expression
        break;
    default:
        break;
}

switch (a) {
    case "1":
        break;
    case "2":
        break;
    case "1":         // duplicate test expression
        break;
    default:
        break;
}

// Good
var a = 1,
    one = 1;

switch (a) {
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    default:
        break;
}

switch (a) {
    case one:
        break;
    case 2:
        break;
    case 3:
        break;
    default:
        break;
}

switch (a) {
    case "1":
        break;
    case "2":
        break;
    case "3":
        break;
    default:
        break;
}

禁止空快语句

// Bad
if (foo) {
}

while (foo) {
}

switch(foo) {
}

try {
    doSomething();
} catch(ex) {

} finally {

}

// Good
if (foo) {
    // empty
}

while (foo) {
    /* empty */
}

try {
    doSomething();
} catch (ex) {
    // continue regardless of error
}

try {
    doSomething();
} finally {
    /* continue regardless of error */
}

正则表达式中禁止存在空的字符类

// Bad
/^abc[]/.test("abcdefg"); // false
"abcdefg".match(/^abc[]/); // null

// Good
/^abc/.test("abcdefg"); // true
"abcdefg".match(/^abc/); // ["abc"]

/^abc[a-z]/.test("abcdefg"); // true
"abcdefg".match(/^abc[a-z]/); // ["abcd"]

禁止在 catch 中重新声明异常形参

// Bad
try {
    // code
} catch (e) {
    e = 10;
}

// Good
try {
    // code
} catch (e) {
    var foo = 10;
}

禁止不必要的 boolean 类型转换

// Bad
var foo = !!!bar;

var foo = !!bar ? baz : bat;

var foo = Boolean(!!bar);

var foo = new Boolean(!!bar);

if (!!foo) {
    // ...
}

if (Boolean(foo)) {
    // ...
}

while (!!foo) {
    // ...
}

do {
    // ...
} while (Boolean(foo));

for (; !!foo; ) {
    // ...
}

// Good
var foo = !!bar;
var foo = Boolean(bar);

function foo() {
    return !!bar;
}

var foo = bar ? !!baz : !!bat;

禁止使用不必要的括号

// Bad
a = (b * c);

(a * b) + c;

typeof (a);

(function(){} ? a() : b());

// Good
(0).toString();

({}.toString.call());

(function(){}) ? a() : b();

(/^a$/).test(x);

禁止使用不必要的分号

// Bad

var x = 5;;

function foo() {
    // code
};

// Good

var x = 5;

var foo = function() {
    // code
};

禁止给声明好的函数重新赋值

// Bad

function foo() {}
foo = bar;

function foo() {
    foo = bar;
}

// Good

var foo = function () {}
foo = bar;

function foo(foo) { // `foo` is shadowed.
    foo = bar;
}

function foo() {
    var foo = bar;  // `foo` is shadowed.
}

禁止在嵌套的块级作用域中声明函数

// Bad

if (test) {
    function doSomething() { }
}

function doSomethingElse() {
    if (test) {
        function doAnotherThing() { }
    }
}

// Good

function doSomething() { }

function doSomethingElse() {
    function doAnotherThing() { }
}

if (test) {
    asyncCall(id, function (err, data) { });
}

var fn;
if (test) {
    fn = function fnExpression() { };
}

禁止在正则表达式中存在非法的表达式

// Bad

RegExp('[')

RegExp('.', 'z')

new RegExp('\\')

// Good

RegExp('.')

new RegExp

this.RegExp('[')

禁止存在不规则的空白符

由于操作失误引入的不规则空白符,由于无法通过肉眼觉察,很容易引起程序运行出错

// Bad

function thing() /*<NBSP>*/{
    return 'test';
}

function thing( /*<NBSP>*/){
    return 'test';
}

function thing /*<NBSP>*/(){
    return 'test';
}

function thing᠎/*<MVS>*/(){
    return 'test';
}

function thing() {
    return 'test'; /*<ENSP>*/
}

function thing() {
    return 'test'; /*<NBSP>*/
}

function thing() {
    // Description <NBSP>: some descriptive text
}

/*
Description <NBSP>: some descriptive text
*/

function thing() {
    return / <NBSP>regexp/;
}

/*eslint-env es6*/
function thing() {
    return `template <NBSP>string`;
}

// Good

function thing() {
    return ' <NBSP>thing';
}

function thing() {
    return '​<ZWSP>thing';
}

function thing() {
    return 'th <NBSP>ing';
}

禁止在判断条件中的左操作符中做取反操作

// Bad

if(!key in object) {
    // operator precedence makes it equivalent to (!key) in object
    // and type conversion makes it equivalent to (key ? "false" : "true") in object
}

// Good

if(!(key in object)) {
    // key is not in object
}

if(('' + !key) in object) {
    // make operator precedence and type conversion explicit
    // in a rare situation when that is the intended meaning
}

禁止用函数的方式调用全局对象

// Bad

var math = Math();
var json = JSON();

// Good

function area(r) {
    return Math.PI * r * r;
}
var object = JSON.parse("{}");

禁止在正则表达式中存在多个空格

// Bad

var re = /foo   bar/;
var re = new RegExp("foo   bar");

// Good

var re = /foo {3}bar/;
var re = new RegExp("foo {3}bar");

禁止在数组中使用空元素

// Bad

var items = [,];
var colors = [ "red",, "blue" ];

// Good

var items = [];
var items = new Array(23);

// trailing comma (after the last element) is not a problem
var colors = [ "red", "blue", ];

禁止在 return、throw、continue、break 之后插入没有机会运行的代码

// Bad

function foo() {
    return true;
    console.log("done");
}

function bar() {
    throw new Error("Oops!");
    console.log("done");
}

while(value) {
    break;
    console.log("done");
}

throw new Error("Oops!");
console.log("done");

function baz() {
    if (Math.random() < 0.5) {
        return;
    } else {
        throw new Error();
    }
    console.log("done");
}

for (;;) {}
console.log("done");

// Good

function foo() {
    return bar();
    function bar() {
        return 1;
    }
}

function bar() {
    return x;
    var x;
}

switch (foo) {
    case 1:
        break;
        var x;
}

禁止在 finally 中存在流程控制语句

finally 一般作为 try catch 之后执行的一段代码,不应该在 finally 中插入干扰 try catch 流程的代码,比如:return、throw、break、continue 等

// Bad

let foo = function() {
    try {
        return 1;
    } catch(err) {
        return 2;
    } finally {
        return 3;
    }
};

let foo = function() {
    try {
        return 1;
    } catch(err) {
        return 2;
    } finally {
        throw new Error;
    }
};

// Good

let foo = function() {
    try {
        return 1;
    } catch(err) {
        return 2;
    } finally {
        console.log("hola!");
    }
};

let foo = function() {
    try {
        return 1;
    } catch(err) {
        return 2;
    } finally {
        let a = function() {
            return "hola!";
        }
    }
};

let foo = function(a) {
    try {
        return 1;
    } catch(err) {
        return 2;
    } finally {
        switch(a) {
            case 1: {
                console.log("hola!")
                break;
            }
        }
    }
};

请使用 isNaN() 方法来检查一个值是否是 NaN

// Bad

if (foo == NaN) {
    // ...
}

if (foo != NaN) {
    // ...
}

// Good

if (isNaN(foo)) {
    // ...
}

if (!isNaN(foo)) {
    // ...
}

相关文章

网友评论

      本文标题:Node.js 应用开发规约

      本文链接:https://www.haomeiwen.com/subject/ayaxdftx.html