├── images ├── readme.md ├── eventloop.png ├── InterviewMap.png ├── T7$DI(QWJ)VK)QBTNCUZF34.png ├── 2c3151c5fe2669ff242614c04de86ef0_672x532.png ├── 67aa2ba68d8dac054c77a1b41e798c68_467x324.png ├── fa84428874feeb553665b291bac30b70_300x297.png └── e17edc7ae0617a002b2d77ef1d26ad4a_1057x372.png ├── JavaScript ├── 严格模式.md ├── event-loop.md ├── 原型与继承.md ├── 作用域、作用域链与闭包.md ├── 基础概念.md ├── this.md ├── 模块化规范.md ├── DOM-操作技术.md ├── 实用的几个 DOM 操作技巧.md ├── DOM-概念及API.md └── 数组、字符串、Map、Set方法整理.md ├── 服务器 ├── node.js │ ├── 操作数据库.md │ ├── 深入浅出node.js-part1.md │ ├── 深入浅出 node.js-part2(网络编程).md │ └── 深入浅出 node.js-part3.md ├── OS 基础知识.md ├── Nginx.md └── Linux 基础.md ├── CSS ├── 常见问题2.md ├── 常见问题1.md └── CSS Secrets-P1.md ├── Vue └── 书写规范.md ├── README.md ├── React └── 书写规范.md ├── Safety └── Safety.md ├── DataStruct ├── DataStruct.md └── Tree.md ├── Browser └── Browser.md └── 面试题 └── 面试题精选1.md /images/readme.md: -------------------------------------------------------------------------------- 1 | 存图片 2 | -------------------------------------------------------------------------------- /images/eventloop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/eventloop.png -------------------------------------------------------------------------------- /images/InterviewMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/InterviewMap.png -------------------------------------------------------------------------------- /images/T7$DI(QWJ)VK)QBTNCUZF34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/T7$DI(QWJ)VK)QBTNCUZF34.png -------------------------------------------------------------------------------- /images/2c3151c5fe2669ff242614c04de86ef0_672x532.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/2c3151c5fe2669ff242614c04de86ef0_672x532.png -------------------------------------------------------------------------------- /images/67aa2ba68d8dac054c77a1b41e798c68_467x324.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/67aa2ba68d8dac054c77a1b41e798c68_467x324.png -------------------------------------------------------------------------------- /images/fa84428874feeb553665b291bac30b70_300x297.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/fa84428874feeb553665b291bac30b70_300x297.png -------------------------------------------------------------------------------- /images/e17edc7ae0617a002b2d77ef1d26ad4a_1057x372.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenMingK/Blog/HEAD/images/e17edc7ae0617a002b2d77ef1d26ad4a_1057x372.png -------------------------------------------------------------------------------- /JavaScript/严格模式.md: -------------------------------------------------------------------------------- 1 | 除了正常运行模式,ECMAscript 5 添加了第二种运行模式:”严格模式”(strict mode)。顾名思义,这种模式使得 Javascript 在更严格的条件下运行。 2 | 3 | 严格模式主要有以下限制: 4 | 5 | 1.变量必须声明后再使用 6 | 7 | 2.函数的参数不能有同名属性,否则报错 8 | 9 | 3.不能使用 with 语句 10 | 11 | 4.不能对只读属性赋值,否则报错 12 | 13 | 5.不能使用前缀 0 表示八进制数,否则报错 14 | 15 | 6.不能删除不可删除的属性,否则报错 16 | 17 | 7.不能删除变量 delete prop,会报错,只能删除属性 delete global[prop] 18 | 19 | 8.eval 不会在它的外层作用域引入变量 20 | 21 | 9.eval 和 arguments 不能被重新赋值 22 | 23 | 10.arguments 不会自动反映函数参数的变化 24 | 25 | 11.不能使用`arguments.callee` 26 | 27 | 12.不能使用`arguments.caller` 28 | 29 | 13.禁止 this 指向全局对象 30 | 31 | 14.不能使用 fn.caller 和 fn.arguments 获取函数调用的堆栈 32 | 33 | 15.增加了保留字(比如 protected、static 和 interface) 34 | 35 | ***** 36 | 37 | 设立”严格模式”的目的,主要有以下几个: 38 | 39 | 1.消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为; 40 | 41 | 2.消除代码运行的一些不安全之处,保证代码运行的安全; 42 | 43 | 3.提高编译器效率,增加运行速度; 44 | 45 | 4.为未来新版本的 Javascript 做好铺垫。 46 | 47 | 进入”严格模式”的标志,是下面这行语句:`"use strict"` 48 | -------------------------------------------------------------------------------- /服务器/node.js/操作数据库.md: -------------------------------------------------------------------------------- 1 | # mysql 操作 2 | ## 安装 mysql 模块 3 | - `cnpm install mysql` 4 | - `const mysql = require('mysql')` 5 | 6 | ## 建立数据库连接 7 | ```js 8 | // 连接数据库 9 | function connect() { 10 | return mysql.createConnection({ 11 | // 这里将常量统一维护在constant对象中 12 | host: constant.dbHost, // ip 13 | user: constant.dbUser, // mysql用户名 14 | password: constant.dbPwd, // mysql密码 15 | database: 'book' // 数据库名 16 | }) 17 | } 18 | const conn = connect() 19 | 20 | ``` 21 | 或者 22 | ```js 23 | const mysql = require('mysql') 24 | let connection = mysql.createConnection({ 25 | host: 'localhost', 26 | user: 'root', 27 | password: '123456', 28 | database: 'test' 29 | }) 30 | connection.connect() 31 | connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { 32 | if (error) throw error 33 | console.log(' The solution is: ', results[0].solution) 34 | }) 35 | ``` 36 | ## 增、删、查、改 37 | ### 查询数据 38 | step1:建立连接 39 | step2:创建 sql 语句字符串 40 | step3: 41 | ```js 42 | conn.query(sql, (err, results) => { 43 | if(err) { } 44 | else { } 45 | }) 46 | ``` 47 | ```js 48 | app.get('/book/detail', (req, res) => { 49 | const conn = connect() 50 | const fileName = req.query.fileName 51 | const sql = `select * from book where fileName='${fileName}'` 52 | conn.query(sql, (err, results) => { 53 | if (err) { 54 | res.json({ 55 | error_code: 1, 56 | msg: '电子书详情获取失败' 57 | }) 58 | } else { 59 | if (results && results.length === 0) { 60 | res.json({ 61 | error_code: 1, 62 | msg: '电子书详情获取失败' 63 | }) 64 | } else { 65 | const book = handleData(results[0]) 66 | res.json({ 67 | error_code: 0, 68 | msg: '获取成功', 69 | data: book 70 | }) 71 | } 72 | } 73 | conn.end() // 注意关闭数据库链接 74 | }) 75 | }) 76 | ``` 77 | results返回的数据格式是怎样的? 78 |  79 | 查询结果如下图 80 |  81 | 返回一个数组,results\[0\]可以直接获取到第一个对象的引用,results\[0\].Sno 可以直接获取到这个对象的 Sno 属性对应的值。 82 | 83 | ## 插入数据 84 | ```js 85 | // ...建立连接的过程省略 86 | const addSql = 'INSERT INTO websites(Id, name, url, alexa, country) VALUES(0, ?, ?, ?, ?)' 87 | const addSqlParams = ['菜鸟工具', 'https://c.runoob.com', '23453', 'CN'] 88 | connection.connect() 89 | connection.query(addSql, addSqlParams, function (err, result) { 90 | if (err) { 91 | console.log('[INSERT ERROR] - ', err.message) 92 | return 93 | } 94 | console.log('INSERT ID: ', result) 95 | }) 96 | connection.end() 97 | ``` 98 | 或者 99 | ```js 100 | const sql= 'INSERT INTO websites(Id, name, url, alexa, country) 101 | VALUES(0, '菜鸟工具', 'https://c.runoob.com', '23453', 'CN')' 102 | connection.query(sql, (err, result) => { 103 | // do something... 104 | }) 105 | ``` 106 | 一般都会使用模板字符串: 107 | ```js 108 | const query = req.query // 获取URL中的参数 109 | const sql = `SELECT * FROM ${query.table}` 110 | ``` 111 | 插入成功后返回的信息格式如下: 112 | ```js 113 | OKPacket { 114 | fieldCount: 0, 115 | affectedRows: 1, 116 | insertId: 3, 117 | serverStatus: 2, 118 | warningCount: 0, 119 | message: '', 120 | protocol41: true, 121 | changedRows: 0 } 122 | ``` 123 | 124 | ## 更新数据 125 | ```js 126 | // ...建立连接的过程省略 127 | const addSql = 'UPDATE websites SET name = ?, url = ? WHERE Id = ?' 128 | const addSqlParams = ['菜鸟移动站', 'https://m.runoob.com', 6] 129 | connection.connect() 130 | connection.query(addSql, addSqlParams, function (err, result) { 131 | if (err) { 132 | console.log('[UPDATE ERROR] - ', err.message) 133 | return 134 | } 135 | console.log('UPDATE affectedRows: ', result.affectedRows) 136 | }) 137 | connection.end() 138 | ``` 139 | 更新成功返回的信息格式如下:与 insert 操作一样 140 | ```js 141 | OKPacket { 142 | fieldCount: 0, 143 | affectedRows: 1, 144 | insertId: 3, 145 | serverStatus: 34, 146 | warningCount: 0, 147 | message: '(Rows matched: 1 Changed: 1 Warnings: 0)', 148 | protocol41: true, 149 | changedRows: 1 } 150 | ``` 151 | -------------------------------------------------------------------------------- /服务器/OS 基础知识.md: -------------------------------------------------------------------------------- 1 | # 操作系统的基本功能 2 | 1.进程管理 3 | 4 | 进程控制、进程同步、进程通信、死锁处理、处理机调度等。 5 | 6 | 2.内存管理 7 | 8 | 内存分配、地址映射、内存保护与共享、虚拟内存等。 9 | 10 | 3.文件管理 11 | 12 | 文件存储空间的管理、目录管理、文件读写管理和保护等。 13 | 14 | 4.设备管理 15 | 16 | 完成用户的 I/O 请求,方便用户使用各种设备,并提高设备的利用率。 17 | 18 | 主要包括缓冲管理、设备分配、设备处理、虛拟设备等。 19 | 20 | ## 系统调用 21 | 如果一个进程在用户态需要使用内核态的功能,就进行系统调用从而陷入内核,由操作系统代为完成。 22 | 23 | 24 | 25 | Linux 的系统调用主要有以下这些: 26 | 27 | | Task | Commands | 28 | | :-: | --- | 29 | | 进程控制 | fork(); exit(); wait(); | 30 | | 进程通信 | pipe(); shmget(); mmap(); | 31 | | 文件操作 | open(); read(); write(); | 32 | | 设备操作 | ioctl(); read(); write(); | 33 | | 信息维护 | getpid(); alarm(); sleep(); | 34 | | 安全 | chmod(); umask(); chown(); | 35 | # 进程与线程 36 | ## 进程 37 | 进程是资源分配的基本单位。 38 | 39 | 进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。 40 | 41 | ## 线程 42 | 线程是独立调度的基本单位。 43 | 44 | 一个进程中可以有多个线程,它们共享进程资源。 45 | 46 | QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等, 47 | 线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。 48 | 49 | 50 | 51 | ## 区别 52 | Ⅰ 拥有资源 53 | 54 | 进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。 55 | 56 | 更为具体地说,线程之间共享**堆**和**全局变量**,因为堆是在进程空间中开辟出来的,所以肯定是跨线程共享的; 57 | 58 | 同理,全局变量是整个程序所共享的,也应由线程共享。而每个线程都会独立地维护属于自己的**寄存器**与**栈**。 59 | 60 | Ⅱ 调度 61 | 62 | 线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。 63 | 64 | Ⅲ 系统开销 65 | 66 | 由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。 67 | 68 | 类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。 69 | 70 | Ⅳ 通信方面 71 | 72 | 线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC。 73 | 74 | 具体来说,进程间通信一般有以下两种形式:1.共享内存 2.消息传递 75 | 76 | 77 | 78 | - 共享内存模式:建立一块供协作进程共享的内存区域,进程通过向此共享区域读或写入数据来交换信息。 79 | - 消息传递模式:通过在协作进程间交换消息来实现通信。 80 | 81 | # 程序在内存中的分布 82 | 83 | 84 | **代码段(.text)**:也称文本段(Text Segment),存放着程序的机器码和只读数据,可执行指令就是从这里取得的。如果可能,系统会安排好相同程序的多个运行实体共享这些实例代码。这个段在内存中一般被标记为只读,任何对该区的写操作都会导致段错误(Segmentation Fault)。 85 | 86 | **BSS段(.bss)**:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS 是英文 Block Started by Symbol 的简称。BSS 段属于静态内存分配。 87 | 88 | **数据段(.data)**:数据段(data segment)通常是指用来存放程序中已初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配。 89 | 90 | **堆(Heap)**:用来存储程序运行时分配的变量。堆的大小并不固定,可动态扩张或缩减。堆的内存的分配与释放由应用程序控制,通常申请的内存都需要释放,如果没有释放,在程序运行结束后操作系统会自动回收。 91 | 92 | **栈(Stack)**:是一种用来存储函数调用时的临时信息的结构,如函数调用所传递的参数、函数的返回地址、函数的局部变量等。 在程序运行时由编译器在需要的时候分配,在不需要的时候自动清除。 93 | 94 | - 所谓**动态存储区域**: 即 堆 栈 95 | - 所谓**静态存储区域**:即 存储静态变量和全局变量以及代码段的部分 96 | 97 | # 死锁 98 | ## 必要条件 99 | 100 | 101 | - 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。 102 | - 占有和等待:已经得到了某个资源的进程可以再请求新的资源。 103 | - 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。 104 | - 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。 105 | 106 | ## 死锁处理 107 | 主要有以下四种方法: 108 | - 鸵鸟策略 109 | - 死锁检测与死锁恢复 110 | - 死锁预防 111 | - 死锁避免 112 | 113 | ### 鸵鸟策略 114 | 把头埋在沙子里,假装根本没发生问题。 115 | 116 | 因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。 117 | 118 | 当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。 119 | 120 | 大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。 121 | ### 死锁检测与死锁恢复 122 | 不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。 123 | 124 | 125 | 126 | 上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。 127 | 128 | 图 a 可以抽取出环,如图 b,它满足了环路等待条件,因此会发生死锁。 129 | 130 | 每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记, 131 | 如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。 132 | 133 | 134 | ### 死锁预防 135 | 在程序运行之前预防发生死锁。 136 | 137 | 1.破坏互斥条件 138 | 139 | 例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进程。 140 | 141 | 2.破坏占有和等待条件 142 | 143 | 一种实现方式是规定所有进程在开始执行前请求所需要的全部资源。 144 | 145 | 3.破坏不可抢占条件 146 | 147 | 4.破坏环路等待 148 | 149 | 给资源统一编号,进程只能按编号顺序来请求资源。 150 | 151 | ### 死锁避免 152 | 在程序运行时避免发生死锁。使用银行家算法来保证资源的合理分配:[https://blog.csdn.net/qq\_37205708/article/details/86550339](https://blog.csdn.net/qq_37205708/article/details/86550339) 153 | 154 | # 操作系统笔记十篇 155 | [https://blog.csdn.net/qq\_37205708/article/category/8618355](https://blog.csdn.net/qq_37205708/article/category/8618355) 156 | -------------------------------------------------------------------------------- /JavaScript/event-loop.md: -------------------------------------------------------------------------------- 1 | >这里只介绍浏览器中的事件循环,node 中的事件循环放在 node.js 专题部分 2 | 3 | ## 灵魂三问 4 | JavaScript 为什么是单线程的?JavaScript 为什么需要异步?JavaScript 单线程又是如何实现异步的? 5 | 6 | 7 | **1.JavaScript 为什么是单线程的?** 8 | 9 | 10 | 现在有 2 个线程 process1 process2,假设 JavaScript 是多线程的,所以他们可以对同一个 dom 同时进行操作。process1 删除了该 dom,而 process2 编辑了该 dom,同时下达 2 个矛盾的命令,浏览器究竟该如何执行呢?这样想,JavaScript 为什么被设计成单线程应该就容易理解了吧。 11 | 12 | 13 | **2.JavaScript 为什么需要异步?** 14 | 15 | 16 | 如果 JavaScript 中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验,所以 JavaScript 中存在异步执行。 17 | 18 | 19 | **3.JavaScript 单线程又是如何实现异步的呢?** 20 | 21 | 22 | 是通过**事件循环**来实现的 23 | 24 | >为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个新标准并没有改变 JavaScript 单线程的本质。 25 | 26 | 为什么说 JavaScript 是“非阻塞”的语言?非阻塞即:“程序不会因为某个任务而停下来” 27 | ```js 28 | console.log("程序时间:" + new Date().getTime()) 29 | 30 | setTimeout(function () { 31 | console.log("暂停一秒:" + new Date().getTime()) 32 | }, 1000) 33 | 34 | console.log('这是暂停一秒之后的时间:' + new Date().getTime()) 35 | ``` 36 | 简单来,如果上图的 setTimeout 换成 C++ 的 sleep(1000) 之类的,那么 C++ 是会确实地“睡眠”那么段时间的,而 JS 不会。如果我就是想实现这个功能呢?可以利用 Promise 实现: 37 | ```js 38 | async function test () { 39 | console.log('start') 40 | await sleep(3000) 41 | console.log('3s has passed') 42 | } 43 | 44 | function sleep (ms) { 45 | return new Promise((resolve, reject) => { 46 | setTimeout(() => { 47 | resolve() 48 | }, ms) 49 | }) 50 | } 51 | ``` 52 | ## 任务队列 53 | **任务队列(task queue)** 54 | 当遇到一个异步事件后,JavaScript 引擎并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列。 55 | 这些任务又被细分为宏任务和微任务 56 | - 宏任务(macrotask):script(全局任务),setTimeout ,setInterval ,setImmediate **(node.js 独有)**,I/O(磁盘读写或网络通信) ,UI rendering(UI交互事件) 57 | - 微任务(microtask):process.nextTick **(node.js 独有)**, Promise.then, Object.observer(已废弃), MutationObserver. 58 | 59 | ## 事件循环(event loop) 60 | 这里首先要明确一点:浏览器是一个进程,其有多个线程(具体见 Broswer 章节) 61 | 一般情况下, 浏览器有如下五个线程: 62 | * GUI 渲染线程 63 | * JavaScript 引擎线程 64 | * 浏览器事件触发线程 65 | * 定时器触发线程 66 | * 异步 HTTP 请求线程 67 | 68 | 69 | GUI 渲染线程和 JavaScript 引擎线程是互斥的,其他线程相互之间都是可以并行执行的。 70 | 71 | 72 | 浏览器中,JavaScript 引擎循环地从任务队列中读取任务并执行,这种运行机制就叫做事件循环。 73 | 更准确地说,事件循环是按下面几个步骤执行的: 74 | 1. 执行同步代码,这属于宏任务(初始时的同步代码就是 script 整体代码) 75 | 2. 执行栈为空,查询是否有微任务 (microtask) 需要执行 76 | 3. 执行所有微任务 77 | 4. 必要的话渲染 UI 78 | 5. 然后开始下一轮 Event loop,执行宏任务中的异步代码 79 | 80 | 81 | 82 | ## 例题 83 | ```js 84 | setTimeout(function () { 85 | console.log(1); 86 | }, 0); 87 | 88 | Promise.resolve(function () { 89 | console.log(2); 90 | }) 91 | 92 | new Promise(function (resolve) { 93 | console.log(3); 94 | }); 95 | 96 | console.log(4); 97 | 98 | //上述代码的输出结果是什么??? 99 | ``` 100 | 正确答案是`------------------->` 3 4 1 101 | 解释如下: 102 | ``` js 103 | // 遇到 setTimeout 将 setTimeout 回调放入宏仁务队列中 104 | setTimeout(function () { 105 | console.log(1) 106 | }, 0) 107 | 108 | // 遇到了 promise,但是并没有 then 方法回调 109 | // 所以这句代码会在执行过程中进入我们当前的执行上下文 紧接着就出栈了 110 | Promise.resolve(function () { 111 | console.log(2) 112 | }) 113 | 114 | // 遇到了一个 new Promise,Promise 有一个原则就是在初始化 Promise 的时候Promise 内部的构造器函数会立即执行, 115 | // 因此在这里会立即输出一个 3,所以这个 3 是第一个输出的 116 | new Promise(function (resolve) { 117 | console.log(3) 118 | }) 119 | // 然后第二个输出 4 当代码执行完毕后回去微任务队列查找有没有任务, 120 | // 发现微任务队列是空的,那么就去宏仁务队列中查找,发现有一个我们刚刚放进去的setTimeout 回调函数, 121 | // 那么就取出这个任务进行执行,所以紧接着输出1 122 | console.log(4) 123 | ``` 124 | 125 | 太简单了?来看看这题: 126 | ```js 127 | console.log('begin'); // 1.begin 128 | setTimeout(() => { 129 | console.log('setTimeout 1'); // 3.setTimeout 1 130 | Promise.resolve() // Promise.resolve().then :直接把 then 回调放入微任务队列 131 | .then(() => { 132 | console.log('promise 1'); // 5.promise 1 133 | setTimeout(() => { 134 | console.log('setTimeout2'); // 8. setTimeout2 135 | }); 136 | }) 137 | .then(() => { 138 | console.log('promise 2'); // 7. promise 2 注意7比8要快,then 方法返回一个新的 Promise 对象 139 | }); 140 | new Promise(resolve => { 141 | console.log('a'); // 4. a 142 | resolve(); 143 | }).then(() => { 144 | console.log('b'); // 6. b 145 | }); 146 | }, 0); 147 | console.log('end'); // 2.end 148 | ``` 149 | -------------------------------------------------------------------------------- /CSS/常见问题2.md: -------------------------------------------------------------------------------- 1 | # 清除浮动 2 | 参考链接:[https://blog.csdn.net/h\_qingyi/article/details/81269667](https://blog.csdn.net/h_qingyi/article/details/81269667) 3 | 4 | 方案1:触发 BFC 实现清除浮动 5 | ```css 6 | .fahter{ 7 | width: 400px; 8 | overflow: hidden; 9 | } 10 | ``` 11 | 缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素 12 | ***** 13 | 方案2:使用 after 伪元素清除浮动 14 | ```css 15 | .clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/ 16 | content: ""; 17 | display: block; 18 | height: 0; 19 | clear:both; 20 | visibility: hidden; 21 | } 22 | .clearfix{ 23 | *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/ 24 | } 25 | ``` 26 | 优点:符合闭合浮动思想,结构语义化正确 27 | 缺点:ie6-7 不支持伪元素:after,使用 zoom:1 触发 hasLayout. 28 | ***** 29 | 方案3:使用 before 和 after 双伪元素清除浮动 30 | ```css 31 | .clearfix:after,.clearfix:before{ 32 | content: ""; 33 | display: table; /* ??? */ 34 | } 35 | .clearfix:after{ 36 | clear: both; 37 | } 38 | .clearfix{ 39 | *zoom: 1; 40 | } 41 | ``` 42 | 43 | # 两侧宽度固定、中间宽度自适应的三栏布局 44 | 参考链接 45 | 46 | [https://blog.csdn.net/Cinderella\_hou/article/details/52156333](https://blog.csdn.net/Cinderella_hou/article/details/52156333) 47 | 48 | [https://chokcoco.github.io/CSS-Inspiration/#/./layout/holy-grail-layout](https://chokcoco.github.io/CSS-Inspiration/#/./layout/holy-grail-layout) 49 | 50 | [https://www.cnblogs.com/hfdj/p/7554933.html](https://www.cnblogs.com/hfdj/p/7554933.html) 51 | 52 | [https://www.jianshu.com/p/81ef7e7094e8](https://www.jianshu.com/p/81ef7e7094e8) 53 | 54 | 解决方案:绝对定位、圣杯布局及双飞翼布局方案、 flex 方案 55 | 56 | ## 圣杯布局 57 | 原理: 58 | * 圣杯布局的关键点是通过 margin-left 与 left 属性将左右两列放置到准确的位置 59 | * 圣杯布局的关键点父元素需要设置 padding 60 | * 圣杯布局的关键点 margin-left 取值为百分比时,是以其父元素的宽度为基准的 61 | 62 | 缩放浏览器能看到自适应效果,分析过程见链接1 63 | 64 | ```html 65 | 66 | 67 |