WebGIS开发面试题:前端篇(三)
1-1 同步代码,⼀行⼀行放在call stack执行1-2 遇到异步,会先"记录"下,等待时机(定时,网络请求)1-3 时机到了,就移动到Callback Queue1-4 Call Stack为空(即同步代码执行完)Event--Loop开发工作。1-5 轮询查找Callback Queue,如有则移动到Call Stack执行。1-6 继续轮询查询(永动机⼀样)
本系列内容主要介绍webgis开发过程中可能会遇到的常见面试题和答案,从前端到二维到三维,干货满满。记得关注我不走丢!
需要更多面试题、视频讲解、webgis教程的宝子戳↓↓↓
前几期内容点击下方链接:
1、同步异步
异步和单线程
- JS是单线程语⾔,只能同时做⼀件事。
- 浏览器和node.js已⽀持JS启动进程,如Web Worker。
- JS和DOM渲染共用同⼀个线程,因为JS可修改DOM结构。
异步是因为单线程而来的。
那么遇到等待(网络请求,定时任务)不能卡住,所以需要异步,异步是基于回调callback函数形式。
异步
//异步
console.log(100);
setTimeout(()=>{
console.log(200)
},1000) //callback
console.log(300);
//异步不会阻塞代码的执⾏。
同步
console.log(100);
alert(200);
console.log(300);
//同步会造成线程的阻塞。
总结
- JS 是单线程的语⾔
- 异步不会阻塞代码的执行
- 同步会阻塞代码执行
应用场景
网络请求,如何ajax-图片加载
定时任务,如setTimeout
题目
console.log("start");
let img = document.createElement("img");
img.onload = function(){
console.log("load");
}
img.src= "react.jpg";
console.log(img)
console.log("end")
2、promise
1-1 promise有几种状态
pending
fulfilled
rejected
pending
var p = new Promise(() => {
});
console.log(p)
fulfilled
var f = new Promise((resolve, reject) => {
resolve(1)
})
console.log(f)
rejected
var r = new Promise((resolve, reject) => {
reject(1)
})
console.log(r)
1-2 状态之间的切换
pending-->fulfilled
var f = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(1);
},1000)
})
console.log(f)
pending -->rejected
var r = new Promise((resolve, reject) => {
setTimeout(()=>{
reject(1);
},1000)
})
console.log(r)
1-3 触发状态
1-3-1 正常触发
1.正常情况下catch和then的返回值都是fulfilled的状态
2.触发函数中存在报错的情况,返回值是rejected的状态
// then
var p= new Promise((resolve, reject) => {
resolve(1);
reject(2);
})
var r = p.then(res=>{
console.log(res)
})
console.log(r) //fulfilled
//catch
var p= new Promise((resolve, reject) => {
reject(2);
})
var c = p.catch(err=>{
console.log(err)
})
console.log(c) //fulfilled
//catch 语句报错
var p= new Promise((resolve, reject) => {
reject(2);
})
var r = p.catch(res=>{
console.log(res)
throw "error"
})
console.log(r)
1-3-3 then和catch函数报错之后的触发
then和catch报错之后,获取的状态rejected,那么这种状态只能使用catch函数去调用
var p= new Promise((resolve, reject) => {
resolve(1);
reject(2);
})
var r = p.then(res=>{
console.log(res)
throw "error"
})
var t = r.catch(res=>{
console.log(res)
}) //
1-4 promise实现图片加载
const url ="react.jpg";
function loadImg(src){
return new Promise((resolve,reject)=>{
const img = document.createElement("img"); img.onload = ()=>{
resolve(img);
}
img.onerror = ()=>{
reject(new Error("图⽚加载失败"))
}
img.src = src;
})
}
loadImg(url).then(res=>{
console.log(res.width)
}).catch(err=>{
console.log(err)
})
3、Async,await-catch
(async()=>{
try{
var res = await jjf; }catch(err){
console.log(err); }
})();
Event-Loop
JS是单线程运行的
异步要基于回调来实现
event loop就是异步回调的实现原理
JS如何执行
从前到后,⼀行⼀行执行
如果某⼀行执行报错,则停止下⾯代码的执行
先把同步代码执行完,再执行异步代码
console.log("start"); setTimeout(()=>{
console.log("callback") },2000)
console.log("end");
同步代码执⾏完毕,就会启动event-loop,是浏览器内核启动的。
4、调用栈
1、console.log("start")执行先将其放在调用栈中,控制台输出"start"
2、console.log("start")执行完毕,将其从调用栈中移除
接着将setTimeout()函数到调用栈中,因为它是⼀个webAPI,那么在webAPI中有⼀个定时器。
3、调用栈中移除setTimeout(),执行console.log("end")
4、console.log("end")执行之后,也从调用栈中移除
5、同步代码执行完毕之后,Event Loop会不断的循环callback Queue,看里面是否有异步任务
6、最后Event Loop会将callback Queue中的代码放到调用栈⾥去
7、 callback在调用栈中被执行完毕之后,被从调用栈中移除
Tips:这地方会等待3s之后,callback函数才会被放到Callback Queue中,被Event Loop捕获。
总结:
1-1 同步代码,⼀行⼀行放在call stack执行
1-2 遇到异步,会先"记录"下,等待时机(定时,网络请求)
1-3 时机到了,就移动到Callback Queue
1-4 Call Stack为空(即同步代码执行完)Event--Loop开发工作。1-5 轮询查找Callback Queue,如有则移动到Call Stack执行。
1-6 继续轮询查询(永动机⼀样)
5、Event-Loop和Promise
- 微任务是ES6语法规定的
- 宏任务是由浏览器规定的
总结
- 宏任务有哪些?微任务有哪些?微任务触发时机更早
- 微任务、宏任务和DOM渲染的关系
- 微任务、宏任务和DOM渲染,在event loop的过程
6、Vue
Vue2 vs Vue3
1、Vue3相对于Vue2,最核心的是多了⼀个组合式API。
Vue2的缺陷,组件的业务逻辑过于复杂的情况,代码的逻辑分散到各处,代码比较混动。
2、多了⼀个新的组件Teleport,Suspense
3、组件中可以定义多个根节点
4、组件中是按需导入的Tree Shaking支持(ES Module)
Vue3不会将所有的API都打包进来,只会打包你用到的API。
5、⽣命周期会有不同
6、计算,监听,keep-alive语法堂都不⼀样了
7、定义响应式的方法不同
vue2 和vue 3的生命周期
⽣命周期函数,就是Vue在某⼀点自动执行的函数。
7、Vue3中的setup语法糖的优势
Vue3中的setup语法糖是⼀个新特性,它提供了⼀种新的方式来编写Vue组件。它的优势主要包 括:
1. 更加简洁的代码:使⽤setup语法糖,可以将组件选项分为两部分,⼀部分是props、data、 computed、watch等选项,另⼀部分是⽣命周期钩⼦函数。这样可以使代码更加简洁易懂。
2. 更加灵活的组件选项:在setup中可以使用响应式数据、计算属性、watch等,这样可以让组 件选项更加灵活,也可以更好地实现复杂的业务逻辑。
3. 更加清晰的逻辑分离:使用setup语法糖可以更好地将组件的逻辑分离,使得组件的数据和逻 辑更加清晰明了,便于维护和开发。
4. 更好的性能:由于Vue3中使用了Proxy来实现响应式数据,setup语法糖可以更好地利用Proxy 的优势,提⾼组件的性能。
综上所述,Vue3中的setup语法糖提供了更加简洁、灵活、清晰和⾼性能的方式来编写Vue组件, 可以帮助开发者更加⾼效地开发和维护Vue应用。
8、ref vs reactive
仅从代码层⾯讨论
1、ref只可以定义单个响应式数据
2、reactive可以定义多个响应式数据,和Vue2中的data类似
死死记住:ref本质也是 reactive,ref(obj)等价于 reactive({value: obj})
- vue3中实现响应式数据的方法是就是使用ref和reactive,所谓响应式就是界面和数据同步,能实现实时更新。
- vue2中响应式是通过defineProperty实现的,vue3中是通过ES6的Proxy来实现的。
<template>
<div></div>
</template>
<script setup >
import { ref, isRef, reactive } from "vue";
const count = ref(10);
const state = reactive({
value: 20,
});
console.log(count.value);
console.log(isRef(count));
console.log(state.value)
</script>
<style scoped>
</style>
9、vue3如何设置全局变量
注意,使用全局变量是有⼀定的⻛险的,因为它们可能被不同的组件或库使用,并且可能会被不小 心覆盖或修改。因此,应该谨慎使用全局变量,最好将它们限制在必要的范围内。
1、app.config.globalProperties
要设置Vue 3全局变量,可以使用Vue 3提供的createApp方法
1、main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
app.config.globalProperties.$http = 'Hello, world!'
app.mount('#app')
2、组件中使用
<template>App</template>
<script setup>
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance();
console.log(proxy.$http)
</script>
2、provide - inject
main.js
const app = createApp(App);
app.provide("$http","http")
app.mount('#app')
<template>
<div>App</div>
</template>
<script setup>
import { inject } from 'vue';
const http = inject("$http");
console.log(http)
</script>
3、Vue和ol
1、设置原型
/* 定义原型 */
export const prototype = app.config.globalProperties;
2、在组件中设置原型属性的值
<template>
<div id="map"></div>
</template>
<script setup>
import { onMounted } from "vue";
import { gaode } from "../map_libs/gaode"; import { prototype } from "../main"; //重要 onMounted(() => {
/* Pinia 全局对象 */
const map = new ol.Map({
target: "map",
layers: [gaode],
view: new ol.View({
projection: "EPSG:4326",
center: [114.3, 30.5],
zoom: 4,
}),
});
prototype.$map = map; //重要
});
</script>
3、封装获取全局属性的工具函数
可以帮助我们更好的获取Map,这个函数建议放置自动导包中
/* 推荐放到⾃动导包中 */
import { getCurrentInstance } from 'vue'
function useGlobalMap() {
const { proxy } = getCurrentInstance();
/* getCurrentInstance().appContext.config.globalProperties.$map */ return (proxy.$map);
}
export { useGlobalMap };
4、组件中使用全局Map
<template>control</template>
<script setup>
import { onMounted } from "vue";
import { useGlobalMap } from "../utils/globalMap"; onMounted(() => {
console.log(useGlobalMap());
});
</script>
10、Vuex和Pinia有什么区别,那个更好用?
Vuex 和Pinia 都是用于Vue.js 应用程序状态管理的库,它们的主要目的是将应用程序状态集中管 理,使得应用程序的状态变得可预测和可维护。然而,它们在实现上存在⼀些不同。
以下是Vuex 和Pinia 的⼀些区别:
1. Vuex 是Vue.js 官方提供的状态管理库,而Pinia 是社区驱动的状态管理库。
2. Vuex 使用单⼀的全局状态树来管理整个应用程序的状态,而Pinia 使用多个独立的状态存储 来管理状态,每个存储都可以包含自己的状态、getter、mutation 和action。
3. 在Vuex 中,所有的状态、mutation 和action 都是全局的,任何组件都可以直接访问它们。 而在Pinia 中,状态存储只能通过组件实例来访问和修改,这使得状态变得更加可控和预测。
4. 在使用Vuex 时,需要先创建⼀个store,然后将它注入到根 Vue 实例中。而在使用Pinia 时,不需要创建⼀个全局的store,而是可以在组件内部直接使用状态存储。
5. Pinia 支持TypeScript,它提供了更好的类型支持和自动化类型推断。
总之,Vuex 和Pinia都是⾮常优秀的状态管理库,具体选择哪⼀个取决于项目的需求和开发者的 个⼈喜好。
1、Vuex
2、Pinia
核心概念
1、State
2、Getter
3、Action
代码实现:
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => { const count = ref(0)
const doubleCount = computed(() => count.value * 2) function increment() {
count.value++
}
return { count, doubleCount, increment }
})
更多推荐
所有评论(0)