diff --git "a/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.docx" "b/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.docx" deleted file mode 100644 index 39865df..0000000 Binary files "a/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.docx" and /dev/null differ diff --git "a/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.docx" "b/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.docx" deleted file mode 100644 index 5863683..0000000 Binary files "a/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.docx" and /dev/null differ diff --git a/README.md b/README.md index dfb5150..9fa306b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,38 @@ -# studyFiles -һЩNodeJSǰ˵ѧϰʼǣKoa+MongoDB+MySQL+JavaScript+Bootstrap+React+jQueryȵ \ No newline at end of file +# 资源分享 + +一些NodeJS和前端的学习笔记 + +一些经典且高质量的电子书 + +一些逗比的生活感悟 + +一些脑残的成长的经历 + + +剧集/电影/电子书等寻找请邮件联系[threerocks](196887298@qq.com) +技术交流请联系[threerocks](196887298@qq.com) + +2016/11/24 100star + +
+*此目录均为原创文章* + +*转载请注明:* + +*转载自:https://github.com/threerocks* + +
+ GitHub +
+
+ 主页 +
+
+ CNode +
+
+ 简书 +
+ + + diff --git a/git.txt b/git.txt deleted file mode 100644 index b8a49bf..0000000 --- a/git.txt +++ /dev/null @@ -1,10 +0,0 @@ -Create a new repository on the command line -touch README.md -git init -git add README.md -git commit -m "first commit" -git remote add origin git@github.com:teamtogether/TestProject.git -git push -u origin master -Push an existing repository from the command line -git remote add origin git@github.com:teamtogether/TestProject.git -git push -u origin master \ No newline at end of file diff --git "a/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.docx" "b/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.docx" deleted file mode 100644 index ffd3e66..0000000 Binary files "a/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.docx" and /dev/null differ diff --git a/nodejs+phantomjs+nodemailer.docx b/nodejs+phantomjs+nodemailer.docx deleted file mode 100644 index 2253a48..0000000 Binary files a/nodejs+phantomjs+nodemailer.docx and /dev/null differ diff --git "a/package\347\256\241\347\220\206.docx" "b/package\347\256\241\347\220\206.docx" deleted file mode 100644 index 96ef231..0000000 Binary files "a/package\347\256\241\347\220\206.docx" and /dev/null differ diff --git "a/~$\346\227\245\350\256\26020160125.docx" "b/~$\346\227\245\350\256\26020160125.docx" deleted file mode 100644 index 03e6a50..0000000 Binary files "a/~$\346\227\245\350\256\26020160125.docx" and /dev/null differ diff --git "a/~$\346\227\245\350\256\26020160202.docx" "b/~$\346\227\245\350\256\26020160202.docx" deleted file mode 100644 index 4e117f4..0000000 Binary files "a/~$\346\227\245\350\256\26020160202.docx" and /dev/null differ diff --git a/~WRL2776.tmp b/~WRL2776.tmp deleted file mode 100644 index f16aca4..0000000 Binary files a/~WRL2776.tmp and /dev/null differ diff --git "a/Koa\346\212\200\346\234\257\345\210\206\344\272\253.pptx" "b/\346\212\200\346\234\257\345\210\206\344\272\253ppt/Koa\346\212\200\346\234\257\345\210\206\344\272\253.pptx" similarity index 100% rename from "Koa\346\212\200\346\234\257\345\210\206\344\272\253.pptx" rename to "\346\212\200\346\234\257\345\210\206\344\272\253ppt/Koa\346\212\200\346\234\257\345\210\206\344\272\253.pptx" diff --git "a/\347\224\265\345\255\220\344\271\246/CSS3\345\261\236\346\200\247\351\200\237\346\237\245\350\241\250.pdf" "b/\347\224\265\345\255\220\344\271\246/CSS3\345\261\236\346\200\247\351\200\237\346\237\245\350\241\250.pdf" new file mode 100644 index 0000000..60066e8 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/CSS3\345\261\236\346\200\247\351\200\237\346\237\245\350\241\250.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/GitHub\345\205\245\351\227\250\344\270\216\345\256\236\350\267\265.pdf" "b/\347\224\265\345\255\220\344\271\246/GitHub\345\205\245\351\227\250\344\270\216\345\256\236\350\267\265.pdf" new file mode 100644 index 0000000..5229b5b Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/GitHub\345\205\245\351\227\250\344\270\216\345\256\236\350\267\265.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\345\237\272\347\241\200\346\225\231\347\250\213\357\274\210\347\254\2548\347\211\210\357\274\211\344\270\255\346\226\207\351\253\230\346\270\205\347\211\210.pdf" "b/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\345\237\272\347\241\200\346\225\231\347\250\213\357\274\210\347\254\2548\347\211\210\357\274\211\344\270\255\346\226\207\351\253\230\346\270\205\347\211\210.pdf" new file mode 100755 index 0000000..adeed75 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\345\237\272\347\241\200\346\225\231\347\250\213\357\274\210\347\254\2548\347\211\210\357\274\211\344\270\255\346\226\207\351\253\230\346\270\205\347\211\210.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\346\235\203\345\250\201\346\214\207\345\215\227\347\254\254\344\272\214\347\211\210.pdf" "b/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\346\235\203\345\250\201\346\214\207\345\215\227\347\254\254\344\272\214\347\211\210.pdf" new file mode 100644 index 0000000..904fd9c Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTML5\344\270\216CSS3\346\235\203\345\250\201\346\214\207\345\215\227\347\254\254\344\272\214\347\211\210.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTML5\346\240\207\347\255\276\345\210\227\350\241\250.pdf" "b/\347\224\265\345\255\220\344\271\246/HTML5\346\240\207\347\255\276\345\210\227\350\241\250.pdf" new file mode 100644 index 0000000..c3ee2ec Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTML5\346\240\207\347\255\276\345\210\227\350\241\250.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\344\270\255\346\226\207\347\211\210.pdf" "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\344\270\255\346\226\207\347\211\210.pdf" new file mode 100644 index 0000000..e46e963 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\344\270\255\346\226\207\347\211\210.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\345\210\206\346\236\220.pdf" "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\345\210\206\346\236\220.pdf" new file mode 100644 index 0000000..7a05508 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\345\210\206\346\236\220.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\350\257\246\350\247\243.pdf" "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\350\257\246\350\247\243.pdf" new file mode 100644 index 0000000..5891d04 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/HTTP\345\215\217\350\256\256\350\257\246\350\247\243.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271[\344\277\256\350\256\242\347\211\210].pdf" "b/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271[\344\277\256\350\256\242\347\211\210].pdf" new file mode 100644 index 0000000..581e410 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271[\344\277\256\350\256\242\347\211\210].pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271_\344\277\256\350\256\242\347\211\210.pdf" "b/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271_\344\277\256\350\256\242\347\211\210.pdf" new file mode 100644 index 0000000..581e410 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/JavaScript\350\257\255\350\250\200\347\262\276\347\262\271_\344\277\256\350\256\242\347\211\210.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/JavaScript\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\346\214\207\345\215\227.pdf" "b/\347\224\265\345\255\220\344\271\246/JavaScript\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\346\214\207\345\215\227.pdf" new file mode 100644 index 0000000..6de62b6 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/JavaScript\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\346\214\207\345\215\227.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/JavaScript\351\253\230\347\272\247\347\250\213\345\272\217\350\256\276\350\256\241\357\274\210\347\254\2543\347\211\210\357\274\211.pdf" "b/\347\224\265\345\255\220\344\271\246/JavaScript\351\253\230\347\272\247\347\250\213\345\272\217\350\256\276\350\256\241\357\274\210\347\254\2543\347\211\210\357\274\211.pdf" new file mode 100644 index 0000000..a0749a1 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/JavaScript\351\253\230\347\272\247\347\250\213\345\272\217\350\256\276\350\256\241\357\274\210\347\254\2543\347\211\210\357\274\211.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/Node.js\345\256\236\346\210\230.pdf" "b/\347\224\265\345\255\220\344\271\246/Node.js\345\256\236\346\210\230.pdf" new file mode 100644 index 0000000..deb52dd Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/Node.js\345\256\236\346\210\230.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/Node.js\345\274\200\345\217\221\346\214\207\345\215\227_\344\270\255\346\226\207\346\255\243\347\211\210.pdf" "b/\347\224\265\345\255\220\344\271\246/Node.js\345\274\200\345\217\221\346\214\207\345\215\227_\344\270\255\346\226\207\346\255\243\347\211\210.pdf" new file mode 100644 index 0000000..a8d206a Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/Node.js\345\274\200\345\217\221\346\214\207\345\215\227_\344\270\255\346\226\207\346\255\243\347\211\210.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/Node\344\270\216Express\345\274\200\345\217\221.pdf" "b/\347\224\265\345\255\220\344\271\246/Node\344\270\216Express\345\274\200\345\217\221.pdf" new file mode 100755 index 0000000..e7d5d19 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/Node\344\270\216Express\345\274\200\345\217\221.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/Node\345\215\263\345\255\246\345\215\263\347\224\250(linuxidc.com).pdf" "b/\347\224\265\345\255\220\344\271\246/Node\345\215\263\345\255\246\345\215\263\347\224\250(linuxidc.com).pdf" new file mode 100644 index 0000000..29a9ee1 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/Node\345\215\263\345\255\246\345\215\263\347\224\250(linuxidc.com).pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/REACT\357\274\232\345\274\225\351\242\206\346\234\252\346\235\245\347\232\204\347\224\250\346\210\267\347\225\214\351\235\242\345\274\200\345\217\221\346\241\206\346\236\266.pdf" "b/\347\224\265\345\255\220\344\271\246/REACT\357\274\232\345\274\225\351\242\206\346\234\252\346\235\245\347\232\204\347\224\250\346\210\267\347\225\214\351\235\242\345\274\200\345\217\221\346\241\206\346\236\266.pdf" new file mode 100644 index 0000000..6d82e8a Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/REACT\357\274\232\345\274\225\351\242\206\346\234\252\346\235\245\347\232\204\347\224\250\346\210\267\347\225\214\351\235\242\345\274\200\345\217\221\346\241\206\346\236\266.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/Web\346\200\247\350\203\275\346\235\203\345\250\201\346\214\207\345\215\227.pdf" "b/\347\224\265\345\255\220\344\271\246/Web\346\200\247\350\203\275\346\235\203\345\250\201\346\214\207\345\215\227.pdf" new file mode 100644 index 0000000..821a9e8 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/Web\346\200\247\350\203\275\346\235\203\345\250\201\346\214\207\345\215\227.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/css\346\217\255\347\247\230.pdf" "b/\347\224\265\345\255\220\344\271\246/css\346\217\255\347\247\230.pdf" new file mode 100644 index 0000000..7f7cd34 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/css\346\217\255\347\247\230.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/javascript-promise-book.pdf" "b/\347\224\265\345\255\220\344\271\246/javascript-promise-book.pdf" new file mode 100644 index 0000000..0b75e48 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/javascript-promise-book.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\343\200\220\345\210\206\344\272\253\343\200\221koa-not-only-generator.pdf" "b/\347\224\265\345\255\220\344\271\246/\343\200\220\345\210\206\344\272\253\343\200\221koa-not-only-generator.pdf" new file mode 100644 index 0000000..0d52da6 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\343\200\220\345\210\206\344\272\253\343\200\221koa-not-only-generator.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\344\270\200\344\270\252\346\234\210\346\202\237\351\200\217JavaScript.pdf" "b/\347\224\265\345\255\220\344\271\246/\344\270\200\344\270\252\346\234\210\346\202\237\351\200\217JavaScript.pdf" new file mode 100644 index 0000000..93fd283 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\344\270\200\344\270\252\346\234\210\346\202\237\351\200\217JavaScript.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\345\215\267\357\274\211.pdf" "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\345\215\267\357\274\211.pdf" new file mode 100644 index 0000000..ad311ea Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\345\215\267\357\274\211.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\357\274\211.pdf" "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\357\274\211.pdf" new file mode 100644 index 0000000..052b74b Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\212\357\274\211.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\255\345\215\267\357\274\211.pdf" "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\255\345\215\267\357\274\211.pdf" new file mode 100644 index 0000000..922d484 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\344\275\240\344\270\215\347\237\245\351\201\223\347\232\204JavaScript\357\274\210\344\270\255\345\215\267\357\274\211.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243HTTP.pdf" "b/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243HTTP.pdf" new file mode 100644 index 0000000..a298811 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243HTTP.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243http\351\253\230\346\270\205.zip" "b/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243http\351\253\230\346\270\205.zip" new file mode 100644 index 0000000..6576967 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\345\233\276\350\247\243http\351\253\230\346\270\205.zip" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\347\262\276\351\200\232JavaScript.pdf" "b/\347\224\265\345\255\220\344\271\246/\347\262\276\351\200\232JavaScript.pdf" new file mode 100644 index 0000000..655120b Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\347\262\276\351\200\232JavaScript.pdf" differ diff --git "a/\347\224\265\345\255\220\344\271\246/\347\274\226\345\206\231\345\217\257\347\273\264\346\212\244\347\232\204JavaScript.pdf" "b/\347\224\265\345\255\220\344\271\246/\347\274\226\345\206\231\345\217\257\347\273\264\346\212\244\347\232\204JavaScript.pdf" new file mode 100644 index 0000000..c18ae89 Binary files /dev/null and "b/\347\224\265\345\255\220\344\271\246/\347\274\226\345\206\231\345\217\257\347\273\264\346\212\244\347\232\204JavaScript.pdf" differ diff --git "a/\347\254\224\350\256\260/Cookie.md" "b/\347\254\224\350\256\260/Cookie.md" new file mode 100644 index 0000000..f02a845 --- /dev/null +++ "b/\347\254\224\350\256\260/Cookie.md" @@ -0,0 +1,23 @@ +# cookie # + +Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。 +Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。 + +cookie是存于用户硬盘的一个文件,这个文件通常对应于一个域名,当浏览器再次访问这个域名时,便使这个cookie可用。因此,cookie可以跨越一个域名下的多个网页,但不能跨越多个域名使用。 + +cookie机制将信息存储于用户硬盘,因此可以作为全局变量,这是它最大的一个优点。它可以用于以下几种场合。 + +(1)保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。 cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个 月、一年等。 + +(2)跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。如果每次都需要选择所在地是烦琐的,当利用了 cookie后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后 台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便。 + +(3)定制页面。如果网站提供了换肤或更换布局的功能,那么可以使用cookie来记录用户的选项,例如:背景色、分辨率等。当用户下次访问时,仍然可以保存上一次访问的界面风格。 + +(4)创建购物车。正如在前面的例子中使用cookie来记录用户需要购买的商品一样,在结账的时候可以统一提交。例如淘宝网就使用cookie记录了用户曾经浏览过的商品,方便随时进行比较。 + +当然,上述应用仅仅是cookie能完成的部分应用,还有更多的功能需要全局变量。cookie的缺点主要集中于安全性和隐私保护。主要包括以下几种: + +(1)cookie可能被禁用。当用户非常注重个人隐私保护时,他很可能禁用浏览器的cookie功能; +(2)cookie是与浏览器相关的。这意味着即使访问的是同一个页面,不同浏览器之间所保存的cookie也是不能互相访问的; +(3)cookie可能被删除。因为每个cookie都是硬盘上的一个文件,因此很有可能被用户删除; +(4)cookie安全性不够高。所有的cookie都是以纯文本的形式记录于文件中,因此如果要保存用户名密码等信息时,最好事先经过加密处理。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/JavaScript\344\270\255Array\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" "b/\347\254\224\350\256\260/JavaScript\344\270\255Array\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" new file mode 100644 index 0000000..b2f8957 --- /dev/null +++ "b/\347\254\224\350\256\260/JavaScript\344\270\255Array\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" @@ -0,0 +1,45 @@ +# JavaScript中Array的一些操作 +## 1、判断一个对象是否为数组 +``` +function isArray(a) { + return Array.isArray ? Array.isArray(a) : Object.prototype.toString.call(a) === '[object Array]'; +} +``` +  Array.isArray是ES6新增的一个方法,考虑不是所有浏览器都支持ES5,先做判断,如果浏览器支持Array.isArray()则使用,否则使用Object.prototype.toString.call()方法,注意这里说的toString()是Object原型链上的toString()方法,和obj.toString()是两码事。Object.prototype.toString.call()只会返回[Object [[Class]]]这种形式。 +## 2、数组虑重 +  一共总结了四种方法,其中前面两种实际编码中不会用到,但是面试的时候可以提一下。 +#### 双重循环 +  就不多说了,挨个儿比较,时间复杂度为O(n^2)。 +#### 排序后遍历 +  先对数组排序,由于数组已经有序,只需要检查数组中第i个元素与新的结果数组中最后一个元素是否相等即可,如果不相等,则放到新的结果数组中,这种方法的时间复杂度为O(n),但是还要考虑排序的消耗,所以同样不可取。这两种方法比较简单,均不上代码。 +#### Hash的方法 +  散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 +  把Hash表用于数组去重就在于,把数组的值依次存入Hash表的Key值,Value值可以存储Key出现的次数。存取的时候产生冲突的话,忽略该元素,反之把该元素存入新数组。该方法时间复杂度为O(n),是应用最为广泛的去重方法,而在JavaScript语言中,Hash表是用Object实现的,代码如下。 +``` +function unique(array) { + var newArray = []; + var object = {}; + for (var i = 0; i < array.length; i++){ + if(!object[array[i]]) { + newArray.push(array[i]); + object[array[i]] = 1; + } + } + return newArray; +} +``` +#### Set()方法 +  最新的ES6中新增了Map(),Set()这两种数据结构,以及Array.from()方法,它们底层都是用红黑树实现(一种严格意义上平衡二叉树),它们的操作时间复杂度也就是红黑树的操作时间复杂度都为O(logN)。 +  Set()和Map()的区别在于,Set()中的数据没有重复,这个特性刚好可以用于数组去重,且效率非常高,这么好的数据结构在ES6才被实现,真是可惜。 +  下面看代码,非常简洁: +``` +let arr1 = Array.from(new Set(arr1)); +//NodeJS中已经全面支持ES6,这种方法爽的不要不要的。 +``` +#### 总结 +``` +function newUnique(arr1) { + return Array.from ? Array.from(new Set(arr1)) : unique(arr1); +} +//unique()为上面的Hash方法函数。 +``` \ No newline at end of file diff --git "a/\347\254\224\350\256\260/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.md" "b/\347\254\224\350\256\260/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.md" new file mode 100644 index 0000000..9738e27 --- /dev/null +++ "b/\347\254\224\350\256\260/JavaScript\346\250\241\345\235\227\345\214\226+JavaScript\346\225\260\346\215\256\346\216\250\351\200\201.md" @@ -0,0 +1,24 @@ +## һJavaScriptģ黯ĸԱʣ +2009꣬Nodejs ˵ JavaScript ģ黯дܿ˵ JSer ţǷ׷׷ЧдģĹ淶ҲDzCommonJS ͳһǰ˵дAMD ΪԼʺ˵ġڵ CMD dz졣 +ԴnodejsѴģ飬requireá +AMDRequireJSƹжģ鶨Ĺ淶 +첽ģ飬ǰãǰִС +Defineģdefine([require,foo],function(){return}); +Requireģ飨ǰãrequire([foo,bar],function(foo,bar){}); +CMDSeaJSƹжģ鶨Ĺ淶 +Defineexportsdefine(function(require,exports,module){}); +Moduleϴ洢˵ǰģһЩ +Require(./a)ֱ롣Requeir.async첽롣 +ͬأͽӳִС +ƵĻCommonJS Modules/2.0淶 +## JavaScript +ڵ·dzȣǵֻÿ춼յAPPĸϢJavaScriptҪwebappͷ񣬲ÿζȥAjaxServerݵءڱ뱣һӲţͨǰ˲ͣ˷H5ºWebSocket˫͵ݵıԡ +### 1.CometHTTPӵķͼ + HTTP ӵķͼComet һ Web Ӧüܹ˻첽ķʽͻ˳ݣҪͻʽķComet ܹdzʺ¼ Web ӦãԼԽԺʵʱҪǿӦãƱҺ Web Ϸȡ +### 2.WebSocketͷ +WebSocket ͷͨhttpʵֵͨ,cometһ̶ģ˫ͨ,Чʽϵ,ҪнϺõ֧; flashеsocketxmlsocketʵ˫ͨ,ͨ flex ajax bridge,javascriptʹ. Ԥ,websocketһеõʵ,,õ㷺ʹ.״HTML5WebSocketЭ飬ܸõĽʡԴʹﵽʵʱͨѶ +### 3.SSE(Server-Send Event)ݵ·ʽ +ݵ·ʽSSEͳҳ"ѯ"ݣǺܶೡϣЧķʽǷ""ݡ磬ÿյµĵʼ,һ"֪ͨ",ҪʱѯpollingЧʡ¼Server-Sent EventsSSEΪ˽⣬һAPIEventSourceϡĿǰIE֧֡ +## JavaScript +obj array js ΪʱΪô +string number booleanΪʱΪֵ diff --git "a/\347\254\224\350\256\260/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.md" "b/\347\254\224\350\256\260/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.md" new file mode 100644 index 0000000..db3725c --- /dev/null +++ "b/\347\254\224\350\256\260/Koa\346\212\200\346\234\257\345\210\206\344\272\2532.0.md" @@ -0,0 +1,401 @@ +### 学习交流 +项目同时部署在阿里云,访问地址[www.keepforward.xyz:3000](www.keepforward.xyz:3000) +gihub地址:[https://github.com/a1511870876/myblog](https://github.com/a1511870876/myblog)欢迎star +一些学习分享,大家共同交流,地址[https://github.com/a1511870876/studyFiles](https://github.com/a1511870876/studyFiles) +### 写在前面 +  Koa使用了ES6规范的generator和异步编程是一个更轻量级Web开发的框架,Koa 的先天优势在于 generator。由于是我个人的分享交流,所以Node基础、ES6标准、Web开发基础以及Koa的"Hello World"程序都不在讨论,希望各位小伙伴提出意见和指导。 +  PS:Koa 内核中没有捆绑任何中间件,但不用担心,Koa 拥有极其强悍的拓展性,正文所有中间件都可以在npm官网下载安装,但国内域名安装会有一些限制,提供一个国内镜像安装方法,速度非常快,在直接npm模块失败的时候非常好用,使用npm --registry=http://registry.npmjs.org install XXXXX –XX 命令安装,只需要在install后面加上要安装的中间件名称和相应的参数即可。 +### 一、使用Koa搭建Web项目流程 +**1、Koa项目创建** +  个人认为不管任何框架,Web项目搭建必需的几个方面,页面、中间件、路由、会话和存储、日志、静态文件指定,以及错误的处理。当然,网站开发不止这些东西,还有许多主题,比如实时通讯,搜索引擎架构,权限控制,邮件优先队列,日志记录分析,对Web开发还刚刚入门属于菜鸟级别,这里就不做深入的讨论了。了解Express框架的小伙伴一定知道Express的部署过程,不管是通过express-generator生成还是WebStorm等编译器直接创建,它的目录结构大概是这样的: +``` +|——app.js +|——bin +|——node_modules +|——package.json +|——public +|——routes +|——views +``` +  *app.js,是程序启动文件 +  *bin,存放执行程序 +  *node_modules,存放项目依赖库 +  *package.json,是配置和一些相关信息 +  *public,存放静态文件(css,js,img) +  *routes,存放路由文件 +  *views,存放前台页面文件 +  这些结构基本包含了上述提到的Web项目搭建的要素,但是目前类似express-generator的Koa部署工具Koa-generator(非官方)并不完善并且个人测试存在些许错误。其实Koa-generator也是仿造上述express-generator生成的目录,既然这样还不如手动创建目录来的爽快(generator-k是另一款生成器,用上去感觉还行),在根目录新建app.js作为程序的启动文件,创建三个文件夹分别命名public、routes和views,最后新建package.json文件存放你的项目的一些信息。完成这些创建之后,用npm命令安装Koa,这样的话一个基本的Koa框架就搭建好了,非常的的轻量级,它的目录结构如下: +``` + |——app.js + |——node_modules + |——public + | |——img + | |——css + | |——js + | + |——routes + | |——index.js + | |——user.Js + | + |——views + | |——_layout.html + | |——index.html + | + |——package.json + Koa项目运行:node --harmony app.js + 必须加 --harmony ,这样才会支持 ES6 语法。 +``` +**2、Koa日志** +  日志是项目error调试和日常维护的基本手段,Koa有日志模块Koa-logger,npm install Koa-logger后使用app.use(logger());命令程序就会在控制台自动打印日志,当然如果你对Koa-logger的风格不满意或者想要看到更多得信息也可以自己编辑代码实现有自己风格的日志打印。 +例如: +``` + auto map route -> [get]/authority/saveAddUser/ + auto map route -> [get]/authority/searchUserInfo/ + auto map route -> [get]/authority/updateUser/ + auto map route -> [get]/authority/deletedUser/ + auto map route -> [get]/authority/getSelectValues/ + auto map route -> [get]/authority/saveAuthority/ +``` +  最后呢,如果有需要,要把日志进行存储。 +**3、Koa的错误处理** +  Koa 有 error 事件,当发生错误时,可以通过该事件,对错误进行统一的处理。 +``` +var Koa = require('koa'); +var app = Koa(); +app.on('error', function(err,ctx){ + console.log(err); +}); +app.listen(3000); +``` +  上面这段代码在如果捕获到错误,页面会打印出 “Internal Server Error” (这是Koa对错误的默认处理)。这个错误我们在综合监控系统中也经常见到,那么我们显然无法根据这条日志得到什么信息 +``` +TypeError: Cannot read property 'split' of undefined +at Object.Home.index (d:\test\route\home.js:143:31) +at GeneratorFunctionPrototype.next (native) +at Object.dispatch (d:\test\node_modules\koa-router\lib\router.js:97:44) +at GeneratorFunctionPrototype.next (native) +``` +  这些错误信息是怎么报出来的的呢,其实是Koa-onerror 中间件,它优化错误信息,根据这些错误信息就能更好的捕获到错误。 +Koa-onerror使用方法: +``` + var onerror = require('Koa-onerror'); + onerror(app); +``` +**4、Koa静态文件指定** +  Koa静态文件指定中间件Koa-static,npm install Koa-static之后就可以使用Koa-static负责托管 Koa 应用内的静态资源。映射了静态文件目录,引用的时候直接去该目录下寻找资源,会减少一些消耗。(不知道讲的准确不准确,只是个人的理解)指定public为静态文件目录的代码如下: +``` + var staticServer = require('koa-static'); + var path = require('path'); + app.use(staticServer(path.join(__dirname,'public'))); +``` +**5、ejs模板的使用** +  渲染页面需要一种模板,这里选择风格接近html的ejs模板。npm install Koa-ejs后就可以在Koa框架中使用ejs模版。 +``` + var render = require('koa-ejs'); + render(app, { + root: path.join(__dirname, 'views'), + layout: '__layout', + viewExt: 'html', + cache: false, + debug: true + }); + app.use(function *(){ + yield this.render('index',{layout:false}); + }); +``` +**6、Koa路由设置** +  Koa个极简的web框架,简单到连路由模块都没有配备。自己手写路由是这样的: +``` + app.use(function *(){ + //我是首页 + if(this.path==='/'){ + } + }); +``` +  使用更加强大的路由中间件,Koa中设置路由一般安装Koa-router,Koa-router支持五种方法 +``` + router.get() + router.post() + router.put() + router.del() + router.patch() +``` +  GET方法举例: +``` + var app = require('koa')(); + var Router = require('koa-router'); + var myRouter = new Router(); + myRouter.get('/', function *(next) { + yield this.render('index',{layout:false}); + }); + app.use(myRouter.routes()); + app.listen(3000); +``` +  Koa-router 拥有丰富的 api 细节,用好这些 api ,可以让页面代码更为优雅与可维护。 +接收query参数 +``` + http://localhost:3000/?a=1(条件) + index.js + var router = require('koa-router')(); + router + .get('/',function *(next){ + console.log(this.query); + yield this.render('index',{layout:false}); + }) + .get('/home',function *(ctx,next){ + ctx.render('home'); + }); + //ctx为Koa2.0中支持 + ... ... + module.exports = router; + 控制台打印: + <-- GET /?a=1 + { a: '1' } + { a: '1' } + 接收params参数 + http://localhost:3000/users/123(参数) + router.get('/user/:id', function *(next) { + console.log(this.params.id); + }); +``` +  param() 用于封装参数处理中间件,当访问 /detail/:id 路由时,会先执行 param() 定义的 generator function 逻辑。函数的第一个是路由参数的值,next 是中间件流程关键标识变量。 +yield next; +  表示执行下一个中间件。 +``` + app.param('id',function *(id,next){ + this.id = Number(id); + if ( typeof this.id != 'number') return this.status = 404; + yield next; + }).get('/detail/:id', function *(next) { + //我是详情页面 + var id = this.id; //123 + this.body = id; + }); +``` +**7、Koa中间件** +  Koa的中间件很像Express的中间件,也是对HTTP请求进行处理的函数,但是必须是一个Generator函数即 function \*(){} 语法,不然会报错。可以这么说,Nodejs的Web程序中任何请求和响应都是中间件在操作。 +``` + app + .use(logger()) //日志中间件 + .use(serve(__dirname + '/public')) //静态文件指定中间件 + .use(router.routes()) //路由中间件 + .use(router.allowedMethods()); //路由中间件 +``` +  app.use 加载用于处理http请求的middleware(中间件),当一个请求来的时候,会依次被这些 middlewares处理。执行的顺序是你定义的顺序。中间件的执行顺序规则是类似“栈”的结构,所有需要执行的中间件都被一个一个放入“栈”中,当没有遇到next()的时候,“栈”里边的这些中间件被逆序执行。 +``` + app.use(function *(next){ + this; // is the Context + this.request; // is a Koa Request + this.response; // is a Koa Response + }); +``` +说明: +  •this是上下文 +  •\*代表es6里的generator +  http模型里的请求和响应 +  •this.request +  •this.response +  app.use() 究竟发生了什么不可思议的化学反应呢? +其实 app.use() 就干了一件事,就是将中间件放入一个数组,真正执行逻辑的是:app.listen(3000); +Koa 的 listen() 除了指定了 http 服务的端口号外,还会启动 http server,等价于: +``` + var http = require('http'); + http.createServer(app.callback()).listen(3000); +``` +  后面这种繁琐的形式有什么用呢? +  一个典型的场景是启动 https 服务,默认 app.listen(); 是启动 http 服务,启动 https 服务就需要: +``` + var https = require('https'); + https.createServer(app.callback()).listen(3000); +``` +### 二、异步编程 +**1、异步流程控制** +  异步编程对 JavaScript 语言太重要。JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可。 +  以前,异步编程的方法,大概有下面四种。 +  回调函数 +  事件监听 +  发布/订阅 +  Promise 对象 +  JavaScript 语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。它的英语名字 callback,直译过来就是"重新调用"。 +读取文件进行处理,是这样写的。 +``` + fs.readFile('/etc/passwd', function (err, data) { + if (err) throw err; + console.log(data); + }); +``` +  上面代码中,readFile 函数的第二个参数,就是回调函数,也就是任务的第二段。等到操作系统返回了 /etc/passwd 这个文件以后,回调函数才会执行。回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。假定读取A文件之后,再读取B文件,代码如下。 +``` + fs.readFile(fileA, function (err, data) { + fs.readFile(fileB, function (err, data) { + // ... + }); + }); +``` +  不难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就称为"回调函数噩梦"(callback hell)。Promise就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的横向加载,改成纵向加载。采用Promise,连续读取多个文件,写法如下。 +``` + var readFile = require('fs-readfile-promise'); + readFile(fileA) + .then(function(data){ + console.log(data.toString()); + }) + .then(function(){ + return readFile(fileB); + }) + .then(function(data){ + console.log(data.toString()); + }) + .catch(function(err) { + console.log(err); + }); +``` +  上面代码中,我使用了 fs-readfile-promise 模块,它的作用就是返回一个 Promise 版本的 readFile 函数。Promise 提供 then 方法加载回调函数,catch方法捕捉执行过程中抛出的错误。可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。 +  Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。 +  那么,有没有更好的写法呢? +  ECMAScript 6 (简称 ES6 )作为下一代 JavaScript 语言,将 JavaScript 异步编程带入了一个全新的阶段。异步编程的语法目标,就是怎样让它更像同步编程。 +  Koa 的先天优势在于 generator。 +  generator指的是 +``` + function* xxx(){ + } +``` +  是es6里的写法。 +``` + var r = 3; + function* infinite_ap(a) { + for( var i = 0; i < 3 ; i++) { + a = a + r ; + yield a; + } + } + var sum = infinite_ap(5); + console.log(sum.next()); // returns { value : 8, done : false } + console.log(sum.next()); // returns { value : 11, done: false } + console.log(sum.next()); // returns { value : 14, done: false } + console.log(sum.next()); //return { value: undefined, done: true } +``` +  yield语句就是暂停标志,next方法遇到yield,就会暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回对象的value属性的值。当下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。如果没有再遇到新的yield语句,就一直运行到函数结束,将return语句后面的表达式的值,作为value属性的值,如果该函数没有return语句,则value属性的值为undefined。当第一次调用 sum.next() 时 返回的a变量值是5 + 3,同理第二次调用 sum.next() ,a变量值是8 +3,知道循环执行结束,返回done:true标识。大家有没有发现个问题,Koa 中 generator 的用法与上述 demo 演示的用法有非常大得差异,那是因为 Koa 中的 generator 使用了 co 进行了封装。 +**2、co的使用** +  Ps:(这里只是简单介绍,后续可以作为一个专题来讲) +  co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行。 +  比如,有一个 Generator 函数,用于依次读取两个文件。 +``` + var gen = function* (){ + var f1 = yield readFile('/etc/fstab'); + var f2 = yield readFile('/etc/shells'); + console.log(f1.toString()); + console.log(f2.toString()); + }; +``` +  co 函数库可以让你不用编写 Generator 函数的执行器。 +``` + var co = require('co'); + co(gen); +``` +  上面代码中,Generator 函数只要传入 co 函数,就会自动执行。 +  co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数。 +``` + co(gen).then(function (){ + console.log('Generator 函数执行完成'); + }) +``` +  上面代码中,等到 Generator 函数执行结束,就会输出一行提示。 +  为什么 co 可以自动执行 Generator 函数? +  前面文章说过,Generator 函数就是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。 +  两种方法可以做到这一点。 +  (1)回调函数。将异步操作包装成 Thunk 函数,在回调函数里面交回执行权。 +  (2)Promise 对象。将异步操作包装成 Promise 对象,用 then 方法交回执行权。 +  co 函数库其实就是将两种自动执行器(Thunk 函数和 Promise 对象),包装成一个库。使用 co 的前提条件是,Generator 函数的 yield 命令后面,只能是 Thunk 函数或 Promise 对象。 +  参考:[http://www.ruanyifeng.com/blog/2015/05/co.html](http://www.ruanyifeng.com/blog/2015/05/co.html) +**3、Koa 中间件机制实现原理** +使用 Koa 的同学一定会有如下疑问: + +1. Koa 的中间件机制是如何实现? +2. 为什么中间件必须是 generator function? +3. next 实参指向是什么?为什么可以通过 yield next 可以执行下一个中间件? +4. 为什么中间件从上到下执行完后,可以从下到上执行 yield next 后的逻辑? + +  通过实现简单的 Koa 框架(剥离除中间件外所有的逻辑)来解答上述问题,这个框架的名字叫 SimpleKoa: +``` + var co = require('co'); + function SimpleKoa(){ + this.middlewares = []; + } + SimpleKoa.prototype = { + //注入个中间件 + use: function(gf){ + this.middlewares.push(gf); + }, + //执行中间件 + listen: function(){ + this._run(); + }, + _run: function(){ + var ctx = this; + var middlewares = ctx.middlewares; + return co(function *(){ + var prev = null; + var i = middlewares.length; + //从最后一个中间件到第一个中间件的顺序开始遍历 + while (i--) { + //实际Koa的ctx应该指向server的上下文,这里做了简化 + //prev 将前面一个中间件传递给当前中间件 + prev = middlewares[i].call(ctx, prev); + } + //执行第一个中间件 + yield prev; + })(); + } + }; +``` +  写个 demo 印证下中间件执行顺序: +``` + var app = new SimpleKoa(); + app.use(function *(next){ + this.body = '1'; + yield next; + this.body += '5'; + console.log(this.body); + }); + app.use(function *(next){ + this.body += '2'; + yield next; + this.body += '4'; + }); + app.use(function *(next){ + this.body += '3'; + }); + app.listen(); +``` +  执行后控制台输出:123456,对照 Koa 中间件执行顺序,完全一致!寥寥几行代码,我们就实现了 Koa 的中间件机制!这就是 co 的魔力。 +### 三、Koa中涉及但本次没有讲的问题 +**1、Koa中的cookie和session(后续详细讲解)** +  web应用程序都离不开cookie和session的使用,是因为Http是一种无状态性的协议。保存用户状态信息的一种方法或手段,Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。 +**2、Koa中nosql(后续技术分享会详细讲解)** +  mongodb是一个基于文档的非关系型数据库,所有数据是从磁盘上进行读写的,其优势在于查询功能比较强大,能存储海量数据。 +  redis是内存型数据库,数据保存在内存中,通过tcp直接存取,优势是速度快,并发高,缺点是数据类型有限,查询功能不强,一般用作缓存。它由C语言实现的,与 NodeJS工作原理近似,同样以单线程异步的方式工作,先读写内存再异步同步到磁盘,读写速度上比MongoDB有巨大的提升,当并发达到一定程度时,即可考虑使用Redis来缓存数据和持久化Session。 +``` + var mongoose = require('mongoose'); + // 引入 mongoose 模块 + mongoose.connect('mongodb://localhost/blog'); + // 然后连接对应的数据库:mongodb://localhost/test + // 其中,前面那个 mongodb 是 protocol scheme 的名称;localhost 是 mongod 所在的地址; + // 端口号省略则默认连接 27017;blog是数据库的名称 + // mongodb 中不需要建立数据库,当你需要连接的数据库不存在时,会自动创建一个出来。 + module.exports = mongoose; + // 导出 mongoose 模块 + var mongoose = require('../modules/db'); + // 引入 mongoose 模块 + var User = mongoose.model('User',{ + name: {type: String, match: /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/}, + password: String + }); + //创建了一个名为 User 的 model + var user1 = new User({name:'12345@qqqqqq.com'}); + user1.password = 'a5201314'; + user1.save(function(err){ + if(err){ + console.log("save error"); + } + }); +``` \ No newline at end of file diff --git "a/\347\254\224\350\256\260/Node\344\272\244\344\272\222\345\274\217\345\221\275\344\273\244\350\241\214\345\267\245\345\205\267\345\274\200\345\217\221\342\200\224\342\200\224\350\207\252\345\212\250\345\214\226\346\226\207\346\241\243\345\267\245\345\205\267.md" "b/\347\254\224\350\256\260/Node\344\272\244\344\272\222\345\274\217\345\221\275\344\273\244\350\241\214\345\267\245\345\205\267\345\274\200\345\217\221\342\200\224\342\200\224\350\207\252\345\212\250\345\214\226\346\226\207\346\241\243\345\267\245\345\205\267.md" new file mode 100644 index 0000000..e4ea11f --- /dev/null +++ "b/\347\254\224\350\256\260/Node\344\272\244\344\272\222\345\274\217\345\221\275\344\273\244\350\241\214\345\267\245\345\205\267\345\274\200\345\217\221\342\200\224\342\200\224\350\207\252\345\212\250\345\214\226\346\226\207\346\241\243\345\267\245\345\205\267.md" @@ -0,0 +1,325 @@ +# Node交互式命令行工具开发——自动化文档工具 +  `nodejs`开发命令行工具,流程相对简单,但一套完整的命令行程序开发流程下来,还是需要下点功夫,网上资料大多零散,这篇教程意在整合一下完整的开发流程。 +  [npm](https://www.npmjs.com/)上命令行开发相关包很多,例如`minimist`、`optimist`、`nopt`、`commander.js`、`yargs`等等,使用方法和效果类似。其中用得比较多的是TJ大神的[commander](https://www.npmjs.com/package/commander)和[yargs](https://www.npmjs.com/package/yargs),本文以`commander`为基础讲述,可以参考这篇[教程](http://yijiebuyi.com/blog/2cd3833e8551a302b4ec645031bfd3d0.html),yargs教程可以参考[阮大神的](http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html)或者[这一篇](https://ideras.me/a-complete-guide-to-yargs/index.html)。 +  另外,一个完整的命令行工具开发,还需要了解`process`、`shelljs`、`path`、`linebyline`等模块,这些都是`node`基础模块或一些简单模块,非常简单,就不多说了,另外如果你不想用回调函数处理异步还需要了解一下`Promise`、`Generator`函数。这是教程:`i5ting`大神的[《深入浅出js(Node.js)异步流程控制》](https://github.com/i5ting/asynchronous-flow-control?utm_source=tuicool&utm_medium=referral)和阮大神的[异步编程教程]( http://es6.ruanyifeng.com/#docs/async)以及[promise小人书](http://liubin.github.io/promises-book/#introduction),另外想尝试ES7 stage3阶段的`async/await`异步解决方案,可参考这篇[教程](http://think2011.net/2015/11/09/ES7-Async-Await/),`async/await`解决方案需要`babel`转码,这是[教程](http://www.ruanyifeng.com/blog/2016/01/babel.html)。本人喜欢`async/await`(哪个`node`开发者不喜欢呢?)但不喜欢倒腾,况且`async/await`本身就是`Promise`的语法糖,所以没选择使用,据江湖消息,`nodejs`将在今年晚些时候(10月份?)支持`async/await`,很是期待。 +  以下是文章末尾实例用到的一些依赖。 + +```json +"dependencies": { + "bluebird": "^3.4.1", + "co": "^4.6.0", + "colors": "^1.1.2", + "commander": "^2.9.0", + "dox": "^0.9.0", + "handlebars": "^4.0.5", + "linebyline": "^1.3.0", + "mkdirp": "^0.5.1" + } +``` +  其中`bluebird`用于`Promise`化,TJ大神的`co`用于执行`Generator`函数,`handlebars`是一种模板,`linebyline`用于分行读取文件,`colors`用于美化输出,`mkdirp`用于创建目录,另外教程中的示例是一款工具,可以自动化生成数据库和`API`接口的`markdown`文档,并通过修改`git hooks`,使项目的每次`commit`都会自动更新文档,借助了TJ大神的`dox`模块。 +  所有推荐教程/教材,仅供参考,自行甄选阅读。 +### 安装Node +  各操作系统下安装见[Nodejs官网](https://nodejs.org/en/),安装完成之后用`node -v`或者`which node`等命令测试安装是否成功。`which`在命令行开发中是一个非常有用的命令,使用`which`命令确保你的系统中不存在名字相同的命令行工具,例如`which commandName`,例如`which testdev`命令返回空白那么说明`testdev`命令名称还没有被使用。 +### 初始化 +1. 新建一个`.js`文件,即是你的命令要执行的主程序入口文件,例如`testdev.js`。在文件第一行加入`#!/usr/bin/env node`指明系统在运行这个文件的时候使用`node`作为解释器,等价于`node testdev.js`命令。 +2. 初始化`package.json`文件,使用`npm init`命令根据提示信息创建,也可以是使用`npm init -y`使用默认设置创建。创建完成之后需要修改`package.json`文件内容加入`"bin": {"testdev": "./testdev.js"}`这条信息用于告诉`npm`你的命令(`testdev`)要执行的脚本文件的路径和名字,这里我们指定`testdev`命令的执行文件为当前目录下的`testdev.js`文件。 +3. 为了方便测试在`testdev.js`文件中加入代码`console.log('hello world');`,这里只是用于测试环境是否搭建成功,更加复杂的程序逻辑和过程需要按照实际情况进行编写 + +### 测试 +  使用`npm link`命令,可以在本地安装刚刚创建的包,然后就可以用`testdev`来运行命令了,如果正常的话在控制台会打印出`hello world` +### commander +  TJ的[commander](https://github.com/tj/commander.js)非常简洁,`README.md`已经把使用方法写的非常清晰。下面是例子中的代码: + +```js +const program = require('commander'), + co = require('co'); + +const appInfo = require('./../package.json'), + asyncFunc = require('./../common/asyncfunc.js'); + +program.allowUnknownOption(); +program.version(appInfo.version); + +program + .command('init') + .description('初始化当前目录doc.json文件') + .action(() => co(asyncFunc.initAction)); + +program + .command('show') + .description('显示配置文件状态') + .action(() => co(asyncFunc.showAction)); + +program + .command('run') + .description('启动程序') + .action(() => co(asyncFunc.runAction)); + +program + .command('modifyhook') + .description('修改项目下的hook文件') + .action(() => co(asyncFunc.modifyhookAction)); + +program + .command('*') + .action((env) => { + console.error('不存在命令 "%s"', env); + }); + +program.on('--help', () => { + console.log(' Examples:'); + console.log(''); + console.log(' $ createDOC --help'); + console.log(' $ createDOC -h'); + console.log(' $ createDOC show'); + console.log(''); +}); + +program.parse(process.argv); +``` +  定义了四个命令和个性化帮助说明。 +### 交互式命令行process +  `commander`只是实现了命令行参数与回复一对一的固定功能,也就是一个命令必然对应一个回复,那如何实现人机交互式的命令行呢,类似`npm init`或者`eslint --init`这样的与用户交互,交互之后根据用户的不同需求反馈不同的结果呢。这里就需要`node`内置的`process`模块。 +  这是我实现的一个`init`命令功能代码: + +```js +exports.initAction = function* () { + try { + var docPath = yield exists(process.cwd() + '/doc.json'); + if (docPath) { + func.initRepl(config.coverInit, arr => { + co(newDoc(arr)); + }) + } else { + func.initRepl(config.newInit, arr => { + co(newDoc(arr)); + }) + } + } catch (err) { + console.warn(err); + } +``` +  首先检查`doc.json`文件是否存在,如果存在执行覆盖交互,如果不存在执行生成交互,`try...catch`捕获错误。 +  交互内容配置如下: + +```js + newInit: + [ + { + title:'initConfirm', + description:'初始化createDOC,生成doc.json.确认?(y/n) ', + defaults: 'y' + }, + { + title:'defaultConfirm', + description:'是否使用默认配置.(y/n) ', + defaults: 'y' + }, + { + title:'showConfig', + description:'是否显示doc.json当前配置?(y/n) ', + defaults: 'y' + } + ], + coverInit:[ + { + title:'modifyConfirm', + description:'doc.json已存在,初始化将覆盖文件.确认?(y/n) ', + defaults: 'y' + }, + { + title:'defaultConfirm', + description:'是否使用默认配置.(y/n) ', + defaults: 'y' + }, + { + title:'showConfig', + description:'是否显示doc.json当前配置?(y/n) ', + defaults: 'y' + } + ], +``` +  人机交互部分代码也就是`initRepl`函数内容如下: + +```js +//初始化命令,人机交互控制 +exports.initRepl = function (init, func) { + var i = 1; + var inputArr = []; + var len = init.length; + process.stdout.write(init[0].description); + process.stdin.resume(); + process.stdin.setEncoding('utf-8'); + process.stdin.on('data', (chunk) => { + chunk = chunk.replace(/[\s\n]/, ''); + if (chunk !== 'y' && chunk !== 'Y' && chunk !== 'n' && chunk !== 'N') { + console.log(config.colors.red('您输入的命令是: ' + chunk)); + console.warn(config.colors.red('请输入正确指令:y/n')); + process.exit(); + } + if ( + (init[i - 1].title === 'modifyConfirm' || init[i - 1].title === 'initConfirm') && + (chunk === 'n' || chunk === 'N') + ) { + process.exit(); + } + var inputJson = { + title: init[i - 1].title, + value: chunk, + }; + inputArr.push(inputJson); + if ((len--) > 1) { + process.stdout.write(init[i++].description) + } else { + process.stdin.pause(); + func(inputArr); + } + }); +} +``` +  人机交互才用向用户提问根据用户不同输入产生不同结果的形式进行,顺序读取提问列表并记录用户输入结果,如果用户输入`n/N`则终止交互,用户输入非法字符(除`y/Y/n/N`以外)提示输入命令错误。 +### 文档自动化 +  文档自动化,其中数据库文档自动化,才用依赖`sequelize`的方法手写(根据需求不同自行编写逻辑),`API`文档才用TJ的[dox](https://github.com/tj/dox)也很简单。由于此处代码与命令行功能相关度不大,请读者自行去示例地址查看代码。 +### 示例地址 +[github地址](https://github.com/threerocks/buildDOC) +[npm地址]( https://www.npmjs.com/package/createDOC) +### 工具说明 +## 简介 + +工具可以自动化生成数据库和API接口的markdown文档,并通过修改git hooks,使项目的每次commit都会自动更新文档。 + +## 安装 + + `npm i createDOC -g` + +## 配置 + - 在项目根目录使用`createDOC init`命令初始化,该命令会在当前目录创建`doc.json`文件。 + - 生成`doc.json`文件后,需要详细配置数据库schemas存储路径(目前只支持关系型数据库),以及路由控制文件,以及子路由目录。 + - API注释规则,遵循TJ大神dox规范,简化版规则如下 + + ```js + /** + * API description + * + * @param {type} name/name=default_value description + * @return {String} description + * @example + * any example + * + * @other description + */ + ``` + +*ps: 此工具为内部使用工具,如个人使用可下载源码,做简单修改即可* +## 使用 + +```sh + Usage: createDOC [options] [command] + + Commands: + + init 初始化当前目录doc.json文件 + show 显示配置文件状态 + run 启动程序 + modifyhook 修改项目下的hook文件 + * + + Options: + + -h, --help output usage information + -V, --version output the version number + + Examples: + + $ createDOC --help + $ createDOC -h + $ createDOC show +``` + +## 示例说明 +doc.json示例 + +```json +{ + "db": { + "schemas": "/Users/mac/Desktop/testssss/schemas", + "markdown": { + "path": "/Users/mac/Desktop/testssss/doc1/", + "file": "db.md" + } + }, + "api": { + "controller": "/Users/mac/Desktop/testssss", + "routes": "/Users/mac/Desktop/testssss", + "markdown": { + "path": "/Users/mac/Desktop/testssss/doc1", + "file": "api.md" + } + } +} +``` +schema.js示例 + +```js +module.exports = function(sequelize, DataTypes) { + return sequelize.define('test_zk_absence', { + //这是id + id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true + }, + //这是end_data + end_date: { + type: DataTypes.DATE, + allowNull: true + }, + /* + { + a:1, + b:2, + c:{a:2}, + d:'2222' + } + */ + type_id: { + type: DataTypes.INTEGER, + allowNull: true + }, + updated_at: { + type: DataTypes.DATE, + allowNull: false + } + }, { + tableName: 'test_zk_absence' + }); + }; +``` +api注释示例 + +```js +/** + * 获取多个课程 + * @param {Number} examinationId 考试类型 + * @param {Number} subjectId 科目类型 + * @param {Number} statusId=3 状态类型 + * @param {String} startDate 更新开始时间 + * @param {String} endDate 更新结束时间 + * @param {String} keyword 关键词 + * @param {Number} page 页码 + * @return {Array} ok + * @example [1,2,3,3,4] + */ +getCourses(req, params) { + ... ... +} +``` +## TODO +1. 代码逻辑优化,适应力更强。 +2. 代码速度、质量优化。 +3. 加入单元测试 + + + + diff --git "a/\347\254\224\350\256\260/Object.create\350\257\246\350\247\243.md" "b/\347\254\224\350\256\260/Object.create\350\257\246\350\247\243.md" new file mode 100644 index 0000000..b7e3998 --- /dev/null +++ "b/\347\254\224\350\256\260/Object.create\350\257\246\350\247\243.md" @@ -0,0 +1,14 @@ +# Object.create +简单来讲,new Object()是一种通过构造函数来创建object的方式,而Object.create(proto, [ propertiesObject ]) +不需要通过构造函数就可以创建一个object,Object.create()的第一个参数是必须要的,第二个参数可选。其实Object.create()内部依然是通过new一个构造函数的方式来实现的,它有构造函数,不过这个构造函数是隐式存在的,看一下使老旧浏览器支持Object.create方法的“polyfill”就可以对它们之间的区别一目了然了: + +```js +if (!Object.create) { + Object.create = function (o) { + function F() {} //定义了一个隐式的构造函数 + F.prototype = o; + return new F(); //其实还是通过new来实现的 + }; + } + ``` +ps:Object.create可以用于对象的深拷贝,非常好用 diff --git "a/\347\254\224\350\256\260/git.md" "b/\347\254\224\350\256\260/git.md" new file mode 100644 index 0000000..672db6b --- /dev/null +++ "b/\347\254\224\350\256\260/git.md" @@ -0,0 +1,10 @@ +Create a new repository on the command line +touch README.md +git init +git add README.md +git commit -m "first commit" +git remote add origin https://github.com/a1511870876/secondWorks.git +git push -u origin master +Push an existing repository from the command line +git remote add origin https://github.com/a1511870876/secondWorks.git +git push -u origin master \ No newline at end of file diff --git "a/\347\254\224\350\256\260/http\345\214\205\344\270\276\344\276\213.md" "b/\347\254\224\350\256\260/http\345\214\205\344\270\276\344\276\213.md" new file mode 100644 index 0000000..d40f2f3 --- /dev/null +++ "b/\347\254\224\350\256\260/http\345\214\205\344\270\276\344\276\213.md" @@ -0,0 +1,37 @@ +# HTTP协议 # +刚刚说到其实协议就是让浏览器跟服务器互相知道他们要什么,因此浏览器发给服务器的包就要带着一些用户操作信息,服务器发给浏览器的包就要带着用户想要的数据信息。 +当浏览器输入一个URL,相当于浏览器发起一个HTTP请求包出去,浏览器会把一些自身信息以及用户操作的信息写在包头上带到服务器,这样服务器才知道你在用什么浏览器想请求它的什么资源。 + +## HTTP请求包的常见包头如下 +GET / HTTP/1.1 +获取的路径以及HTTP版本 +Host: www.qq.com:8080 +服务器主机名字&端口号 +Connection: keep-alive +用于长连 +User-Agent: Chrome/35.0.1916.153 +浏览器基本信息 +Accept-Encoding: gzip,deflate,sdch +告诉服务器支持的编码 +Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,nl;q=0.4,zh-TW;q=0.2 +告诉服务器优先支持的语言 +Cookie: id=1;username=raphealguo; +解决HTTP无状态重要的Cookie,里边是key=value对 紧接着服务器收到HTTP请求,经过CGI处理之后回复一个HTTP响应包,服务器需要告诉你包里边是什么(Content-Type),包里边有多少东西 (Content-Length),服务器版本是什么等等。 + +## HTTP响应包常见的包头如下: + +HTTP/1.1 200 OK +HTTP版本以及状态码 +Server: nginx/1.4.1 +服务器版本 +Date: Mon, 30 Jun 2014 09:44:10 GMT +回包时间 +Content-Type: text/html; charset=UTF-8 +包里边的类型 +Content-Length: 14534 +包体的长度 +Connection: keep-alive +用于长连 +Cache-Control: no-cache, must-revalidate +用于缓存控制 +具体的HTTP协议的细节推荐阅读《HTTP权威指南》。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/http\351\224\231\350\257\257\347\240\201.md" "b/\347\254\224\350\256\260/http\351\224\231\350\257\257\347\240\201.md" new file mode 100644 index 0000000..6cef1e8 --- /dev/null +++ "b/\347\254\224\350\256\260/http\351\224\231\350\257\257\347\240\201.md" @@ -0,0 +1,31 @@ +# 所有 HTTP 状态代码及其定义 + +## 2xx 成功 ## +200 正常;请求已完成。 +201 正常;紧接 POST 命令。 +202 正常;已接受用于处理,但处理尚未完成。 +203 正常;部分信息 — 返回的信息只是一部分。 +204 正常;无响应 — 已接收请求,但不存在要回送的信息。 + +## 3xx 重定向 ## +301 已移动 — 请求的数据具有新的位置且更改是永久的。 +302 已找到 — 请求的数据临时具有不同 URI。 +303 请参阅其它 — 可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。 +304 未修改 — 未按预期修改文档。 +305 使用代理 — 必须通过位置字段中提供的代理来访问请求的资源。 +306 未使用 — 不再使用;保留此代码以便将来使用。 + +## 4xx 客户机中出现的错误 ## +400 错误请求 — 请求中有语法问题,或不能满足请求。 +401 未授权 — 未授权客户机访问数据。 +402 需要付款 — 表示计费系统已有效。 +403 禁止 — 即使有授权也不需要访问。 +404 找不到 — 服务器找不到给定的资源;文档不存在。 +407 代理认证请求 — 客户机首先必须使用代理认证自身。 +415 介质类型不受支持 — 服务器拒绝服务请求,因为不支持请求实体的格式。 + +## 5xx 服务器中出现的错误 +500 内部错误 — 因为意外情况,服务器不能完成请求。 +501 未执行 — 服务器不支持请求的工具。 +502 错误网关 — 服务器接收到来自上游服务器的无效响应。 +503 无法获得服务 — 由于临时过载或维护,服务器无法处理请求。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.md" "b/\347\254\224\350\256\260/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.md" new file mode 100644 index 0000000..24be758 --- /dev/null +++ "b/\347\254\224\350\256\260/mongoose\344\275\277\347\224\250\345\277\203\345\276\227.md" @@ -0,0 +1,41 @@ +### 主要是自己使用mongoose的一些有疑虑的地方简单介绍 +  初次使用mongoose的过程中有很多的疑惑,MongoDB是文档型数据库,文档保存在集合中,所有的增删改查都是在集合中操作,而在mongoose中很多操作并没有集合的概念,因此在集合的创建、查询、删除等等操作的时候,我就会想Collections在哪?相信初学者都会有这样的疑惑。直到翻看了官方文档中的一句话,“With Mongoose, everything is derived from a Schema.”注意,是everything。记住这句话,我相信不管是学习还是使用mongoose,那么思考的方向已经对了。 +  使用mongoose连接MongoDB就不多说了,直接上代码: +``` + var mongoose = require(‘mongoose’); + // 引入 mongoose 模块 + mongoose.connect(‘mongodb://localhost/test); + // 然后连接对应的数据库:mongodb://localhost/test + // 其中,前面那个 mongodb 是 protocol scheme 的名称;localhost 是 mongod 所在的地址; + // 端口号省略则默认连接 27017;test 是数据库的名称 + // mongodb 中不需要建立数据库,当你需要连接的数据库不存在时,会自动创建一个出来。 + var db = mongoose.connection; + db.on(‘error’, console.error.bind(console, ‘connection error:’)); + db.once(‘open’, function (callback) { + console.log(“MongoDB Opened!”); + }); + module.exports = mongoose; +``` +  值得注意的是,考虑任何问题,尤其是我们码农在程序中考虑任何问题,都要考虑发生错误怎么办,使用mongoose也不例外。 +``` + var mongoose = require(’…/modules/db’); + var impressionSchema = mongoose.Schema({ + impression:{type:String}, + author:{type:String} + }); + var impressionModel = mongoose.model(‘friendimpression’,impressionSchema); + var impression = new impressionModel({impression:“fool”,author:“sweety”}); + impression.save(function (err) { + if (err) return console.error(err); + console.log(“Save Successful!”); + }); +``` +  这段代码是保存一个文档的实例,在这段代码中我的疑虑是我们把文档保存在哪个Collection里边?答案仍然是“With Mongoose, everything is derived from a Schema.”,mongoose是通过model来创建mongodb中对应的collection的,mongoose在内部创建collection时将我们传递的collection名(‘friendimpression’)小写化,同时如果小写化的名称后面没有字母——s,则会在其后面添加一s,针对我们刚建的collection,则会命名为:friendimpressions。 +``` + impressionModel.find(function (err, docs) { + if (err) return console.error(err); + console.log(docs) + }); + }; +``` +  查询的疑虑在于,我如果对存在的表进行查询怎么办?我必须先创建model?可是我不需要插入删除等操作,我只想查询一下就完事儿。看一下mongoose官方的查询方法Model.find、Model.findOne、Model.findById、Model.where、Model.$where等等,都是基于Model,Model又来自Schema,其实Schema就是你文档结构的规则,俗话说无规矩不成方圆,MongoDB也是一样,不关你是查询还是插入、删除都得有个规矩,所以即使是简单的查询也要从Schema开始,有了规矩增删改查起来也方便很多。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/nodejs+phantomjs+nodemailer.md" "b/\347\254\224\350\256\260/nodejs+phantomjs+nodemailer.md" new file mode 100644 index 0000000..fbe38be --- /dev/null +++ "b/\347\254\224\350\256\260/nodejs+phantomjs+nodemailer.md" @@ -0,0 +1,196 @@ +### 功能 +每天定时截图,并把截到的图片自动通过邮件发送。 +### 说明 +代码注释已经非常详细,就不多做说明,需要的朋友自己查看代码即可,主文件Mail.js,截图文件capturePart1.js,capturePart2.js,capturePart3.js,这里只展示了capturePart1.js其他两个类似。值得注意的是有登录权限的网站一定要设置Cookie,需要截取高质量图片的话截取时间一定设置长一些。 +### Mail.js +``` + * 定时发送邮件功能说明: + * node.js必备安装模块:node_modules-->phantomjs,nodemailer,node-schedule,moment + * 涉及JS文件:route-->mail.js,public-->js-->capturePart1.js,capturePart2.js,capturePart3.js + * 截图保存地址:public-->images-->mainPage.jpeg(1600*4200) + * 截图url:http://www.***********.com + * 程序主要思路: + * (1)phantomjs截图-->参照http://phantomjs.org/ + * (2)nodemailer发送邮件-->参照https://www.npmjs.com/package/nodemailer + * (3)node-schedule定时-->参照https://www.npmjs.com/package/node-schedule + * 注意: + * 改变发件服务器请修改SMTP + * 改变收件人请修改变量receiver + * 改变邮件内容请修改变量html + * 改变邮件附加图片和附件请修改attachments + * 改变截图功能请修改public-->js-->server.js + * 改变定时功能请修改变量rule + * ------Sweety +//组件引入开始 +var schedule = require("node-schedule"); +var path = require('path'); +var childProcess = require('child_process'); +var phantomjs = require('phantomjs'); +var nodemailer = require("nodemailer"); +var moment = require("moment"); +//组件引入结束 +/*--------------------------------------------------------------------------------------------------------------------------------------------*/ +//变量定义开始 +var today; //今天开始时间 +var binPath = phantomjs.path; //获取phantomjs.exe路径 +var jsPath = process.cwd()+"/public/js/"; //获取server.js所在目录 +var childArgs; +//capturePart3(); +//capturePart1(); +//变量定义结束 +/*--------------------------------------------------------------------------------------------------------------------------------------------*/ +//主程序开始 +var rule = new schedule.RecurrenceRule(); //schedule定时器 +rule.hour = 11; +rule.minute = 0; +rule.second = 0; //定时器规则设定(每天11点触发事件) +var j = schedule.scheduleJob(rule, function(){ + var now = moment(); + today = now.clone().add(-1, 'days').format('YYYY-MM-DD'); + capturePart1(); //触发截图事件(邮件发送功能包含在截图事件里边) +}); +//主程序结束 +/*---------------------------------------------------------------------------------------------------------------------------------------------*/ +//phantomjs截图开始(第一张) +function capturePart1(){ + childArgs = [ + path.join(jsPath, 'serverPart1.js'), //server.js + ' https://www.hao123.com ' //要截图的url + ]; + childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) { + if(err) + { + console.log(err); //打印错误信息 + }else{ + console.log("Captured Part1 Successful !!"); //打印正确信息 + capturePart2(); + } + }); +} +//phantomjs截图结束(第一张) +//phantomjs截图开始(第二张) +function capturePart2(){ + childArgs = [ + path.join(jsPath, 'serverPart2.js'), //server.js路径 + 'https://www.hao123.com ' //要截图的url + ]; + childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) { + if(err) + { + console.log(err); //打印错误信息 + }else{ + console.log("Captured Part2 Successful !!"); //打印正确信息 + capturePart3(); + } + }); +} +//phantomjs截图结束(第二张) +//phantomjs截图开始(第三张) +function capturePart3(){ + childArgs = [ + path.join(jsPath, 'serverPart3.js'), //server.js路径 + ' https://www.hao123.com ' //要截图的url + ]; + childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) { + if(err) + { + console.log(err); //打印错误信息 + }else{ + console.log("Captured Part3 Successful !!"); //打印正确信息 + sent(); // 触发发送邮件事件 + } + }); +} +//phantomjs截图结束(第三张) +/*-------------------------------------------------------------------------------------------------------------------------------------------------*/ +//nodemailer发送邮件开始 +function sent(){ + var imgPart1 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart1.jpeg"); //图片来源 + var imgPart2 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart2.jpeg"); //图片来源 + var imgPart3 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart3.jpeg"); //图片来源 + var smtpTransport = nodemailer.createTransport("SMTP",{ //邮件SMTP设定(发送邮箱服务器必须开启SMTP) + host: "smtp.xxxxx.com", // 主机 + secureConnection: false, // 不使用 SSL + port: 587, // SMTP 端口 + auth: { + user: "xxxxx@xxxx.com", //用户名 + pass: "xxxxxx" //密码 + } + }); + var html = '' + + 'XX好:
'+ + '  下面为【XXXX】日报汇报('+today+')的内容,请参考
' + + '  (日报详细信息请点击此处登陆查看)'+ + '
' + + ''+ + ''+ + '';//邮件内容(html代码),img唯一指定地址对应cid(见mailOptions设定) + var receiver = "xxx@xxx.com";//收件人列表 + var cc = "xxxx@xxxx.com,xxx@xxx.com,xxx@xxxx.com"; //抄送人列表 + var bcc = "xxx@xxxx.com,xxx@xxxx.com"; //密抄送人列表 + var mailOptions = { //邮件内容选项设定 + from: "", //发件地址 + //to: "xxx@xxxx.com", + to: receiver, //收件人 + cc:cc, //抄送人 + bcc:bcc, //密抄送人 + subject:"【XXXX】日报汇报("+today+")", //邮件主题 + text: "【XXXX】日报汇报("+today+")", // plaintext body + html:html, //html内容 + attachments: [ + { + filename: 'mainPagePart1.jpeg', //图片名称 + contents: imgPart1, //图片来源 + cid: 'img1' //插入图片标识 + },{ + filename: 'mainPagePart2.jpeg', //图片名称 + contents: imgPart2, //图片来源 + cid: 'img2' //插入图片标识 + },{ + filename: 'mainPagePart3.jpeg', //图片名称 + contents: imgPart3, //图片来源 + cid: 'img3' //插入图片标识 + } + ] + }; + smtpTransport.sendMail(mailOptions, function(error, response){//发送邮件 + if(error){ + console.log(error); //打印错误信息 + }else{ + console.log("Sent Successful !!"); //打印正确信息 + } + }); +} +//nodemailer发送邮件结束 +function changeData(){ +} +/*---------------------------------------------------------------------------------------------------------------------------------------------*/ +``` + +### capturePart1.js + +``` +//phantomjs截图 +var page = require('webpage').create(), + system = require('system'), + address; +page.viewportSize = { width:1920, height: 1080}; +page.clipRect = { top: 200, left: 210, width: 1680, height: 1530 }; +page.customHeaders={"Cookie":"koa:sess=e*******=;koa:sess.sig=pjadZtLAVtiO6-Haw1vnZZWrRm8"}; +if (system.args.length === 1) { + phantom.exit(1); +} else { + address = system.args[1]; + page.open(address, function (status) { + }); +} +setTimeout(function() { + console.log(""); + console.log("### STEP 5: Close page and shutdown (with a delay)"); + page.render('./public/images/mainPagePart1.jpeg', {format: 'jpeg', quality: '100'}); + page.close(); + setTimeout(function(){ + phantom.exit(); + }, 3000); +}, 19000); +``` \ No newline at end of file diff --git "a/\347\254\224\350\256\260/package\347\256\241\347\220\206.md" "b/\347\254\224\350\256\260/package\347\256\241\347\220\206.md" new file mode 100644 index 0000000..dbc912c --- /dev/null +++ "b/\347\254\224\350\256\260/package\347\256\241\347\220\206.md" @@ -0,0 +1,30 @@ +## Package管理 +  后台npm +  (不多说) +  前台bower +  简介: +  Bower的功能类似于Nodejs中的npm或者Python中的pip,用于web包管理,如果越来越多得开源项目都托管在github上,bower只需要将github上项目加上一个配置文件既可以使用bower方式使用安装包。作为包管理,bower能提供添加新web包,更新web包,删除web包,发布web包功能,管理包依赖。web包通常认为由html+css+javascript构成。使用: +  根据上面的简介描述,bower依赖于nodejs,下载安装依赖库实际上是使用git进行下载,因此使用bower前确保安装了Node和Git环境,并且建议使用git bash命令行来执行bower install命令。 +  (常用npm、node、大神略过此段)另外可能我们需要在任何目录使用bower命令的话,需要配置npm环境变量,这一步很重要,不然会提示“bower”不是内部或外部命令,配置npm环境变量就很简单了,在path目录下添加npm全局的包的安装路径但不包含node_modules目录,另外新建NODE_PATH,值为全局的包的安装路径包含node_modules目录,例如:path:D:\node,NODE_PATH:D:\node\node_modules,这样我们npm install XXX –g的安装包才能在全局使用,不会出现提示“XXX不是内部或外部命令”。 +  好了,废话不多说,bower使用就很简单了: +  安装bower +  npm install bower -g +  在项目目录中运行 +  bower install jquery +  运行成功之后项目中会多出components文件夹,文件夹中jquery文件夹,jquery文件夹里面就有最新的  jquery文件。 +  这还不能说明他NB的地方,试想下面的场景,jQuery升级了,是不是再down一次jQuery呢?bower可以这样做: +  bower update jquery +  就可以自动升级到最新版的jquery了。 +  再假设我们需要使用bootstrap,bootstrap可不是一个文件,有css,js还有图片。js还依赖于jQuery,如果使用bower: +  bower install bootstrap +  bower会自动从github上down最新的代码,而且,会自动将依赖包jquery也down一次。 +  如果你发布程序的时候不想把一些依赖的库发布上去(主要原因是太大了 – – ),可以在项目根目录下生成一个 bower.json 文件用来管理依赖。 +  在项目目录下执行 +  bower init +  按照提示操作就好,这样子会生成一个bower文件 +  安装 jquery +  bower install jquery --save +  这样子 bower.json 文件就会写入一个 Jquery的依赖项 +  别人只要在项目目录下输入 +  bower install +  就会自动安装了 diff --git "a/\347\254\224\350\256\260/python\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\255\246\344\271\240.md" "b/\347\254\224\350\256\260/python\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\255\246\344\271\240.md" new file mode 100644 index 0000000..311cec0 --- /dev/null +++ "b/\347\254\224\350\256\260/python\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\255\246\344\271\240.md" @@ -0,0 +1,134 @@ +## 正则表达式学习 +\.就是一个占位符,匹配除'\n'之外的任意字符。 +\*匹配前面字符0次或任意次 +?匹配前一个字符0次或1次 +___ +上面的内容全部只需要了解即可,需要掌握的只有下面这一种组合方式(.*?) +.* 贪心算法,尽可能多的匹配,像一个胖子尽可能多的吃 +.*?非贪心算法,尽可能少的匹配,像一个婴儿少量多餐 +``` +例如:code = 'hhosahfoxxIxxohofhjosfhxxlovexxoruowhntlnmlxxyouxxljh' + re.findall('xx.*xx',code)匹配第一个xx到最后一个xx,即xxIxxohofhjosfhxxlovexxoruowhntlnmlxxyouxx + re.findall('xx.*?xx',code)匹配结果['xxIxx','xxlovexx','xxyouxx'] +(.*?)括号内的数据作为结果返回 +例如:d = re.findall('xx(.*?)xx',code) + for each in d + print each +打印结果: +I +love +you +``` +___ +re.S +``` +例如:code = 'hhosahfoxxI + xxohofhjosfhxxlovexxoruowhntlnmlxxyouxxljh' + d = re.findall('xx(.*?)xx',code) + print d +打印结果['ohofhjosfh','oruowhntlnml'] +解释:.号可以匹配任意字符,但除了换行符'\n' +这时候就需要re.S +例如:d = re.findall('xx(.*?)xx',code,re.S) + print d +打印结果['I\n','love','you'] +可以看出re.S的作用使.包括\n +其他: +重点掌握三个 +re.I 使匹配对大小写不敏感 +re.L 做本地化识别(locale-aware)匹配 +re.M 多行匹配,影响 ^ 和 $ +``` +___ +对比findall与search的区别 +``` +s2 = 'asdfxxIxx123xxlovexxdfdasdfxxIxx123xxlovexxdfd' +f = re.search('xx(.*?)xx123xx(.*?)xx',s2) +print f.group(2) +if not f: + print 'not' +else: + print 'yes' +输出结果: +love +yes +注:re.serch与re.match()区别是re.match()只匹配字符串的开始,则匹配失败,函数返回None +f2 = re.findall('xx(.*?)xx123xx(.*?)xx',s2) +print f2 +输出结果: +[('I', 'love'), ('I', 'love')] +注:findall返回一个list,有多次匹配在list中嵌套tuple(元组) +``` +___ +sub的使用 +``` +s = '123abccssfadjfdj123' +output = re.sub('123(.*?)123','123%d123%789',s) +print output +``` +___ +常用技巧 +``` +1、在确定只有一个内容时,使用search方法可以提高效率 +2、不要要使用compile +str = 'asdfxxIxx123xxlovexxdfdasdfxxIxx123xxlovexxdfd' +pattern = 'xx(.*?)xx' +new_pattern = re.compile(pattern,re.S) +output = re.findall(new_pattern,str) +3、匹配数字使用\d+ +a = 'asdsds123456fasd888fas' +b = re.findall('(\d+)',a) +print b +执行结果:['123456','888'] +``` +___ +总结 +``` +re.match 尝试从字符串的起始位置匹配一个模式。 +re.search 扫描整个字符串并返回第一个成功的匹配。 +re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。 +re.sub用于替换字符串中的匹配项。 +re.split按照能够匹配的子串将string分割后返回列表。 +re.findall搜索string,以列表形式返回全部能匹配的子串。 +re.finditer搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。 +re.I 使匹配对大小写不敏感 +re.L 做本地化识别(locale-aware)匹配 +re.M 多行匹配,影响 ^ 和 $ +re.S 使 . 匹配包括换行在内的所有字符 +re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. +re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 +. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 +\d 匹配一个数字字符。等价于 [0-9]。 +\D 匹配一个非数字字符。等价于 [^0-9]。 +\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 +\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 +\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 +\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 +[Pp]ython 匹配 "Python" 或 "python" +rub[ye] 匹配 "ruby" 或 "rube" +[aeiou] 匹配中括号内的任意一个字母 +[0-9] 匹配任何数字。类似于 [0123456789] +[a-z] 匹配任何小写字母 +[A-Z] 匹配任何大写字母 +[a-zA-Z0-9] 匹配任何字母及数字 +[^aeiou] 除了aeiou字母以外的所有字符 +[^0-9] 匹配除了数字外的字符 +. 点 匹配单个任意字符 +[...] 字符组 匹配单个字符组出现的字符 +[^...] 排除型字符组 匹配单个未在字符组出现的字符 +\char 转义符 如果char是元字符或没有特殊含义, 则匹配char。 +? 问号 容许非必须的一次匹配 ++ 加号 匹配1次以上 +* 星号 匹配任意次 +{min,max} 区间量词 匹配min次到max次。 +^$ 脱字符和美元符 匹配一行文本的开头和结束。 +\b 边界符 匹配单词的边界 +| | 多选结构 +(...) 括号 用处有三,请看上面 +\1.\2 反向引用 对括号捕捉到的分组进行引用。 +括号 +如果需要使用分组,或者对一个分组进行量词限定,就可以使用它了。使用括号以后,可以: +在后面进行反向引用 +作为一个子表达式使用 +限制多选结构 +``` \ No newline at end of file diff --git "a/\347\254\224\350\256\260/vue\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/\347\254\224\350\256\260/vue\345\255\246\344\271\240\347\254\224\350\256\260.md" new file mode 100644 index 0000000..2cfd088 --- /dev/null +++ "b/\347\254\224\350\256\260/vue\345\255\246\344\271\240\347\254\224\350\256\260.md" @@ -0,0 +1,4 @@ +## vue学习笔记 +vue不是一个框架,它只是一个提供MVVM风格的双向数据库绑定的库,专注于UI层面。Vue提供的核心是MVVM中的VM,也就是viewModel,它负责连接View和Model。 +vue借鉴了angular和react的经验,使用了angular的双向绑定特性,Angular 的 directive 和 filter的概念,以及react组件化的概念,同时借鉴了两者的API。 +在Vue.js的定义中,View就是用户实际看到的DOM元素,而Model就是原生的JavaScript对象 diff --git "a/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220Koa.md" "b/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220Koa.md" new file mode 100644 index 0000000..d7c5132 --- /dev/null +++ "b/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220Koa.md" @@ -0,0 +1,192 @@ +半年前曾经写过一篇[Koa技术分享](https://cnodejs.org/topic/56936889c2289f51658f0926),当时写这篇文章的时候还在校园,实习期间接触一个Koa的项目,之后自己又写了一个[小项目](https://github.com/a1511870876/myblog),之后总结心得便有了上面这篇文章。半年的时间,忙于毕业和论文,git和文章都鲜有更新,如今毕业就业,再次接触Koa,再看这篇文章,感到当时的稚嫩,有很多地方没有考虑仔细,理解也不深入。怀着程序员严谨的精神,准备重写一篇Koa的技术分享。 + +tj的thunkify源码 +``` +/** + * Module dependencies. + */ +var assert = require('assert'); +/** + * Expose `thunkify()`. + */ +module.exports = thunkify; +/** + * Wrap a regular callback `fn` as a thunk. + * + * @param {Function} fn + * @return {Function} + * @api public + */ +function thunkify(fn){ + assert('function' == typeof fn, 'function required'); + return function(){ + //这里就是将所有的参数放进了一个新的数组,这里之所以不用[].slice。是因为有人在bluebird docs发现,如果直接这样泄露arguments,v8的一些优化的编译会被搁置,就会有性能上的损失。 + var args = new Array(arguments.length); + var ctx = this; + for(var i = 0; i < args.length; ++i) { + args[i] = arguments[i]; + } + return function(done){ + //这里用called是为了标记只执行了一次,类似于promise的resolve和reject只能执行一次一样。 + var called; + args.push(function(){ + if (called) return; + called = true; + //因为arguments是一个list,必须得用apply才能在done传入。 + done.apply(null, arguments); + }); + //这里用个try catch,可以在执行失败时走一遍callback,传入err信息 + try { + fn.apply(ctx, args); + } catch (err) { + done(err); + } + } + } +}; +``` +下面的是co源码的逐行阅读,先把参照的一些图片列举出来 +``` +//array原生的slice + var slice = Array.prototype.slice; + //这里写的这么古怪就只是想在es6的模块引入时更加舒服一些,参见下面的图片3 + module.exports = co['default'] = co.co = co; + //将传入的generator函数包装成一个返回promise的方法 + //这是一个独立的方法,就是将传入的函数包装成了co执行前的形式 + co.wrap = function (fn) { + //存了一个指针指向原generator函数 + createPromise.__generatorFunction__ = fn; + return createPromise; + function createPromise() { + //返回的方法调用就会直接执行co。 + return co.call(this, fn.apply(this, arguments)); + } + }; + //执行generator或者generator函数然后返回一个promise + function co(gen) { + var ctx = this; + var args = slice.call(arguments, 1) + // 将所有的东西放到一个promise里面,来防止引起内存泄露错误的promise chaining。 + //tudo:看一下这个issue see https://github.com/tj/co/issues/180 + //参见下面的内存泄露的研究 + //https://github.com/promises-aplus/promises-spec/issues/179 看的我好累,完全没有看懂啊!!! + //总之不管怎样,他是把传进来的东西包装成了一个promise + return new Promise(function(resolve, reject) { + //这里是判断下gen是不是函数,generators function执行之后是一个object + if (typeof gen === 'function') gen = gen.apply(ctx, args); + //传入的不是generators函数,没有next,就直接resolve返回结果;这里是错误兼容而已,因为co就是基于generator的,传入其他的没有意义 + if (!gen || typeof gen.next !== 'function') return resolve(gen); + //主要就是走下面的onFulfilled方法,这个方法返回的是一个promise(resolve或者reject) + onFulfilled(); + function onFulfilled(res) { + var ret; + try { + //调用第一次next方法 + ret = gen.next(res); + } catch (e) { + //出错了直接reject出去 + return reject(e); + } + //将第一次的结果({done:true,value:{}})传入内部方法next + next(ret); + } + //promise失败的时候调用 + //这里在promise错误的时候,就会尝试向外throw err。Genertor的属性,可以内部抛出,外部不活。如果我们对这个yield进行了try catch,就会被捕获,不处理的话,就会reject出去,在co的catch语句中co(*fn).catch处理。 + function onRejected(err) { + var ret; + try { + ret = gen.throw(err); + } catch (e) { + return reject(e); + } + next(ret); + } + //循环得到next的结果,return的还是一个promise + function next(ret) { + //如果done为true的话,代表执行结束,返回一个resolve的promise + if (ret.done) return resolve(ret.value); + //既然还没执行完,就将ret.value转换成一个promise + var value = toPromise.call(ctx, ret.value); + //如果成功转化为了promise,就在这个promise执行完了再调用onFulfilled方法 + if (value && isPromise(value)) return value.then(onFulfilled, onRejected); + return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + + 'but the following object was passed: "' + String(ret.value) + '"')); + } + }); + } + //将yield后面的东西转化成一个promise + function toPromise(obj) { + //如果不存在的话,直接返回,走最后的报错流程 + if (!obj) return obj; + //判断传入的是不是promise,是的话直接返回 + if (isPromise(obj)) return obj; + //判断传入的是不是generator,或者generator function,是的话,继续调用co函数进行循环~ + if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj); + //如果就是个普通的thunk函数,也把他转化为promise + if ('function' == typeof obj) return thunkToPromise.call(this, obj); + //如果是array或者object的话,也走相应地变换方法 + if (Array.isArray(obj)) return arrayToPromise.call(this, obj); + if (isObject(obj)) return objectToPromise.call(this, obj); + //如果都不是,直接返回,走最后的报错流程 + return obj; + } + //这里将thunk转化成了promise,thunk就是调用的时候传入一个error和res的function,就在最外面包了个promise就行了 + function thunkToPromise(fn) { + var ctx = this; + return new Promise(function (resolve, reject) { + fn.call(ctx, function (err, res) { + if (err) return reject(err); + if (arguments.length > 2) res = slice.call(arguments, 1); + resolve(res); + }); + }); + } + //这里的array转化为promise其实就是通过Promise.all来包裹,这个方法只接受promise的数组,并且装化为一个新的promise + //参见下面的promise平行执行的研究 + function arrayToPromise(obj) { + return Promise.all(obj.map(toPromise, this)); + } + //将一个object转化为promise,其实就是内部调用了promise.all方法而已 + function objectToPromise(obj){ + var results = new obj.constructor(); + var keys = Object.keys(obj); + var promises = []; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var promise = toPromise.call(this, obj[key]); + if (promise && isPromise(promise)) defer(promise, key); + else results[key] = obj[key]; + } + return Promise.all(promises).then(function () { + return results; + }); + function defer(promise, key) { + // predefine the key in the result + results[key] = undefined; + promises.push(promise.then(function (res) { + results[key] = res; + })); + } + } + //检查是否是promise,果然就是简单的判断他有没有then方法 + function isPromise(obj) { + return 'function' == typeof obj.then; + } + //这里判断是不是generator就是判断他的next和throw方法是不是function + function isGenerator(obj) { + return 'function' == typeof obj.next && 'function' == typeof obj.throw; + } + //判断是否是generatorFunction就是判断了他的constructor的name + function isGeneratorFunction(obj) { + var constructor = obj.constructor; + //这里是为了解决没有constructor的对象,比如Object.create(null) + if (!constructor) return false; + //这里两种情况会返回true,一种是名字正确地,一种是他的prototype是generator + if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true; + return isGenerator(constructor.prototype); + } + //就是通过constructor来判断是不是一个简单的对象 + function isObject(val) { + return Object == val.constructor; + } +``` \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220let\345\222\214const\345\234\250for\345\276\252\347\216\257\344\270\255\347\232\204\344\275\234\347\224\250\345\216\237\347\220\206.md" "b/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220let\345\222\214const\345\234\250for\345\276\252\347\216\257\344\270\255\347\232\204\344\275\234\347\224\250\345\216\237\347\220\206.md" new file mode 100644 index 0000000..48e6bb2 --- /dev/null +++ "b/\347\254\224\350\256\260/\346\267\261\345\205\245\345\211\226\346\236\220let\345\222\214const\345\234\250for\345\276\252\347\216\257\344\270\255\347\232\204\344\275\234\347\224\250\345\216\237\347\220\206.md" @@ -0,0 +1,53 @@ +# 深入剖析let/const在for循环中的作用原理 +```js +var a=[]; +for(var i = 0;i<3;i++){ + a[i]=function(){console.log(i)} +} +a[1](); //3 +``` +for循环执行过程伪代码如下: + +```js +var a=[] +var i = 0; + +if(i<3) { + a[i]=function(){console.log(i)} +} +i++; + +if(i<3) { + a[i]=function(){console.log(i)} +} +i++; + +if(i<3) { + a[i]=function(){console.log(i)} +} +i++; + +//a ==> [function(){console.log(i), function(){console.log(i), function(){console.log(i)}] + +//a[1] ==> function(){console.log(i) + +a[1](); // console.log(i) ==> 3 因为 i 现在的值是3 + +``` +console.log(i) ==> 3 因为 i 现在的值是3!这句话不对! +console.log(i) ==> 3 因为 i 现在的值是3!这句话不对! +console.log(i) ==> 3 因为 i 现在的值是3!这句话不对! + +而是块级作用域内并没有i,要去上一级作用域局部作用域中找,找到i,局部作用域中分 i现在的值是3。 + +如果把for循环的var换成let呢? + +```js +var a=[]; +for(var i = 0;i<3;i++){ + a[i]=function(){console.log(i)} +} +a[1](); //1 +``` +console.log(i)在其块级作用域内就找到了i,每次for循环把当前i值存入块级作用域。所以a[1]()会打印1; + diff --git "a/\347\254\224\350\256\260/\350\213\261\350\257\255\345\215\225\350\257\215.md" "b/\347\254\224\350\256\260/\350\213\261\350\257\255\345\215\225\350\257\215.md" new file mode 100644 index 0000000..0123997 --- /dev/null +++ "b/\347\254\224\350\256\260/\350\213\261\350\257\255\345\215\225\350\257\215.md" @@ -0,0 +1,181 @@ +
+#### instance +实例 instanceof A instanceof B :检测B.prototype是否存在于参数A的原型链上. +#### type +类型 +#### Iterator +指针对象 +#### Iterable +遍历器 +#### Slice +片 切片 arr.slice(start,end)切片数组 不会改变原始数组,返回一个子数组 +#### splice +拼接 arr.splice(index,num,item1,...,itemN) 方法向/从数组中添加/删除项目,然后返回被删除的项目。该方法会改变原始数组。 +#### split +split() 方法用于把一个字符串分割成字符串数组。 +#### concat +连接 +#### proxy +代理 +#### global +全球/全局 +#### window +不是windows。js默认指向浏览器对象也就是window.name='gloableName'; +#### transfer +合同 +#### fix +固定 +#### parse +解析。JSON.parse(str) 把字符串解析出json对象 +#### stringify +字符串化 JSON.stringify() 从对象中解析出字符串 +#### TODO +待办事项; 备忘录; +#### Model +模型 数据模型 view/controller +#### overflow +清除浮动`.clearfix{ overflow : auto; zoom: 1 }` +#### directive +指示/指令 +#### attribute +属性 Attribute表示属性,指对象(Object)的特征(Feature)翻译成中文术语为“特性” +#### property +属性 翻译成中文术语为“属性” +为了更好的区分attribute和property,基本可以总结为attribute节点都是在HTML代码中可见的,而property只是一个普通的名值对属性。 +``` +// gameid和id都是attribute节点 +// id同时又可以通过property来访问和修改 +
hello
+// areaid仅仅是property +elem.areaid = 900; +``` +#### prototype +原型 每一个基本对象都有自己的_proto_属性,而每一个函数对象都有自己的prototype原型(函数对象也属于基本对象,所以也有_proto_),每当去定义一个prototype的时候,就相当于把该实例的__proto__指向一个结构体,那么这个被指向结构体就称为该实例的原型。 +#### Member Variable +成员变量 +#### Field +字段 +#### method +方法 +#### operator +操作 +#### highlight +高亮 +#### merge +合并 +#### modified +改变 +#### repository [rɪ'pɒzɪt(ə)rɪ] +仓库 +#### detected [dɪ'tektɪd] +发现/发觉 +#### conflicts ['kɑnflɪkts] +冲突 +#### graph [ɡrɑ:f, ɡræf] +曲线/曲线图 +#### branch +分支 git中查看分支:git branch 创建分支:git branch `` 切换分支:git checkout ``合并分支:git merge `` 删除分支:git branch -d `` 创建并切换分支:git checkout -b `` 查看日志曲线:git log --graph +#### sourse +资源 +#### entries +entry的复数 进入/词目 +#### Array +Array.from()把类似数组和Iterable对象转换为数组 Array.of()把多个静态数值转换为数组 +#### arrow +箭头 Arrow function 箭头函数 +#### option +选项 +#### rest +休息/剩余部分/支架 ...rest 得到的是一个真正的数组而不是一个伪数组 +#### apply/call +apply和call都是接受参数改变this指针的指向,arguments,得到的是一个伪数组,且为全部参数。 +#### Calculator ['kælkjuletɚ] +计算器 +#### buffer +缓冲区 +#### sheet +薄片/纸张 +#### duration [du'reʃən] +持续/时长 +#### periods [pɪərɪədz] +周期(period的复数) +#### Uniform Resource Locater ['ju:nifɔ:m],['risɔrs],[ləu'keitə] +统一资源定位符 local本地 location位置 +#### Uniform Resource Identifier [aɪˈdɛntɪˌfaɪ] +统一资源标识符 +关系: +URI 属于 URL 更低层次的抽象,一种字符串文本标准。 +就是说,URI 属于父类,而 URL 属于 URI 的子类。URL 是 URI 的一个子集。 +二者的区别在于,URI 表示请求服务器的路径,定义这么一个资源。而 URL 同时说明要如何访问这个资源(http://)。 +#### origin /ˈɒrɪdʒɪn/ +起源/原点 +#### constants +常量 +#### remote +遥远的远程的 +#### content +内容 +#### count +数量 +#### starter ['stɑ:tə] +发动机/发动者 +#### rhythm /ˈrɪðəm/ +节奏/韵律 +#### orient ['orɪənt] +使适应 +#### resolved +已完成 resolve [rɪ'zɒlv] 解决 +#### rejected +已失败 reject [rɪ'dʒekt] 拒绝 +#### pending +进行中,未决定的,未发生的 pend [pend] 推迟对…的决定;使悬而不决 +#### underway ['ʌndə'weɪ] +adj. 进行中的;起步的;航行中的 +#### fetch [fetʃ] +取来/拿/取得 +#### thunk [θʌŋk] +n. 形实转换程序 +#### params +参数 +#### arguments +参数 +#### thunkify +英语中的"ify"后缀是使……变得……的意思】只是一种普遍的现象,却不是一种普适的语法规则,所以identify( 确定;鉴定;识别)并没有使用这种后缀.(例如 stringify) +#### ident ['aɪdɛnt] +n. 识别,鉴别 +#### preface ['prefəs] +n. 前言;引语 vt. 为…加序言;以…开始 +#### specified [ˈspesɪfaɪd] +adj. 规定的;详细说明的 v. 指定;详细说明(specify的过去分词) +#### configurable +可配置的 config n. 配置 configure vt. 配置/使成型 +#### enum +枚举类型 enumer types枚举类型 enumerable 可枚举的 +#### descriptor [dɪ'skrɪptə] +n. 描述符号 descript vt. 描述 +#### staff [sta:f] +职员 +#### quote [kwəʊt] +vt. 报价;引述;举证 vi. 报价;引用;引证 n. 引用 +#### semicolon ['sɛmɪkolən] +n. 分号 +#### format ['fɔːmæt] +n. 格式;版式;开本 vt. 使格式化;规定…的格式 vi. 设计版式 +#### wrap [ræp] +vt. 包;缠绕;隐藏;掩护 vi. 包起来;缠绕;穿外衣 n. 外套;围巾 +#### emitter [ɪ'mɪtə] +n. 发射器,发射体 +#### utility [juːˈtɪlɪtɪ] +n. 实用;效用;公共设施;功用 adj. 实用的;通用的;有多种用途的 +#### parenthese +括号;圆括号 +#### instance +实例 +#### fulfilled [fʊl'fɪld] +adj. 满足的;十分愉快的 v. 实现(fulfill的过去分词);履行;满足 +#### workflow +工作流 +#### chain +链 +#### token +n. 表征;代币;记号 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\350\256\251\344\275\240\347\232\204 Node.js \345\272\224\347\224\250\350\267\221\345\276\227\346\233\264\345\277\253\347\232\204 10 \344\270\252\346\212\200\345\267\247.md" "b/\347\254\224\350\256\260/\350\256\251\344\275\240\347\232\204 Node.js \345\272\224\347\224\250\350\267\221\345\276\227\346\233\264\345\277\253\347\232\204 10 \344\270\252\346\212\200\345\267\247.md" new file mode 100644 index 0000000..c5f5d5d --- /dev/null +++ "b/\347\254\224\350\256\260/\350\256\251\344\275\240\347\232\204 Node.js \345\272\224\347\224\250\350\267\221\345\276\227\346\233\264\345\277\253\347\232\204 10 \344\270\252\346\212\200\345\267\247.md" @@ -0,0 +1,108 @@ +### 让你的 Node.js 应用跑得更快的 10 个技巧 +引用地址:[http://www.oschina.net/translate/10-tips-make-node-js-web-app-faster](http://www.oschina.net/translate/10-tips-make-node-js-web-app-faster) +英文原文:[http://www.sitepoint.com/10-tips-make-node-js-web-app-faster](http://www.sitepoint.com/10-tips-make-node-js-web-app-faster) +个人技术分享GitHub地址:[https://github.com/a1511870876/studyFiles](https://github.com/a1511870876/studyFiles) + +  Node.js 受益于它的事件驱动和异步的特征,已经很快了。但是,在现代网络中只是快是不行的。如果你打算用 Node.js 开发你的下一个Web 应用的话,那么你就应该无所不用其极,让你的应用更快,异常的快。本文将介绍 10 条,经过检验得知可大大提高 Node 应用的技巧。废话不多说,让我们逐条来看看。 +### 1. 并行 +  创建 Web 应用的时候,你可能要多次调用内部 API 来获取各种数据。比如说,假设在 Dashboard 页面上,你要执行下面这几个调用: +  用户信息 -getUserProfile(). +  当前活动 -getRecentActivity(). +  订阅内容 -getSubscriptions(). +  通知内容 -getNotifications(). +  为了拿到这些信息,你应该会为每个方法创建独立的中间件,然后将它们链接到 Dashboard 路由上。不过问题是,这些方法的执行是线性的,上一个没结束之前下一个不会开始。可行解决案是并行调用它们。 +  如你所知由于异步性,Node.js 非常擅长并行调用多个方法。我们不能暴殄天物。我上面提到的那些方法没有依赖性,所以我们可以并行执行它们。这样我们可以削减中间件数量,大幅提高速度。 +  我们可以用 async.js 来处理并行,它是一个专门用来调教 JavaScript 异步的 Node 模块。下面代码演示怎样用 async.js 并行调用多个方法的: +``` +function runInParallel() { + async.parallel([ + getUserProfile, + getRecentActivity, + getSubscriptions, + getNotifications + ], function(err, results) { + //This callback runs when all the functions complete + }); +} +``` +  如果你想更深入了解 async.js ,请移步它的 GitHub 页面。 +### 2. 异步 +  根据设计 Node.js 是单线程的。基于这点,同步代码会堵塞整个应用。比如说,多数的文件系统 API 都有它们的同步版本。下面代码演示了文件读取的同步和异步两种操作: +``` +// Asynchronous +fs.readFile('file.txt', function(err, buffer) { + var content = buffer.toString(); +}); +// Synchronous +var content = fs.readFileSync('file.txt').toString(); +``` +  不过要是你执行那种长时间的阻塞操作,主线程就会被阻塞到这些操作完成为止。这大大降低你应用的性能。所以,最好确保你的代码里用的都是异步版本 API,最起码你应该在性能节点异步。而且,你在选用第三方模块的时候也要很小心。因为当你想方设法把同步操作从你代码中剔除之后,一个外部库的同步调用会让你前功尽弃,降低你的应用性能。 +### 3. 缓存 +  如果你用到一些不经常变化的数据,你应该把它们缓存起来,改善性能。比如说,下面的代码是获取最新帖子并显示的例子: +``` +var router = express.Router(); +router.route('/latestPosts').get(function(req, res) { + Post.getLatest(function(err, posts) { + if (err) { + throw err; + } + res.render('posts', { posts: posts }); + }); +}); +``` +  如果你不经常发贴的话,你可以把帖子列表缓存起来,然后一段时间之后再把它们清理掉。比如,我们可以用 Redis 模块来达到这个目的。当然,你必须在你的服务器上装 Redis。然后你可以用叫做 node_redis 的客户端来保存键/值对。下面的例子演示我们怎么缓存帖子: +``` +var redis = require('redis'), + client = redis.createClient(null, null, { detect_buffers: true }), + router = express.Router(); +router.route('/latestPosts').get(function(req,res){ + client.get('posts', function (err, posts) { + if (posts) { + return res.render('posts', { posts: JSON.parse(posts) }); + } + Post.getLatest(function(err, posts) { + if (err) { + throw err; + } + client.set('posts', JSON.stringify(posts)); + res.render('posts', { posts: posts }); + }); + }); +}); +``` +  看到了吧,我们首先检查 Redis 缓存,看看是否有帖子。如果有,我们从缓存中拿这些帖子列表。否则我们就检索数据库内容,然后把结果缓存。此外,一定时间之后,我们可以清理 Redis 缓存,这样就可以更新内容了。 +### 4. gzip 压缩 +  开启 gzip 压缩对你的 Web 应用会产生巨大影响。当一个 gzip 压缩浏览器请求某些资源的时候,服务器会在响应返回给浏览器之前进行压缩。如果你不用 gzip 压缩你的静态资源,浏览器拿到它们可能会花费更长时间。 +  在 Express 应用中,我们可以用内建 express.static() 中间件来处理静态内容。此外,还可以用 compression 中间件压缩和处理静态内容。下面是使用例: +``` +var compression = require('compression'); +app.use(compression()); //use compression +app.use(express.static(path.join(__dirname, 'public'))); +``` +### 5. 如果可以,在用客户端渲染 +  现在有超多功能强劲的客户端 MVC/MVVM 框架,比如说 AngularJS, Ember, Meteor, 等等,构建一个单页面应用变得非常简单。基本上,你只要公开一个 API,返回 JSON 响应给客户端就可以了,而不需要在服务端渲染页面。在客户端,你可以用框架来组织 JSON 然后把它们显示在 UI 上。服务端只发送 JSON 响应可以节省带宽,改善性能,因为你不需要在每个响应里面都返回布局标记了,对吧,你只需要返回纯 JSON,然后在客户端渲染它们。 +  看下我的这个教程,它是关于怎样用 Express 4 公开一个 RESTful APIs的。我还写了另一篇教程,演示了怎样把这些 APIs 和 AngularJS 结合起来。 +### 6. 不要在 Sessions 存储太多数据 +  典型的 Express 页面应用, Session 数据默认是保存在内存中的。当你把太多数据保存在 Session 的时候,会导致服务器开销显著增大。所以,要么你切换到别的储存方式来保存 Session 数据,要么尽量减少存储在 Session 中的数据量。 +  比如说,当用户登录到你的应用的时候,你可以只在 Session 中保存他们的 ID 而不是整个用户数据对象。还有,对于那些你能够从 id 拿到对象的查询,你应该会喜欢用 MongoDB 或者 Redis 来存储 session 数据。 +### 7. 优化查询 +  假设你有个博客,你要在主页上显示最新帖子。你可能会通过 Mongoose 这样取数据: +``` +Post.find().limit(10).exec(function(err, posts) { + //send posts to client +}); +``` +  不过问题是 Mongoose 的 find() 方法会把对象的所有字段都查询出来,而许多字段在主页上并不要求。比如说,commentsis 保存的是特定帖子的回复。我们不需要显示文章回复,所以我们可以在查询的时候把它给剔除掉。这无疑会提高速度。可以像这样优化上面那条查询: +``` +Post.find().limit(10).exclude('comments').exec(function(err, posts) { + //send posts to client +}); +``` +### 8. 用标准的 V8 方法 +  集合上的一些操作,比如 map,reduce,和 forEach 不一定支持所有浏览器。我们可以通过前台的库解决部分浏览器兼容性问题。但对于 Node.js,你要确切知道 Google 的 V8 JavaScript 引擎支持哪些操作。这样,你就可以在服务端直接用这些内建方法来操作集合了。 +### 9. 在 Node 前面用 Nginx +  Nginx 是个微小型轻量 Web 服务器,用它可以降低你的 Node.js 服务器的负载。你可以把静态资源配置到 nginx 上,而不是在 Node 上。你可以在 nginx 上用 gzip 压缩响应,让所有的响应都变得更小。所以,如果你有个正在营运的产品,我觉得你应该会想用 nginx 来改善运行速度的。 +### 10. 打包 JavaScript +  最后,你还可以大大提高页面应用速度,通过把多个 JS 文件打包。当浏览器在页面渲染中碰到 元素的时候会被堵塞,直到拿到这个脚本才继续运行(除非设置了异步属性)。比如,如果你的页面有五个 JavaScript 文件,浏览器会发出五个独立的 HTTP 请求来获取他们。如果把这五个文件压缩打包成一个,整体性能将可以大幅提升。CSS 文件也是一样。你可以用诸如 Grunt/Gulp 这样的编译工具来打包你的资源文件。 +### 结论 +  上面 10 条技巧肯定可以提高你的 Web 应用的速度的。不过,我知道还有改善和优化的空间。如果你有任何改善性能的技巧的话,在回复里告诉我。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\350\267\250\345\237\237.md" "b/\347\254\224\350\256\260/\350\267\250\345\237\237.md" new file mode 100644 index 0000000..4cc1bb8 --- /dev/null +++ "b/\347\254\224\350\256\260/\350\267\250\345\237\237.md" @@ -0,0 +1,68 @@ +一是通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了。 + +二是通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器: +``` +'/proxy?url=http://www.sina.com.cn' +``` +代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发。 + +第三种方式称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源: + +`` +`` +`` +`` +`` +`` +`` + + +JSONP通常以函数调用的形式返回,例如,返回JavaScript内容如下: + +`foo('data');` +这样一来,我们如果在页面中先准备好foo()函数,然后给页面动态加一个节点,相当于动态读取外域的JavaScript资源,最后就等着接收回调了。 + +以163的股票查询URL为例,对于URL:http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice,你将得到如下返回: + +`refreshPrice({"0000001":{"code": "0000001", ... });` +因此我们需要首先在页面中准备好回调函数: +``` +function refreshPrice(data) { + var p = document.getElementById('test-jsonp'); + p.innerHTML = '当前价格:' + + data['0000001'].name +': ' + + data['0000001'].price + ';' + + data['1399001'].name + ': ' + + data['1399001'].price; +} +``` +当前价格: + +刷新 + +最后用getPrice()函数触发: +``` +function getPrice() { + var + js = document.createElement('script'), + head = document.getElementsByTagName('head')[0]; + js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice'; + head.appendChild(js); +} +``` +就完成了跨域加载数据。 + +CORS + +如果浏览器支持HTML5,那么就可以一劳永逸地使用新的跨域策略:CORS了。 + +CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。 + +了解CORS前,我们先搞明白概念: + +Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。 + +可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。 + +上面这种跨域请求,称之为“简单请求”。简单请求包括GET、HEAD和POST(POST的Content-Type类型 +仅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求。 \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\350\276\223\345\205\245\347\275\221\345\235\200\345\220\216\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210.md" "b/\347\254\224\350\256\260/\350\276\223\345\205\245\347\275\221\345\235\200\345\220\216\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210.md" new file mode 100644 index 0000000..05ea6da --- /dev/null +++ "b/\347\254\224\350\256\260/\350\276\223\345\205\245\347\275\221\345\235\200\345\220\216\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210.md" @@ -0,0 +1,96 @@ +# 输入网址之后发生了什么 # +## 1.首先是输入网址 ## +  以www.facebook.com为例 +## 2.浏览器查找域名对应IP ## +### 2.1 DNS查找过程: +  浏览器缓存——浏览器会记录DNS一段时间(2-30分钟不等,视浏览器而定) +  系统缓存——浏览器里没找到DNS缓存,此事浏览器做一个系统调用(window下是gethostbyname)。如发现匹配则采用。(与此对应有host恶意劫持更改攻击) +  路由器缓存——路由器也会有DNS缓存(缓存你上过的网站,所以有时路由器需要进行DNS刷新) +  ISP DNS缓存——接下来是在ISP(互联网服务提供商)的DNS服务器的缓存上查找。 +  递归查找——DNS缓存里没有的话,ISP DNS服务器会先后从根域名服务器(root)、.com顶级域名服务器、Facebook域名服务器获取IP(一般缓存内都会有,所以这一步一般不会发生) +### 2.2 多IP域名DNS查询解决方案 +  循环DNS——单个域名、多个IP列表循环应对DNS查询 +  负载均衡器——一个特定IP的负载均衡服务器(例如:反向代理服务器)负责监听请求并转发给后面的多个服务器集群的某一个,实现多个服务器负载均衡 +  地理DNS——根据用户所处地理位置,返回不同的IP(应用:CDN) +  anycast——一个IP地址映射多个物理主机的路由技术 +## 3.发送请求 + +  得到域名对应的IP后,就开始发送HTTP(S)请求了. +  请求头详解: +  GET [http://facebook.com/](http://facebook.com/) HTTP/1.1 +  Accept: application/x-ms-application, image/jpeg, application/xaml+xml, [...] +  User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; [...] +  Accept-Encoding: gzip, deflate +  Connection: Keep-Alive +  Host: facebook.com +  Cookie: datr=1265876274-[...]; locale=en_US; lsd=WW[...]; c_user=2101[...] + +  请求告诉服务器: +  1. 我要获取(GET) [http://facebook.com/](http://facebook.com/) (GET的URL)这个页面 +  2. Accept:我能接受这些类型的文件 +  3. 我使用的是何种操作系统上的哪个类型那个版本的浏览器 +  4. 承认接受何种方式的压缩文件 +  5. 连接类型:短连接?长连接? +  6. 主机域名 +  7. 发送存储在本机的cookies信息给服务器 + +  除了发送获取请求,还能发送提交响应请求(如:搜索时要把搜索的内容一并发给服务器进行处理(在请求URL后面增加特定的用户参数),以获取特定的内容) +  注意:URL后面加斜杠与不加斜杠的区别(文件夹与单个文件的区别) +  [http://www.facebook.com](http://facebook.com) +  [http://www.facebook.com/](http://facebook.com/) +  当我们输入[http://www.facebook.com](http://facebook.com) 时,浏览器会自动添加斜杠,保证URL的严谨。 +  当我们输入:[http://www.facebook.com/folderOrFile](http://www.facebook.com/folderOrFile) 时,因为浏览器不清楚folderOrFile到底是文件夹还是文件,所以不能自动添加 斜杠。这时,浏览器就不加斜杠直接访问地址,服务器会响应一个重定向,结果造成一次不必要的握手。 +## 4.重定向 +  当我们输入不完整的网址[http://www.facebook.com](http://facebook.com) 时,或者网站迁移做了重定向设置时,服务器会进行一次重定向响应。 +  下面是重定向之后返回的响应头: +  HTTP/1.1 301 Moved Permanently +  Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,pre-check=0 +  Expires: Sat, 01 Jan 2000 00:00:00 GMT +  Location: [http://www.facebook.com/](http://facebook.com/) +  P3P: CP="DSP LAW" +  Pragma: no-cache +  Set-Cookie: made_write_conn=deleted; expires=Thu, 12-Feb-2009 05:09:50 GMT; +  path=/; domain=.facebook.com; httponly +  Content-Type: text/html; charset=utf-8 +  X-Cnection: close +  Date: Fri, 12 Feb 2010 05:09:51 GMT +  Content-Length: 0 + +  1. 301 永久重定向 +  2. 新的Location:…… + +  为什么要重定向,而不直接返回用户想看的内容呢?(既然服务器已经经过重定向知道了用户需要什么) + +  答:原因之一:与搜索引擎排名有关。你看,如果一个页面有两个地址,就像[http://www.igoro.com/](http://www.igoro.com/) 和[http://igoro.com/](http://igoro.com/),搜索引擎会认为它们是两个网站,结果造成每一个的搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是 什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。 +## 5.新的请求 +  重定向之后会发布一个新的获取请求 +## 6.服务器处理请求 +### 6.1 web服务器软件 +  服务器操作系统种类:Linux(一般是厂家根据开源定制)、windows server系列(微软) +  主要的服务器软件:IIS、Apache、Tomcat、JBOSS、Nginx、lighttpd、Tetty +  服务器软件的作用:接收、处理与响应请求(了解CGI的作用) +### 6.2 处理流程: +  web服务器软件(如IIS或者Apache)接收到HTTP请求 +  确定执行那个请求处理程序(一个能读懂请求并且能生成HTML来进行响应的程序)(例如:Asp.Net,PHP,RUBY……)来处理它 +  请求处理器阅读请求头的参数和cookies信息 +  更新服务器上的信息:例如更新数据库信息、服务端cookies +  生成HTML,压缩(gzip或其他),响应请求发送给用户 +## 7.服务器发回一个HTML响应 +  响应包括响应头(响应参数与信息)、响应包(主体文件) +  响应包采用特定方法压缩,整个响应以blob类型传输,响应头指示响应包以何种方式压缩 +  这个响应头与重定向的响应头不太一样,这个响应头还包含着缓存选项,cookies设置和隐私信息等 +## 8.浏览器开始显示HTML +  浏览器在没有完整接收全部HTML文件,就已经开始显示页面了 +## 9.浏览器获取其他文件 +  浏览器解析HTML遇到需要下载的文件时,便再次向服务器(CDN)发送获取文件的请求。 +  注意: +  1. 动态页面无法缓存,静态文件允许浏览器进行缓存。 +  2. 静态文件本地有缓存时直接从本地读取 +  3. 请求响应头内包含着静态文件保存的期限,浏览器知道下载的静态文件要静默保留多久。 +  4. 响应头还会有静态文件的ETag(相当于版本号),当浏览器发现请求的静态文件的响应头的ETag与现有的缓存文件不符时,便会再次向服务器获取静态文件。 +## 10.浏览器发送异步(AJAX)请求 +  web 2.0的一大特征就是页面显示完全后客户端仍旧与服务器端保持联系(keep-alive) +  浏览器执行特定的JS代码会给服务器发送异步请求,获取最新的动态消息,使得页面能保持较新的状态。 +  HTTP是一个请求-响应协议,只有在客户端发送请求,服务器端才能做出响应,而不能主动把消息或者文档发给客户所以,要想保持页面处于最新的状态,需要定时进行轮询(定时发送AJAX请求以更新页面内容) +  AJAX请求十分容易更改,且用户十分容易自己制造和发送AJAX请求,所以没有验证码的没有IP限制条件的投票就是一个小游戏了(参照工作室两次刷票:自己定义IP,自己定时发送AJAX请求,然后票就哗哗的上了)。 +  优化小方案:如果服务器被轮询时没有新消息,它就不理这个客户端。而当请求尚未超时的情况下如果收到了该客户的新消息,服务器就找到未完成的请求,把新消息作为响应发送给客户端(这样就无需频繁地响应请求了) \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\351\207\215\345\255\246JS.md" "b/\347\254\224\350\256\260/\351\207\215\345\255\246JS.md" new file mode 100644 index 0000000..c8e1f62 --- /dev/null +++ "b/\347\254\224\350\256\260/\351\207\215\345\255\246JS.md" @@ -0,0 +1,76 @@ +# 重学JS # +## 1、'use strict'; ## +在strict模式下运行的JavaScript代码,强制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。 +## 2、字符串 ## +- toUpperCase()把一个字符串全部变为大写; +- toLowerCase()把字符串全部变为小写; +- indexOf()会搜索指定字符串第一次出现的位置,并返回下标,没找到返回-1; +- substring(0,5);回指定索引区间的子串; +## 3、数组 ## +1. arr.length; +取得数组的长度,请注意,直接给Array的length赋一个新的值会导致Array大小的变化: +2. Array索引 +可以通过索引把对应的元素修改为新的值,请注意,如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化。 +3. indexOf() +用法类似字符串。 +4. slice() +就是对应String的substring()版本,它截取Array的部分元素,然后返回一个新的Array,只传递一个参数,会截取该参数到数组末尾的所有元素,不传递参数截取全部元素==复制数组。 +5. push()和pop() +push()是向array末尾添加若干元素,pop()是把array最后一个元素删除掉。 +6. unshift和shift +和push()和pop()相反,unshift向array头部添加若干元素,shift()是把array第一个元素删除掉。 +7. sort +对array进行排序它会直接修改当前Array的元素位置 +8. reverse +反转数组 +9. splice +方法是修改Array的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素。 +``` +arr.splice(2, 3, 'Google', 'Facebook'); +// 从索引2开始删除3个元素,然后再添加两个元素: +// 从索引2开始删除3个元素,然后再添加两个元素: +``` +10. concat +拼接数组,并返回一个新的数组,不修改原数组。 +11. join +join()方法是一个非常实用的方法,它把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串: +``` +var arr = ['A', 'B', 'C', 1, 2, 3]; +arr.join('-'); // 'A-B-C-1-2-3' +``` +练习:在新生欢迎会上,你已经拿到了新同学的名单,请排序后显示:欢迎XXX,XXX,XXX和XXX同学!: +``` +'use strict'; +var arr = ['小明', '小红', '大军', '阿黄']; +alert('欢迎'+arr.sort().slice(0, arr.length-1) +'和'+arr.pop()+'同学'); +``` +## 4、对象 ## +对象是一种无序的集合数据类型,它由若干键值对组成。 + +1. 由于JavaScript的对象是动态类型,你可以自由地给一个对象添加或删除属性: +``` +var xiaoming = { + name: '小明' +}; +xiaoming.age; // undefined +xiaoming.age = 18; // 新增一个age属性 +xiaoming.age; // 18 +delete xiaoming.age; // 删除age属性 +xiaoming.age; // undefined +delete xiaoming['name']; // 删除name属性 +xiaoming.name; // undefined +delete xiaoming.school; // 删除一个不存在的school属性也不会报错 +``` +2. in操作符 +检查object是否拥有某一属性(key) +## 5、判断 ## +avaScript使用if () { ... } else { ... }来进行条件判断。 +如果if的条件判断语句结果不是true或false怎么办?例如: +``` +var s = '123'; +if (s.length) { // 条件计算结果为3 + // +} +``` +JavaScript把null、undefined、0、NaN和空字符串''视为false,其他值一概视为true,因此上述代码条件判断的结果是true。 +## 6、Map和Set ## \ No newline at end of file diff --git "a/\347\254\224\350\256\260/\351\207\215\345\255\246html+css+js.md" "b/\347\254\224\350\256\260/\351\207\215\345\255\246html+css+js.md" new file mode 100644 index 0000000..d6799f1 --- /dev/null +++ "b/\347\254\224\350\256\260/\351\207\215\345\255\246html+css+js.md" @@ -0,0 +1,138 @@ +## Html ## +``` +1、短文本引用,自动加双引号,语义是引用。 +2、
长文本引用,自动两端缩进。 +3、

为换行, 为空格,
为水平横线。 +4、
地址。 +5、当代码为一行代码时,你就可以使用标签了。 +6、
语言代码段,多行。
+7、,
+8、click here!新建浏览器窗口中打开链接。
+9、发送
+(第一个参数用?隔开后边参数用&隔开,cc:抄送。Bcc:密抄送。Subject:标题。Body:内容)
+10、” src为图片地址;alt为下载不成功时描述性文本;title为图像可见时图像的描述。
+11、
+12、文本域。
+13、单选框、复选框。同一组的单选按钮,name 取值一定要一致,这样同一组的单选按钮才可以起到单选的作用。
+14、下拉框。multiple="multiple"使用下拉列表框进行多选。
+15、按钮,重置按钮。
+16、
标题文本
、 +常用的内联元素有: +