Generator 函数扫盲
a、形式上,Generator 函数是一个普通函数,但是有两个特征:
1、function关键字与函数名之间有一个星号;
2、函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
b、generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行
c、返回值是遍历器对象。每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
d、yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
e、注意yield的返回值A和其后表达式的返回值B不是一个意思,B是赋给value的
function* f() {
for(var i = 0; true; i++) {
var reset = yield i; // 每次next时执行该行,下面一行等下一个next才执行
if(reset) { i = -1; }
}
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }
f、yield*表达式,用来在一个 Generator 函数A里面执行另一个 Generator 函数B,这里“执行”的意思不是执行B(),即返回值不是遍历器对象C,而是返回C的for...of结果,就好似将B的yield代码拷贝到了A里:
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
for (let v of foo()) {
yield v;
}
yield 'y';
}
for (let v of bar()){
console.log(v);
}
// "x"
// "a"
// "b"
// "y"
g、异步任务的封装
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
// 调用
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});
Saga 用法
1、redux-saga 是一个用于管理 Redux 应用异步操作的中间件(又称异步 action)。
2、redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件。
3、Sagas 监听发起的action,然后决定基于这个 action来做什么:是发起一个异步调用(比如一个 fetch 请求),还是发起其他的action到Store,甚至是调用其他的 Sagas
4、一个实例
// 1、写reducer
import { handleActions } from 'redux-actions'
import { LOGIN_SUCCEEDED, LOGIN_FAILED, LOGOUT_SUCCEEDED, LOGOUT_FAILED} from '../constants/login'
// 语法:handleActions({actionCreator},initialState)
export default handleActions(
{
[LOGIN_SUCCEEDED](state, action) {
return { ...state, ...action.accountInfo,hasLogin: true }
},
[LOGIN_FAILED](state, action) {
alert(action.message)
return state
},
},
{
hasLogin: false,
},
)
// 2、写saga
function* login(action) {
try {
// 语法:call([context, fn], ...args)
const data = yield call(
getJSON,
URLS.LOGIN,
{ password: action.password, accountName: action.accountName },
)
yield put({ type: LOGIN_SUCCEEDED, accountInfo: data }) // 成功时改变state状态
yield hashHistory.push('/project')
} catch (e) {
yield put({ type: LOGIN_FAILED, message: e })
}
}
function* loginSaga() {
yield* takeEvery(LOGIN_REQUESTED, login) // 这一步监听LOGIN_REQUESTED事件
}
export {
loginSaga,
}
// 3、调用方
import { LOGIN_REQUESTED } from '../../constants/login'
class Login extends React.Component {
componentDidMount() {
}
login = e => {
const { dispatch } = this.props
e.preventDefault()
e.stopPropagation()
dispatch({ // 这一步触发LOGIN_REQUESTED事件
type: LOGIN_REQUESTED,
password: this.refs.password.value,
accountName: this.refs.accountName.value,
})
}
render() {
}
}