Vue 编码基础
2.1.1. 组件规范
2.1.2. 模板中使用简单的表达式
2.1.3 指令都使用缩写形式
2.1.4 标签顺序保持一致
2.1.5 必须为 v-for 设置键值 key
2.1.6 v-show 与 v-if 选择
2.1.7 script 标签内部结构顺序
2.1.8 Vue Router 规范
Vue 项目目录规范
2.2.1 基础
2.2.2 使用 Vue-cli 脚手架
2.2.3 目录说明
2.2.4注释说明
2.2.5 其他
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
就相当于
store.dispatch = function Logger1(action) {
console.log(‘Logger1 dispatching’, action)
let result = next(action)
console.log(‘Logger1 next state’, store.getState())
return result
}
注意,这里的next是store之前的dispatch。
也就是说
这个store现在的dispatch方法为
store.dispatch = function Logger1(action) {
console.log(‘Logger1 dispatching’, action)
let result = next(action)
console.log(‘Logger1 next state’, store.getState())
return result
}
然后再遍历到第二个logger
store.dispatch = function Logger2(action) {
console.log(‘Logger2 dispatching’, action)
let result = next(action)
console.log(‘Logger2 next state’, store.getState())
return result
}
注意,到这里的时候,next是等于之前的那个store.dispatch,也就是说这里的next是上面的Logger2
next = function Logger1(action) {
console.log(‘Logger1 dispatching’, action)
let result = next(action)
console.log(‘Logger1 next state’, store.getState())
return result
}
所以现在这个箭头指向的store的dispatch是什么呢?
没错,就是现在这个样子
store.dispatch = function Logger2(action) {
console.log(‘Logger2 dispatching’, action)
let result = function Logger1(action) {
console.log(‘Logger1 dispatching’, action)
let result = next(action)
console.log(‘Logger1 next state’, store.getState())
return result
}
console.log(‘Logger2 next state’, store.getState())
return result
}
看,实际上,现在的store的dispatch是被logger1包装起来,然后再被logger2包装起来。像极了一个礼物呗几个盒子包起来了。
原理实际上就是不断地更新store.dispatch
接下来,我们就可以这样用
applyMiddleware(store, [logger, crashReporter])
刚刚说过,在applyMiddle里必须要给store.dispatch赋值,否则下一个middleware就拿不到最新的dispatch。
但是有别的方式,那就是在middleware里不直接从store.dipatch里读取next函数,而是将next作为一个参数传入,在applyMiddleware里用的时候把这个参数传下去。
step 5
function logger(store) {
return function wrapDispatchToAddLogging(next) {
return function dispatchAndLog(action) {
console.log(‘dispatching’, action)
let result = next(action)
console.log(‘next state’, store.getState())
return result
}
}
}
接着,在applyMiddleware里有可以不用立刻对store.dispatch赋值啦,可以直接赋值给一个变量dispatch,作为middleware的参数传递下去,这样就能链式的增强dispatch的功能啦~
function applyMiddleware(store, middlewares) {
middlewares = middlewares.slice();
middlewares.reverse();
let dispatch = store.dispatch;
middlewares.forEach(middleware => {
dispatch = middleware(store)(dispatch)
})
return Object.assign({}, store, {dispatch})
}
用es6的柯西化写法,可以写成下面的形式,其实这个next我个人觉得叫previous更为合适,因为它指代的是上一个store.dispatch函数。
const logger = store => next => action => {
console.log(‘dispatching’, action)
let result = next(action)
console.log(‘next state’, store.getState())
return result
}
提供报错信息的中间件
const crashReporter = store => next => action => {
try {
return next(action)
} catch (err) {
console.error(‘Caught an exception!’, err)
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
})
throw err
}
}
由此我们可以看到所以middleware要传入的参数就是三个,store,next,action。
接下来,看一个实例,redux-thunk 的源码,我们知道,它用于异步API,因为异步 API action creator返回的是一个funciton,而不是一个对象,所以redux-thunk做的事情 其实很简单,就是看第三个参数action是否是function,是的话,就执行它,如果不是, 就按照原来那样执行next(action)
function createThunkMiddleware(extraArgument) {
return (store) => next => action => {
if(typeof action === ‘function’) {
return action(dispatch, getState, extraArgument)
}
return next(action)
}
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
step 6
下面终于可以看看applyMiddleware的样子啦
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
* @param {…Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (…args) => f(g(h(…args))).
*/
export default function compose(…funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (…args) => a(b(…args)))
}
//可以看出compose做的事情就是上一个函数的返回结果作为下一个函数的参数传入。
/**
* Creates a store enhancer that applies middleware to the dispatch method
* of the Redux store. This is handy for a variety of tasks, such as expressing
* asynchronous actions in a concise manner, or logging every action payload.
* See redux-thunk
package as an example of the Redux middleware.
* Because middleware is potentially asynchronous, this should be the first
* store enhancer in the composition chain.
* Note that each middleware will be given the dispatch
and getState
functions
* as named arguments.
* @param {…Function} middlewares The middleware chain to be applied.
* @returns {Function} A store enhancer applying the middleware.
*/
export default function applyMiddleware(…middlewares) {
return (createStore) => (…args) => {
// 之后就在这里先建立一个store
const store = createStore(…args)
let dispatch = store.dispatch
let chain = []
// 将getState 跟dispatch函数暴露出去
const middlewareAPI = {
getState: store.getState,
dispatch: (…args) => dispatch(…args)
}
//这边返回chain的一个数组,里面装的是wrapDispatchToAddLogging那一层,相当于先给
//middle剥了一层皮,也就是说
// 接下来只需要开始传入dispatch就行
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(…chain)(store.dispatch)
// 翻译过来就是
// wrapCrashReport(wrapDispatchToAddLogging(store.dispatch))
// 此时返回了上一个dispatch的函数作为wrapCrashReport的next参数
// wrapCrashReport(dispatchAndLog)
// 最后返回最终的dipatch
return {
…store,
dispatch
}
}
}
// 第二行有个比较巧妙地地方,就是传入createStore跟…args,为什么要这么做呢
// 可以先看看我们在用applyMiddleware的时候是怎么用的
createStore(
rootReducers, //reducer
preloadedState,
applyMiddleware( //enhancer
thunkMiddleware,
createLogger
)
)
createStore的部分源码是这样的
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState === ‘function’ && typeof enhancer === ‘undefined’) {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== ‘undefined’) {
if (typeof enhancer !== ‘function’) {
throw new Error(‘Expected the enhancer to be a function.’)
}
// 在这里可以看到,如果第三个参数是函数也是我们的applyMiddleware,那就会直接返回这个,对于我们的applyMiddleware来说,就是直接把creatStore的权利放在了自己身上啊~
return enhancer(createStore)(reducer, preloadedState)
}
if (typeof reducer !== ‘function’) {
throw new Error(‘Expected the reducer to be a function.’)
}
…
}
HTTP
-
HTTP 报文结构是怎样的?
-
HTTP有哪些请求方法?
-
GET 和 POST 有什么区别?
-
如何理解 URI?
-
如何理解 HTTP 状态码?
-
简要概括一下 HTTP 的特点?HTTP 有哪些缺点?
-
对 Accept 系列字段了解多少?
-
对于定长和不定长的数据,HTTP 是怎么传输的?
-
HTTP 如何处理大文件的传输?
-
HTTP 中如何处理表单数据的提交?
-
HTTP1.1 如何解决 HTTP 的队头阻塞问题?
-
对 Cookie 了解多少?
-
如何理解 HTTP 代理?
-
如何理解 HTTP 缓存及缓存代理?
-
为什么产生代理缓存?
-
源服务器的缓存控制
-
客户端的缓存控制
-
什么是跨域?浏览器如何拦截响应?如何解决?