回调函数
- js中函数是对象
let fun =function(){
console.log('这是一个函数')
}
fun.name="函数"
fun.age="10"
console.log(fun)
console.log(fun.name+fun.age)
fun()
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用。既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回
- 对象当做参数进行调用
function fn(arg1, arg2, callback) {
var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
callback(num); //传递结果
}
function callbackfun(num) {
console.log("Callback called! Num: " + num); //结果为10和20之间的随机数
}
fn(10, 20, callbackfun);
一个回调函数,也被称为高阶函数,是一个被作为参数传递给另一个函数(在这里我们把另一个函数叫做“otherFunction”)的函数,回调函数在otherFunction中被调用。
一个回调函数本质上是一种编程模式(为一个常见问题创建的解决方案),因此,使用回调函数也叫做回调模式。
因此callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。
- 同步中也可以用回调
是所有异步编程方案的根基,回调函数可以理解为一件你想要做的事情,但是你不知道你依赖的任务什么时候能完成
- 异步中的回调函数
function findAll() {
axios.get("http://localhost:8090/findAll")
.then(res => {
this.userList = res.data;
this.userList.splice(0, 0)
console.log(this.userList)
})
.catch(args => {})
}
res=>{}写法实际上就是一个匿名函数,即一个lambda表达式。
浏览器
js中的异步调用
js ajax请求,异步请求。
-
JS引擎是单线程的
-
浏览器内核
- 事件循环(Event Loop)和任务队列(Task Queue)
JS 是单线程的,但是却能执行异步任务,这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue)。
**事件循环:**JS 会创建一个类似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。
每次 Tick 的过程就是查看是否有待处理事件,如果有则取出相关事件及回调函数放入执行栈中由主线程执行。
待处理的事件会存储在一个任务队列中,也就是每次 Tick 会查看任务队列中是否有需要执行的任务。
**任务队列:**异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如 onclick, setTimeout, ajax 处理的方式都不同,这些异步操作是由浏览器内核的 webcore 来执行的,webcore 包含上图中的3种 webAPI,分别是 DOM Binding、network、timer模块。
**主线程:**JS 只有一个线程,称之为主线程。而事件循环是主线程中执行栈里的代码执行完毕之后,才开始执行的。所以,主线程中要执行的代码时间过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来观察要执行的事件回调,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中由主线程执行。
Ajax异步
很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行onreadystatechange所设置的函数。
vue生命周期
const app = new Vue({
el: "#app",
data: {
msg: "vue生命周期"
},
//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
beforeCreate() {
console.log("beforeCreate")
},
//在实例创建完成后被立即调用
created() {
console.log("created")
},
//在挂载开始之前被调用:相关的 render 函数首次被调用。
beforeMount() {
console.log("beforeMount")
},
//实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。
mounted() {
console.log("mounted")
},
//数据更新时调用,发生在虚拟 DOM 打补丁之前
beforeUpdate() {
console.log("beforeUpdate")
},
//由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
updated() {
console.log("updated")
},
//实例销毁之前调用。在这一步,实例仍然完全可用
beforeDestroy() {
console.log("beforeDestroy")
},
//实例销毁后调用。
destroyed() {
console.log("destroyed")
},
methods: {
destroy() {
this.$destroy()
}
}
})
aysno awiait
用法:
-
async 用来标识方法。
-
await用来标识有回调函数的异步方法将异步函数的返回值赋值给变量
let res = await axios.get(url) //还有解构赋值操作 //可以用来只用来接收变量 let {data:data,status:status}=await axios.get(url)
async-await是axios为了简化.then()的一种全新的语法,语法如此,没有为什么。该语法只能用到ajax请求中。
定义异步请求的回调函数由一条语句写到了一个async标识的函数中。主要是为代码的优美。
const app = new Vue({
el: "#app",
data: {
hello: "helloVue",
div: "<h3>我是一个标题标签</h3>",
userList: [],
msg: []
},
methods: {
findAll: async function() {
let url = `/findAll`
let res = await axios.get(url)
// let {
// data: data,
// status: status
// } = await axios.get(url)
console.log(res.data)
},
//同步和异步的代码块混在一起而且函数定义在一条语句
findAll2: function() {
this.userList.push({
name: 5
})
axios.get("http://localhost:8090/findAll")
.then(res => {
this.userList = res.data;
this.userList.splice(0, 0)
console.log(this.userList)
})
.catch(args => {})
console.log("同步部分")
},
//函数定义在另外一个地方,但是仍然异步调用部分和同步部分混杂。而且异步回调和异步调用不在一起。
findAll3: function() {
let fun = function(res) {
this.userList = res.data;
this.userList.splice(0, 0)
console.log(this.userList)
}
}
this.userList.push({
name: 5
})
axios.get("http://localhost:8090/findAll")
.then(fun)
.catch(args => {})
console.log("同步部分")
},
}
})
vue双向绑定
M: model 数据层
V: view 视图层
VM: 视图数据的控制层
流程:
-
Model变化, 虚拟DOM操作内存数据变化. 所以页面变化.
-
View变化, 虚拟DOM操作内存数据变化, 数据变化.
- 数据绑定和DOM的监听
虚拟DOM和数据怎么绑定。
虚拟DOM vue到底有什么用
双向绑定:
虚拟DOM与真实DOM的区别(注意:需不需要虚拟DOM,其实与框架的DOM操作机制有关):
- 虚拟DOM不会进行排版与重绘操作
- 虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!),最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
- 真实DOM频繁排版与重绘的效率是相当低的
- 虚拟DOM有效降低大面积(真实DOM节点)的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部(同2)
面向切面:
可以通过预编译方式和运行其动态代理实现在不修改源代码的情况下给程序动态统一添加某种特定功能的一种技术。
封装类。
https://blog.csdn.net/u012932876/article/details/117696990
https://blog.csdn.net/u013782203/article/details/51799427