进程:
-
系统层面的最小单位 -
可以被视为一个程序 -
一个进程可以包含多个线程
线程:
-
一个程序执行层面的最小单位 -
可以被视为一个进程的一个执行单元
浏览器是包含多进程的一个程序
1 浏览器的进程:
-
Browser进程 -
第三方插件进程 -
GPU进程 -
渲染进程(重) 每个tab页都有一个渲染进程,互不影响 主要作用为页面渲染,脚本执行,事件处理等 -
渲染进程的主要线程: 1 GUI渲染线程 渲染浏览器界面,解析html代码,解析css,生成CSSOM 把DOM Tree 和CSSOM结合,生成Rendering Tree(渲染树) 修改了一些元素的颜色或者背景色,页面就会重绘 修改元素的尺寸,页面就会回流 GUI渲染线程与JS引擎线程是互斥的 -
2 JS引擎线程 负责解析Javascript脚本,运行代码 同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的 GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程 JS执行时间过长,渲染加载阻塞 造成页面卡顿的情况 <script defer> 请求异步 延迟执行 不阻塞 <script async> 请求异步 立即执行 看网络返回情况不确定阻塞 -
3 事件触发线程 控制事件循环,管理着一个事件队列 -
4 定时触发器线程 setInterval与setTimeout所在线程,定时器线程 规定要求setTimeout中低于4ms的时间间隔算为4ms -
5 异步http请求线程 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求
关于宏微任务
-
new Promise() 这一部分是一个构造函数,这是一个同步任务
-
then 才是微任务
-
先清空微任务队列,再清空红任务队列
// console.log('1');
// setTimeout(function () {
// console.log('2');
// process.nextTick(function () {
// console.log('3');
// });
// new Promise(function (resolve) {
// console.log('4');
// resolve();
// }).then(function () {
// console.log('5');
// });
// });
// process.nextTick(function () {
// console.log('6');
// });
// new Promise(function (resolve) {
// console.log('7');
// resolve();
// }).then(function () {
// console.log('8');
// });
// setTimeout(function () {
// console.log('9');
// process.nextTick(function () {
// console.log('10');
// });
// new Promise(function (resolve) {
// console.log('11');
// resolve();
// }).then(function () {
// console.log('12');
// });
// });
// 1768 2435 9111012
// console.log('script start');
// async function async1() {
// await async2();
// console.log('async1 end');
// }
// async function async2() {
// console.log('async2 end');
// }
// async1();
// setTimeout(function () {
// console.log('setTimeout');
// }, 0);
// new Promise((resolve) => {
// console.log('Promise');
// resolve();
// })
// .then(function () {
// console.log('promise1');
// })
// .then(function () {
// console.log('promise2');
// });
// console.log('script end');
// script start async2 end Promise script end async1 end
// promise1 promise2 setTimeout
/*************************** 柯里化函数 ***********************************/
/**
* 柯里化函数
*
* 函数的 length 属性,获取函数的形参个数,形参的个数就是所需的参数个数
*
* 在调用柯里化工具函数时,手动指定所需的参数个数
*/
const curry = (fn, arity = fn.length, ...args) => {
console.log('arity -> :', arity);
console.log('args -> :', args);
console.log('args.length -> :', args.length);
return arity <= args.length
? fn(...args)
: curry.bind(null, fn, arity, ...args);
};
let _fn = curry(function (a, b, c, d, e) {
console.log(a, b, c, d, e);
});
// _fn(1, 2, 3, 4, 5); // print: 1,2,3,4,5
// _fn(1)(2)(3, 4, 5); // print: 1,2,3,4,5
// _fn(1, 2)(3, 4)(5); // print: 1,2,3,4,5
_fn(1)(2)(3)(4)(5); // print: 1,2,3,4,5
// 应用
/**
* redux的中间件就是用柯里化的思想
* 三层函数
*
* 第一层为了传递store的dispatch(action)和getState()方法,
*
* 第二层传递的参数next是下一个待执行的中间件,
*
* 第三层是函数本体了,传递的参数action是为了最终传递给dispatch而存在的。
*
*/
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) =>
(next) =>
(action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
// createThunkMiddleware 这个函数,返回的是一个柯里化过的函数。
// 正因为这个 action creator 可以返回一个函数,那么就可以在这个函数中执行一些异步的操作
构造函数、实例、原型对象的关系
/**
* 构造函数、实例、原型对象的关系
*
* 构造函数.prototype === 原型对象
*
* 原型对象.constructor === 构造函数
*
* 实例 = new 构造函数(参数)
*
* 实例.__proto__ === 原型对象
*
* 构造函数.__proto__ === Function.prototype
*
* 原型对象没法直接获取的,所以只有通过构造函数的 prototype 属性获取
*
* 判断
* Object.prototype.toString.call( 构造函数.prototype ) === '[object Object]')
*
*
* js分为「函数对象」和「普通对象」,
*
* 每个对象都有 __proto__ 属性
*
* 但是只有函数对象且「非箭头函数」才有 prototype 属性。
*
*
*/
function BigMan(name, age) {
this.name = name;
this.age = age;
}
var man = new BigMan();
var a = man.__proto__ === BigMan.prototype; // true
console.log('BigMan.prototype -> :', BigMan.prototype); // {}
console.log('a -> :', a);
var b = BigMan.prototype === Function.constructor; // false
console.log('b -> :', b);
function Person() {}
// 说明:name,age,job这些本不应该放在原型上,只是为了说明属性查找机制
Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function () {
console.log(this.name);
};
let person1 = new Person();
let person2 = new Person();
// 声明之后,构造函数就有了一个与之关联的原型对象
console.log(Object.prototype.toString.call(Person.prototype)); // [object Object]
console.log(Person.prototype); // {constructor: ƒ}
// 构造函数有一个 prototype 属性引用其原型对象,而这个原型对象也有一个constructor 属性,引用这个构造函数
// 换句话说,两者循环引用
console.log(Person.prototype.constructor === Person); // true
// 构造函数、原型对象和实例是 3 个完全不同的对象
console.log(person1 !== Person); // true
console.log(person1 !== Person.prototype); // true
console.log(Person.prototype !== Person); // true
// 实例通过__proto__链接到原型对象,它实际上指向隐藏特性[[Prototype]]
// 构造函数通过 prototype 属性链接到原型对象,实例与构造函数没有直接联系,
// 与原型对象有直接联系,后面将会画图再次说明这个问题
console.log(person1.__proto__ === Person.prototype); // true
conosle.log(person1.__proto__.constructor === Person); // true
// 同一个构造函数创建的两个实例,共享同一个原型对象
console.log(person1.__proto__ === person2.__proto__); // true
// Object.getPrototypeOf(),返回参数的内部特性[[Prototype]]的值 ,用于获取原型对象,兼容性更好
console.log(Object.getPrototypeOf(person1) == Person.prototype); // true
/**
* 使用new时,到底发生了什么?
*
* 创建一个空对象,作为将要返回的对象实例
* var obj = new Object();
*
* 得到构造函数
* Constructor = [].shift.call(arguments);
*
* 将这个空对象的原型,指向了外部构造函数的 prototype 属性
* obj.__proto__ = Constructor.prototype;
*
* 将这个空对象赋值给函数内部的this关键字
* var res = Constructor.apply(obj, arguments);
*
* 如果构造函数返回一个对象,那么就直接返回该对象,否则返回创建的对象
*
* return typeof res === 'object' ? res : obj;
*/
/**
* instanceOf,
* 只要左边的__proto__属性指向了右边的原型对象,就返回true
*/
function instanceOf(left, right) {
let proto = left.__proto__;
let prototype = right.prototype;
while (true) {
if (proto === null) return false;
if (proto === prototype) return true;
proto = proto.__proto__;
}
}
// 继承
// function Parent() {} // 父类
// function Child() {} // 子类
// Child.prototype.__proto__ = Parent.prototype;
// const obj = new Child();
// console.log(obj instanceof Child); // true
// console.log(obj instanceof Parent); // true
// 上述继承方法只是让 Child 访问到了 Parent 原型链 , 但是没有执行 Parent 的构造函数
// function Parent() {
// this.parentAge = 50;
// }
// function Child() {}
// Child.prototype = new Parent();
// Child.prototype.constructor = Child; // 注意重置constructor
// const obj = new Child();
// console.log(obj.parentAge); // 50