JS知识点备忘
知识点分享:
一.中间件
1.1 为啥要用中间件?
中间件是一个函数,为了解决异步操作,传统的action -> reducer 变为 action -> middleware -> reducer
1.2 react-thunk?
在异步抓取数据的时候,可以发出三种action,分别是:操作发起,操作成功,操作失败
使用react-thunk可以dispatch(function),react-thunk接收到后,如果是一个函数,则返回这个函数的 调用
function 来自 action creactor ,此函数又return出一个函数,参数时dispatch与getstate,在return出的函数可以进行异步处理,还可以dispatch action
举个栗子:
export function fetchTopics() {
return (dispatch,getState) => {
apis.getTopic.getList()
.then(res => dispatch(fetchTopicsSuccess(res.data)))
.catch(error => dispatch(fetchTopicsFailed(error)))
}
}
二.遍历器iterator
1.遍历器是什么?
是一种接口,位各种不同的数据结构提供统一的访问机制,
任何数据结构只要部署了iterator接口,就可以完成遍历操作。
2.作用是什么?
1.为各种数据结构,提供一个统一的访问接口
2.使得数据结构的成员能够按照某种次序排列
3.ES6创造了一种新的遍历命令for...of循环,iterator主要供for...of消费
3.遍历过程是怎样的?
1.创建一个指针对象,指向当前数据结构的起始位置。
2.第一次调用指针的next()方法,可以将指针指向数据结构的第一个成员
3.第二次调用next()指针指向第二个成员
4.不断调用指针的next方法,直到它指向数据结构结束的位置
每一次调用next方法, 都会返回数据结构的当前成员的信息。如{value:1,done:false}
4.默认的iterator接口
1.当使用for...of循环遍历某种数据结构时,该循环会自动寻找iterator接口
2.ES6规定,一个数据结构只要具有Symbol.iterator属性,就可以认为是可遍历的的。该属性本身是一个函数,是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器对象。
5.为对象添加Iterator接口,一个对象如果要具备可被for...of循环调用的Iterator接口,就必须在Symbol.iterator的属性上部署遍历器生成方法。
let obj = {
data:['hello','world'],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if(index < self.data.length) {
return {
value: self.data[index++],
done:false
}
}else {
return { value: undefined, done: true }
}
}
}
}
}
为类似数组的对象调用数组的Symbol.iterator方法
let iterable = {
0: 'a',
1: 'b',
2;'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for(let item of oterable) {
console.log(item) //a b c
}
6.调用iterator接口的场合
1.解构赋值
2.扩展运算符
3.yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口
4.任何接受数组作为参数的场合,都调用了遍历器接口
for...of
Array.from()
Map(),Set()
Promise.all()
Promise.race()
三.generator函数
1.什么是generator?
是ES6提供的一种异步编程解决方案
从语法上:是一个状态机,封装了多个内部状态。
从返回值:执行generator函数会返回一个遍历器对象。
generator:状态机/遍历器对象生成函数
返回的遍历器对象,可以依次遍历generator函数内部的每一个状态
通过generator为对象加遍历接口
function* objectEntries() {
let propKeys = Object.keys(this)
for(let propKey of propKeys) {
yield [propKey,this[propKey]]
}
}
let jane = { first: 'jane', last: 'Doe'};
jane[Symbol.iterator] = objectEntries
for(let [key,value] of jane) {
console.log(`${key} : ${value}`)
}
2.generetor为啥能实现异步?
generator函数可以暂停执行和恢复执行,是它能封装异步任务的根本原因
3.yield是干啥的?
yield后面的表达式,只有当next方法将指针移到它时,才会执行
yield是暂停标志,当函数遇到yield时,会暂停执行,并将yield后的值作为对象属性中的value返回
4.yield与return的异同:
相同点:都能返回紧跟在它之后表达式的值
不同点:yield能记录位置,return不能,一个函数中可以有多个yield
5.next方法的参数:
yield本身无返回值,next方法可以带一个参数,作为上一次yield的表达式的返回值
举个栗子:
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true } //5+24+13
6.内部可以使用try...catch捕获错误
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出错了');
7.generator与协程
协程:多个线程互相协作,完成异步任务(单线程情况下,即多个函数可以并行执行)
第一步,协程A开始执行。
第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
第三步,(一段时间后)协程B交还执行权。
第四步,协程A恢复执行。
协程遇到yield命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。 8.react-saga基础学习使用
sagas:被实现为generator
yield effect -> redux-saga middleware 解释执行指令 -> resolve/reject ->sagas恢复执行
⬇
sagas暂停,等待promise完成
四:async await
1.是什么?
generator的升级版
2.有什么优点?
1.内置执行器
2.语义化
3.适用性广:await后面可以是promise对象或者原始类型的值
4.返回值是promise
3.怎么用?
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);
// 箭头函数
const foo = async () => {};
4.并发与继发
//继发:耗时
let foo = await getFoo();
let bar = await getBar();
//并发
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
5.错误处理,使用try...catch捕获
async function f() {
return await 123; //需要return
}
f().then(v => console.log(v))
async function f() {
await Promise.reject('出错了'); //不需要return也能捕获到错误
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
async function main() {
try {
const val1 = await 1
const val2 = await 1;
throw new Error('出错了');
const val3 = await 3;
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
console.log('hello world')
}
main() //Error:出错了
//hello world
五.虚拟DOM算法原理:
DOM树上的结构,属性信息都可以用JS对象来表示
- 状态变更-->重新渲染整个视图,用JS对象表示DOM信息和结构,当状态变更的时候,重新渲染js对象结构。用选渲染的对象树和旧的树进行对比,记录两棵树的差异,记录下来的不同就是我们需要对页面真正的DOM操作,然后把他们应用再真正的DOM树上,页面就变更了,这样,视图的结构确实重新渲染了,但是最后操作DOM的时候只变更有不同的地方,总结如下:
- 1.1. 用JS对象结构表示DOM树的结构,然后用这个树构建一个真正的DOM树,插到文档当中
- 1.2. 当状态变更时,重新构造一棵新的对象树,然后用新的树和旧的树进行比较,记录两棵树差异
- 1.3. 把2所记录的差异应用到步骤1所构建的真正的DOM树,视图就更新了
- diff算法:virtual DOM只会对同一个层级的元素进行对比
- 2.1.实际操作中,diff会进行深度优先遍历,这样每个节点都会有一个唯一的标记,在进行深度优先遍历的时候,每遍历到一个节点就把该节点和新的树进行对比,如果有差异就记录到一个对象里面。
- 2.2.列表对比算法重点:对节点进行删除,插入,移动的操作,列表对比时,给子节点加上唯一标识key,使用key进行对比,这样才能复用老的DOM树上的节点
- 2.3.找到更改的的节点,进行DOM操作
MV*
- MVC
//view model controller
用户对view操作以后,view捕获到这个操作,会把处理的权利交给controller,controller会对来自view数据进行预处理,决定调用哪个model的接口,然后由model执行相关的业务逻辑。当model变更了以后,会通过观察者模式通知view,view通过观察者模式收到model变更的消息以后,会向model请求最新的数据,然后重新更新界面。
- 1.1view是把控制权交给controller,controller执行应用程序的相关的应用逻辑
- 1.2.controller操作model,model执行业务逻辑对数据进行处理,但不会直接操作view
- 1.3.view和model的同步消息是通过观察者模式进行,而同步操作是由view自己请求model的数据然后对视图进行更新
- MVP
//view presenter model
用户对view的操作会从view移交到presenter,presenter会执行相关的业务逻辑,并且对model层进行操作,model执行完业务逻辑后,也是通过观察者模式把自己变更的消息传递出去。但是是传给presenter而不是view,presenter获取到model变更的消息以后,通过view提供的接口更新页面
- 2.1.view不再负责同步的逻辑,而是由presenter负责,presenter中既有应用程序逻辑也有同步逻辑
- 2.2.view需要提供操作界面的接口给presenter进行调用
- MVVM
view view viewModel
MVVM的调用关系和MVP一样。但是,在ViewModel当中会有一个叫Binder,或者是Data-binding engine的东西。以前全部由Presenter负责的View和Model之间数据同步操作交由给Binder处理。你只需要在View的模版语法当中,指令式地声明View上的显示的内容是和Model的哪一块数据绑定的。当ViewModel对进行Model更新的时候,Binder会自动把数据更新到View上去,当用户对View进行操作(例如表单输入),Binder也会自动把数据更新到Model上去。这种方式称为:Two-way data-binding,双向数据绑定。可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。也就是说,MVVM把View和Model的同步逻辑自动化了。以前Presenter负责的View和Model同步不再手动地进行操作,而是交由框架所提供的Binder进行负责。只需要告诉Binder,View显示的数据对应的是Model哪一部分即可