fetch和XMLHttpRequest区别
fetch使用了Promise,这让它使用起来更加简洁,从而避免陷入”回调地狱”。
在将响应的文本信息转换成JSON格式前,需要先确保响应的状态码为200。 fetch()请求后返回的响应是一个stream对象,这就意味着我们在调用json()方法后会返回一个Promise,因为读取stream的过程是异步操作的。
fetch('./api/some.json')
.then(function(res) {
if (res.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + res.status);
return;
}
// 处理响应中的文本信息
res.json().then(function(data) {
console.log(data);
});
})
.catch(function(err) {
console.log('Fetch Error : %S', err);
})
宏任务微任务——promise()
宏任务中的方法: 1. script (可以理解为外层同步代码,作为入口 ) 2. setTimeout/setInterval
微任务中的方法: 1.Promise 2. nextTick
而他们的执行顺序 是 微任务 先输出 在输出 宏任务
setTimeout(() => {
console.log('定时器');
}, 0)
new Promise((resolve) => {
console.log('同步代码')
resolve('异步代码')
}).then((res) => {
console.log(res);
})
console.log('奥特曼');
// 宏任务和微任务
console.log('start')
setTimeout(()=>{
console.log('setTimeOut')
},0)
Promise.resolve().then(() => {
console.log('p1');
return Promise.resolve()
}).then(()=>{
console.log('p2');
})
Promise.resolve().then(() => {
console.log('p3');
})
console.log('end');
start
end
p1
p3
p2
setTimeOut
Promise()原理
JavaScript 中的 Promise 是一种用于处理异步操作的对象。它代表了一个异步操作的最终完成(或失败)及其结果值。以下是 Promise 的实现原理和工作机制的详细解释。
Promise 的基本概念
-
状态
:一个 Promise 对象有以下几种状态:
pending:初始状态,既不是成功,也不是失败状态。fulfilled:意味着操作成功完成。rejected:意味着操作失败。
-
结果:Promise 的结果(一个值),在
fulfilled状态下是成功的值,在rejected状态下是拒绝的原因。
Promise 的实现原理
以下是一个简化版的 Promise 实现,用于演示其基本原理:
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
let promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
解释
- 状态管理:Promise 初始状态为
pending。通过resolve和reject函数可以将状态变为fulfilled或rejected。一旦状态改变,就不能再修改。 - then 方法:
then方法接受两个回调函数,分别对应 Promise 解决和拒绝时的处理。它返回一个新的 Promise,以实现链式调用。若then方法中回调函数抛出错误,则返回的 Promise 进入rejected状态。 - 回调队列:在
pending状态时,then方法中的回调函数会被添加到相应的回调队列中(onFulfilledCallbacks和onRejectedCallbacks)。在状态变为fulfilled或rejected时,回调队列中的函数会被依次执行。 - 异步执行:为确保 Promise 的回调函数是异步执行的,我们使用
setTimeout将回调函数的执行推迟到 JavaScript 事件循环的下一个周期。 - resolvePromise 函数:这是一个辅助函数,用于处理
then方法中返回的值。如果返回值是一个 Promise,则需要等待其完成;如果是一个普通值,则直接resolve。
这只是一个简化版的实现,用于展示 Promise 的核心原理。在实际应用中,Promise 的实现会更加复杂,需要考虑更多的边界情况和兼容性问题。
vuex实现原理
uex 是 Vue.js 应用的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。下面是 Vuex 实现原理的关键点:
1. 核心概念
- State(状态) : Vuex 使用单一状态树,即一个对象就包含了全部应用层级状态。这样可以直接查找特定的状态,方便调试。
- Getter: 类似于 Vue 的计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生改变时才会被重新计算。
- Mutation(变更) : 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件,每个 mutation 都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
- Action: 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
- Module: 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决这个问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter,甚至是嵌套子模块——从上至下进行同样方式的分割。
2. 实现原理
2.1. State
Vuex 的 state 存储在一个单一对象中,通过 new Vuex.Store 创建。
const store = new Vuex.Store({
state: {
count: 0
}
})
2.2. Getter
通过 getter 来获取 state 的某些状态。
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
getCount: state => state.count
}
})
2.3. Mutation
Mutation 是 Vuex 中改变状态的唯一方法,它必须是同步函数。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
通过 store.commit 触发 mutation。
store.commit('increment')
2.4. Action
Action 类似于 mutation,不同的是:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
})
通过 store.dispatch 分发 action。
store.dispatch('incrementAsync')
2.5. Module
Vuex 允许我们将 store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter,甚至是嵌套子模块。
const moduleA = {
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } },
getters: { doubleCount (state) { return state.count * 2 } }
}
const moduleB = {
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
actions: { increment ({ commit }) { commit('increment') } },
getters: { doubleCount (state) { return state.count * 2 } }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
3. 数据流
Vuex 中的数据流如下:
- 组件调用:组件调用
dispatch去触发一个 action 或调用commit去触发一个 mutation。 - Action 调用:Action 可以包含异步操作,在其内部可以触发多个 mutation。
- Mutation 调用:Mutation 必须是同步函数,在它的回调函数里改变 state。
- State 变更:State 被响应式地更新。
这种单向数据流确保了数据的可追踪性,使应用的状态管理更加可预测和可维护。
公共最长前缀
// 最长公共前缀
// 先判断数组长度,若为0则返回空字符串
// 记录第一个字符串,循环对比,prefix逐渐缩短,判断是否存在公共前缀
function longestCommonPrefix(strs) {
if(!strs.length){
return ''
}
let prefix = strs[0]
for(let i = 0;i<strs.length;i++){
while(strs[i].indexOf(prefix) !== 0){
prefix = prefix.substring(0,prefix.length-1)
}
}
return prefix
}
console.log(longestCommonPrefix(["flower","flow","flight"]));