Skip to main content

杂项

Graphql

Graphql是一门对标传统RESTful的API查询语言,它的特色在于可以在前端指定服务端返回的数据字段类型、还能够将相关的查询聚合成一个请求。

通常前端可以使用graphql-request,这是一个小型轻便的Graphql Client库,相比其他的Graphql Client库(如Apollo-client)只缺少了部分高级能力。

// RESTful实现
fetch('/api/getNameById', {
body: JSON.stringify({id: 1})
})

// Graphql实现
import { request, gql } from 'graphql-request'

// graphql query的简写 用于查询数据
const query = gql`
{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}
`

// graphql mutation 用于修改数据/上传数据
const mutation = gql`
mutation AddMovie($title: String!, $releaseDate: Int!) {
insert_movies_one(object: { title: $title, releaseDate: $releaseDate }) {
title
releaseDate
}
}
`

request('https://api.graph.cool/simple/v1/movies', query).then((data) => console.log(data))

## WebSocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议,它使得客户端和服务器之间的数据交换变得更加简单。

```javascript
// 创建WebSocket连接
const socket = new WebSocket('ws://localhost:8080');

// 连接打开时触发
socket.addEventListener('open', function (event) {
console.log('Connected to WebSocket server');
socket.send('Hello Server!');
});

// 监听消息
socket.addEventListener('message', function (event) {
console.log('Message from server:', event.data);
});

// 监听错误
socket.addEventListener('error', function (event) {
console.error('WebSocket error:', event);
});

// 连接关闭时触发
socket.addEventListener('close', function (event) {
console.log('WebSocket connection closed');
});

// 发送消息
function sendMessage(message) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(message);
}
}

// 关闭连接
function closeConnection() {
socket.close();
}

Service Worker

Service Worker是运行在浏览器背后的脚本,它可以拦截网络请求、缓存资源、推送通知等。

// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
}

// sw.js文件内容
self.addEventListener('install', event => {
console.log('Service Worker installing');
// 缓存资源
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/',
'/index.html',
'/style.css',
'/script.js'
]);
})
);
});

self.addEventListener('fetch', event => {
console.log('Fetching:', event.request.url);
// 拦截请求,返回缓存的资源
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});

Web Workers

Web Workers允许在后台线程中运行JavaScript,不会阻塞主线程。

// 主线程
const worker = new Worker('worker.js');

// 向worker发送消息
worker.postMessage({ command: 'start', data: [1, 2, 3, 4, 5] });

// 监听worker返回的消息
worker.addEventListener('message', function(e) {
console.log('Worker said: ', e.data);
});

// worker.js文件内容
self.addEventListener('message', function(e) {
const { command, data } = e.data;

if (command === 'start') {
// 执行耗时操作
const result = data.reduce((sum, num) => sum + num, 0);

// 返回结果
self.postMessage({
result: result,
message: 'Calculation completed'
});
}
});

Intersection Observer

Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档视窗交叉状态的方法。

// 创建观察器
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible');
// 懒加载图片
if (entry.target.tagName === 'IMG') {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
}
});
}, {
threshold: 0.1, // 当10%的元素可见时触发
rootMargin: '50px' // 提前50px触发
});

// 观察元素
const images = document.querySelectorAll('img[data-src]');
images.forEach(img => observer.observe(img));

Mutation Observer

Mutation Observer API提供了监视对DOM树所做更改的能力。

// 创建观察器
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.');
} else if (mutation.type === 'attributes') {
console.log(`The ${mutation.attributeName} attribute was modified.`);
}
});
});

// 开始观察
const targetNode = document.getElementById('some-id');
const config = {
attributes: true,
childList: true,
subtree: true
};

observer.observe(targetNode, config);

// 停止观察
// observer.disconnect();

Performance API

Performance API提供了访问性能相关信息的方法。

// 测量代码执行时间
performance.mark('start-operation');

// 执行一些操作
for (let i = 0; i < 1000000; i++) {
// 一些计算
}

performance.mark('end-operation');
performance.measure('operation-duration', 'start-operation', 'end-operation');

// 获取测量结果
const measures = performance.getEntriesByType('measure');
console.log(measures[0].duration);

// 获取页面加载性能
const navigation = performance.getEntriesByType('navigation')[0];
console.log('DOM加载时间:', navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart);
console.log('页面加载时间:', navigation.loadEventEnd - navigation.loadEventStart);

// 获取资源加载性能
const resources = performance.getEntriesByType('resource');
resources.forEach(resource => {
console.log(`${resource.name}: ${resource.duration}ms`);
});

Proxy

Proxy对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。

// 基本用法
const target = {
name: 'John',
age: 30
};

const handler = {
get(target, property) {
console.log(`Getting ${property}`);
return target[property];
},
set(target, property, value) {
console.log(`Setting ${property} to ${value}`);
target[property] = value;
return true;
}
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // Getting name, John
proxy.age = 31; // Setting age to 31

// 数组代理示例
const arrayHandler = {
get(target, property) {
if (property === 'negative') {
return (index) => target[target.length + index];
}
return target[property];
}
};

const arr = new Proxy([1, 2, 3, 4, 5], arrayHandler);
console.log(arr.negative(-1)); // 5
console.log(arr.negative(-2)); // 4

Reflect

Reflect是一个内置的对象,它提供拦截JavaScript操作的方法。

// 基本用法
const obj = { name: 'John', age: 30 };

// 等价于 obj.name
console.log(Reflect.get(obj, 'name')); // John

// 等价于 obj.city = 'New York'
Reflect.set(obj, 'city', 'New York');

// 等价于 'name' in obj
console.log(Reflect.has(obj, 'name')); // true

// 等价于 delete obj.age
Reflect.deleteProperty(obj, 'age');

// 等价于 Object.keys(obj)
console.log(Reflect.ownKeys(obj)); // ['name', 'city']

// 与Proxy结合使用
const handler = {
get(target, property, receiver) {
console.log(`Getting ${property}`);
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
console.log(`Setting ${property} to ${value}`);
return Reflect.set(target, property, value, receiver);
}
};

const proxy = new Proxy({}, handler);