day-089-eighty-nine-20230610-问题思考-redux持久化存储-react淘系方案-iterator迭代器-generator生成器-串行发起请求的三种方案-redux中间件-redux-saga
问题思考
-
常用为props和react-redux全局状态管理。
- 父子常用为props,有时也用ref及用ref拿到useImperativeHandle暴露出来的api。
- react-redux则是全局状态管理,也有一些是上下文。不过上下文一般是第三方vue组件内部使用的。
-
受控组件与非受控组件。
-
受状态管控:
- 受状态管控组件:
- 非受状态管控组件:
-
受路由管控:
- 受路由管控组件:
- 非受路由管控组件:
-
-
高阶组件是利用闭包和高阶函数来实现的,传入一个入参组件,返回的视图组件就是入参组件。
redux持久化存储
- redux-persist 实现redux持久化存储的插件
react淘系方案
-
react 淘系方案:阿里巴巴基于react封装的一套框架
-
主要做管理系统的框架:AntdPro
-
学习步骤
- umi
- dva
- redux-saga
- generator
- iterator
-
iterator迭代器
-
iterator是一种机制或规范,并不是一个具体类。
-
是ES6新增的规范。
class Iterator { constructor(assemble) { this.assemble = assemble; this.index = -1; } next() { if (this.index >= this.assemble.length - 1) { return { value: undefined, done: true, }; } let value = this.assemble[++this.index]; let done = false; return { value, done, }; } } let itor = new Iterator([10, 20, 30, 40]); console.log(`itor-->`, itor); //itor--> Iterator {assemble: Array(4), index: -1} console.log(`itor.next()-->`, itor.next()); // -> {value:10,done:false} console.log(`itor.next()-->`, itor.next()); // -> {value:20,done:false} console.log(`itor.next()-->`, itor.next()); // -> {value:30,done:false} console.log(`itor.next()-->`, itor.next()); // -> {value:40,done:false} console.log(`itor.next()-->`, itor.next()); // -> {value:undefined,done:true} console.log(`itor.next()-->`, itor.next()); // -> {value:undefined,done:true}- 上方例子中Iterator()就是一个迭代器类,而itor就是一个迭代器实例对象。
-
-
iterator迭代器:为各种不同的数据结构,提供统一的遍历/迭代
机制-
iterator是一个规范,也可以认为它是一种机制:
-
iterator是一个实例对象:
-
数据结构必须具备next()方法。
- 即iterator实例对象上一个名为next的函数属性。
-
每一次执行next()都是为了迭代到数据中的每个成员。
-
每一次执行next()返回一个对象:
- value:当前迭代的这一项的值。
- done:是否迭代完成。
-
class Iterator { constructor(assemble) { this.assemble = assemble this.index = -1 } next() { if (this.index === this.assemble.length - 1) { return { value: undefined, done: true } } let value = this.assemble[++this.index], done = false return { value, done } } } let itor = new Iterator([10, 20, 30, 40]) console.log(itor.next()) //->{value:10,done:false} console.log(itor.next()) //->{value:20,done:false} console.log(itor.next()) //->{value:30,done:false} console.log(itor.next()) //->{value:40,done:false} console.log(itor.next()) //->{value:undefined,done:true} console.log(itor.next()) //->{value:undefined,done:true} -
-
iterator示例类
class Iterator {
constructor(assemble) {
this.assemble = assemble;
this.index = -1;
}
next() {
if (this.index >= this.assemble.length - 1) {
return {
value: undefined,
done: true,
};
}
let value = this.assemble[++this.index];
let done = false;
return {
value,
done,
};
}
}
let itor = new Iterator([10, 20, 30, 40]);
console.log(`itor-->`, itor); //itor--> Iterator {assemble: Array(4), index: -1}
console.log(`itor.next()-->`, itor.next()); // -> {value:10,done:false}
console.log(`itor.next()-->`, itor.next()); // -> {value:20,done:false}
console.log(`itor.next()-->`, itor.next()); // -> {value:30,done:false}
console.log(`itor.next()-->`, itor.next()); // -> {value:40,done:false}
console.log(`itor.next()-->`, itor.next()); // -> {value:undefined,done:true}
console.log(`itor.next()-->`, itor.next()); // -> {value:undefined,done:true}
迭代器规范
-
如何知道那些数据结构具备迭代器规范呢?
-
看数据结构是否具备Symbol.iterator属性。
- 并且该Symbol.iterator属性的属性值是个函数。
-
常用的具备迭代器规范的数据结构:
-
数组。
let arr = [10,20,30] -
部分伪数组,例如:arguments、HTMLCollection元素集合、NodeList节点集合…
-
字符串。
- 这个是它的包装对象上有,字符串本身是基础数据类型,并没有键值对这些概念。
-
Set/Map
-
…
-
-
普通对象是不具备迭代器规范的。
-
而具备迭代器规范的数据结构,可以使用for/of循环。
- for-of循环只能获取获取数据的成员值。
-
-
for-of循环的底层机制:
-
for-of 循环,只能获取数据的成员值。
-
基于for-of迭代一个数据结构的时候,首先调用数据结构的Symbol.iterator方法。
- 如果不具备这个方法,则直接报错,说明不具备迭代器规范。
-
执行Symbol.iterator方法,会获取到一个iterator对象,iterator对象中具备next()方法。
-
每一轮循环都相当于在执行
Symbol.iterator方法返回的iterator对象中的next()方法,而next()方法返回的是一个具备value/done的对象。-
把获取的 value 属性值,赋值给 value 这个变量。
- 即把
next()方法返回的对象的value属性值,赋值给当前for-of循环中的循环值。
- 即把
-
根据done的值是true/false,决定循环是否继续。
-
- 即根据
next()方法返回的对象的done属性值是否为false,决定是否进行下一轮次的for-of循环。
- 即根据
-
let arr = [10, 20, 30] for (let value of arr) { console.log(value) //10 20 30 } /*let itor = arr[Symbol.iterator]() 第一轮循环 itor.next() -> {value:10,done:false} 第二轮循环 itor.next() -> {value:20,done:false} 第三轮循环 itor.next() -> {value:30,done:false} 第四轮循环 itor.next() -> {value:undefined,done:true} */let arr = [10, 20, 30]; arr[Symbol.iterator] = function iterator() { // this:arr; let self = this; let index = -1; return { next() { console.log(`每一轮次for-of循环时`,); if (index >= self.length - 1) { return { value: undefined, done: true, }; } let value = self[++index]; let done = false; return { value, done, }; }, }; }; // let itor = arr[Symbol.iterator]// for (let value of arr) { console.log(`value-->`, value); //10 ;//20; //30; } -
-
重写数组中的Symbol.iterator属性
let arr = [10, 20, 30];
arr[Symbol.iterator] = function iterator() {
// this : arr
let self = this,
index = -1;
return {
next() {
//console.log(`每一轮次for-of循环时: ${index}`);
if (index === self.length - 1) {
return {
value: undefined,
done: true,
};
}
let value = self[++index],
done = false;
return {
value,
done,
};
},
};
};
// let itor = arr[Symbol.iterator]()
for (let value of arr) {
console.log(value); //10 20 30
}
普通对象与for-of循环
-
面试题:普通对象是否可以使用 for/of 循环进行迭代?如果不行是为啥?如何让其可与基于 for/of 处理?
-
普通对象不能使用for/of 循环进行迭代。
let obj = { name: "哈哈哈", age: 15, [Symbol("AA")]: 100, }; Object.defineProperty(obj, "sex", { value: "男", // enumerable: false, // configurable: false, // writable: false });-
原因:普通不具备迭代器规范,也就是不具备 Symbol.iterator 这个方法。
let obj = { name: "哈哈哈", age: 15, [Symbol("AA")]: 100, }; Object.defineProperty(obj, "sex", { value: "男", // enumerable: false, // configurable: false, // writable: false }); for (let value of obj) { //Uncaught TypeError: obj is not iterable console.log(value) } // 原因:普通不具备迭代器规范,也就是不具备 Symbol.iterator 这个方法。 -
解决办法:手动为其设置一个 Symbol.iterator。
// 面试题:普通对象是否可以使用 for/of 循环进行迭代?如果不行是为啥?如何让其可与基于 for/of 处理? let obj = { name: "哈哈哈", age: 15, [Symbol("AA")]: 100, }; Object.defineProperty(obj, "sex", { value: "男", // enumerable: false, // configurable: false, // writable: false }); // 解决办法:手动为其设置一个 Symbol.iterator Object.prototype[Symbol.iterator] = function iterator() { // 获取对象所有的私有成员 let self = this, keys = Reflect.ownKeys(self), index = -1; return { next() { if (index === keys.length - 1) { return { value: undefined, done: true }; } let value = self[keys[++index]], done = false; return { value, done }; }, }; }; for (let value of obj) { console.log(value); }
-
-
generator生成器
普通函数
function fn(){
return 10
}
console.log(`fn()-->`, fn());//10
generator生成器函数
-
创建函数,并且加一个*号,则函数为生成器函数。
- 生成器函数只能基于function关键字创建。
// 创建函数,并且加一个*号,则函数为生成器函数。
function* fn(){
return 10
}
console.log(`fn()-->`, fn());//看似把函数执行,但是函数并没有执行。最起码函数体中的代码并没有执行,返回结果是:一个具备迭代器规范的对象(迭代器对象),具备next/throw/return三个方法。
generator规则
-
生成器函数函数体中的yield与return。
//生成器函数执行的时候,函数体中的代码并没有执行,只是返回一个迭代器对象。只有通过返回的迭代器对象,基于next方法执行的时候,函数体中的代码才会自上而下执行,而且遇到yield或return结束一次运行! // yield与return后面的值,就是返回对象中value属性的值。 // 对象中的done属性是:遇到yield是false,遇到return是true。 function* fn() { console.log(`A`); yield 10; console.log(`B`); yield 20; console.log(`C`); return 30; } let itor = fn(); // console.log(`itor-->`, itor); console.log(`itor.next()-->`, itor.next()); //输出`A` ; 返回: {value:10,done:false} console.log(`itor.next()-->`, itor.next()); //输出`B` ; 返回: {value:20,done:false} console.log(`itor.next()-->`, itor.next()); //输出`C` ; 返回: {value:30,done:true} console.log(`itor.next()-->`, itor.next()); //返回: {value:undefined,done:true} // 生成器函数的作用:可以基于yield和迭代器规范,控制函数体中的代码一步步的去执行。 -
生成器函数的作用:可以基于yield和迭代器规范,控制函数体中的代码一步步的去执行。
-
返回的迭代器的throw函数。
function* fn() { console.log(`A`); yield 10; console.log(`B`); yield 20; console.log(`C`); } let itor = fn(); console.log(`itor.next()-->`, itor.next()); //输出`A` ; 返回: {value:10,done:false} console.log(`itor.throw("哈哈哈")-->`, itor.throw("哈哈哈")); //直接抛出异常错误,错误原因是"哈哈哈",后续代码都不会再执行。 console.log(`itor.next()-->`, itor.next()); //这行代码也不再执行。 -
返回的迭代器的return函数。
function* fn() { console.log(`A`); yield 10; console.log(`B`); yield 20; console.log(`C`); } let itor = fn(); console.log(`itor.next()-->`, itor.next()); //输出`A` ; 返回: {value:10,done:false} console.log(`itor.return("哈哈哈")-->`, itor.return("哈哈哈")); //说明函数执行已经结束,函数体中的后续代码都不会执行。本次返回是{value:"哈哈哈",done:true},后续代码都不会再执行。 console.log(`itor.next()-->`, itor.next()); //返回{value:undefined,done:true}
async-await语法的示例
const AsyncFunction = function AsyncFunction(generator, ...params) {
return new Promise(resolve => {
// generator:需要管控处理的生成器函数 params:以后执行 generator ,为其传递的实参
let itor = generator(...params)
// 递归一次次的执行 next ,控制生成器函数中的代码一步步执行
const recursion = (x) => {
let { value, done } = itor.next(x)
if (done) {
// 生成器函数执行完毕,结束递归操作,value就是生成器函数最后的返回值
resolve(value)
return
}
if (!(value instanceof Promise)) value = Promise.resolve(value) //确保每一次yield后面的值都是promise实例
value.then(x => {
// 等待上一步处理成功(x是成功的结果),则开启下一步的执行
recursion(x)
})
}
recursion()
})
}
next函数中入参
// yiled 后面的值:作为本次next执行,返回对象中的value的属性值。
// next函数传递的值:作为上一次yield执行的返回结果。或者说,yield执行的返回结果,是下一次执行next,传递的实参信息,所以第一次执行next传递的值是没有用的。
// 形参接收的值:还是生成器函数执行的时候传递的值,和next执行传递的值没关系。
function* fn(x,y) {
console.log(x,y);
console.log(`A`);
let n = yield 10;
console.log(`B`,n);
let m = yield 20;
console.log(`C`,m);
}
let itor = fn(100,200);
console.log(`itor.next(1)-->`, itor.next(1)); //输出`100,200`/`A`; 返回{value:10,done:false}
console.log(`itor.next(2)-->`, itor.next(2)); //输出`B,2`;{value:20,done:false}
console.log(`itor.next(3)-->`, itor.next(3)); //输出`C,3`;{value:undefined,done:true}
串行发起请求的三种方案
redux中间件
redux-thunk
-
redux-thunk中间件
- 底层机制上处理起来非常麻烦「非常绕」
- 函数中的操作全部有开发者自行决定,不方便做统一的智能测试
- …
-
步骤:
redux-saga
- redux-saga 是另外一个处理异步派发的中间件,从各方面都比 redux-thunk 更好一些,所以推荐大家使用 redux-saga 中间件。
redux-saga思路
-
redux-saga不同于redux-thunk或redux-promise中间件。
-
先到redux-thunk或redux-promise中间件,之后通过真正的dispatch到reducer。
- 即便使用了redux-saga中间件,每一次组件中的dispatch派发,都会有一条线,直接到reducer中,多出一条线,会进入到中间件中!
-
-
每一次在组件中派发的时候,派发的行为标识这样处理:
-
如果是同步:让派发的标识和reducer中的一致,和saga中的不一致。
-
如果是异步:让派发的标识和saga中监听的标识一致,和reducer中的标识不一致!
- 等待saga中异步处理完毕,在saga中再次派发一个和reducer中判断一致的标识即可!
-
-
真实项目中,reducer里面按照标识统一管理文件中管理的标识进行判断,saga中监听的标识可以在标识统一管理文件中标识的后面,统一设置
@saga即可。
redux-saga步骤
面试题
-
面试官问的是ES6。
-
快速介绍一些常用的:
let/const/箭头函数/解构赋值/.../模板字符串- 数组对象中新增了一些方法。
- …
-
重点突出一些高级点的:
Promise/async/await: 处理同步异步。Reflect:基础语法如delete与-与*与/之类操作的函数化。Fetch:新的前后端交互。Proxy:代理。iterator:迭代器。generator:生成器。- ES6 Module:模块化,导入与导出。
- …
-
-
面试题:普通对象是否可以使用 for/of 循环进行迭代?如果不行是为啥?如何让其可与基于 for/of 处理?
-
普通对象不能使用for/of 循环进行迭代。
- 原因:普通不具备迭代器规范,也就是不具备 Symbol.iterator 这个方法。
- 解决办法:手动为其设置一个 Symbol.iterator。
-