位运算
var a;
奇偶 a&1
取相反数-n = ~(n - 1) = ~n + 1
将n的二进制表示中最右侧的一个1去掉 n & (n - 1)
firebase
in: FirebaseError: ‘IN’ supports up to 10 comparison values.
react
官方文档
Thinking in React : how to build a react app
https://react.dev/learn/thinking-in-react
Step 3: Find the minimal but complete representation of UI state
useEffect:
useEffect
通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。
所谓的**“副作用”**,举个通俗一点的例子,假如感冒了本来吃点药就没事了,但是吃了药发现身体过敏了,而这个“过敏”就是副作用。
放到React中,本来只是想渲染DOM展示到页面上,但除了DOM之外还有数据,而这些数据必须从外部的数据源中获取,这个“获取外部数据源”的过程就是副作用。
需要清除的 effect,可以防止引起内存泄露!
如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它:
无参数,组件的初始化和更新都会执行
[]初始化调用一次之后不再执行,相当于componentDidMount
useEffect, useState 用来视图刷新。 不支持 异步
对象和数组是通过引用进行比较的
更新的是组件,
state只要变化,视图就会渲染,而useEffect只是渲染时候做些其他事情
Counter
内部状态改变,会使得Counter全都更新,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const BigNumber = ({ number }) => ( <div style={{ fontWeight: 700, fontSize: 36 }}>{number}</div> ); const SomeDecoration = () => <div>Hooray!</div> const Counter = () => { const [count, setCount] = useState(0); const handleButtonClick = useCallback(() => setCount(count => count + 1), []); return ( <div> <BigNumber number={count} /> <button onClick={handleButtonClick}>Increment</button> <SomeDecoration /> </div> ); }; const App = () => ( <> <Counter /> <footer> <a href="https://skk.moe/">Sukka</a> </footer> </> );
01.React.createRef()
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。
(1)挂载HTML元素,返回真实的DOM
(2)挂载React元素,返回render后的实例对象
React.createRef() 调用后返回一个容器,该容器可以存储被ref标识的节点
组件式
像这样, 头像样式 到处用,
函数组件中使用
useRef
使用current
属性访问挂载的对象
ref.current 返回null
02. React.Suspense
React.Suspense
是一种虚拟组件(类似于 Fragment,仅用作类型标识)。通常用来包裹住延迟加载组件。
提供 fallback
属性,用来在组件的延迟加载过程中显式某些 React 元素
03. props 和 state
如果下层组件需要使用上层组件的数据或方法,上层组件就可以通过下层组件的 props
属性进行传递,因此 props
是组件对外的接口。组件除了使用上层组件传递的数据外,自身也可能需要维护管理数据,这就是组件对内的接口 state
。
props
是组件的只读属性,组件内部不能直接修改 props
,要想修改 props
,只能在该组件的上层组件中修改。在组件状态上移的场景中,父组件正是通过子组件的 props
,传递给子组件其所需要的状态。
state
的主要作用是用于组件保存、控制以及修改自己的状态,它只能在 constructor
中初始化,它是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState
来修改,修改 state
属性会导致组件的重新渲染。
04. 函数式组件和类组件
下面,是具体的 class 与 Hooks 的生命周期对应关系:
class 组件
Hooks 组件
constructor
useState
getDerivedStateFromProps
useState 里面 update 函数
shouldComponentUpdate
useMemo
render
函数本身
componentDidMount
useEffect
componentDidUpdate
useEffect
componentWillUnmount
useEffect 里面返回的函数
componentDidCatch
无
getDerivedStateFromError
无
05. classnames
1.在react
中想要动态添加className
时,通常会使用classnames
这个库。
2.我们可以通过npm安装 :npm install classnames
2.classnames
是一个函数,使用的形式较多,记住常用的使用方法即可:
(1)传入一个对象:classnames({class1:true,class2:false})
,true
表示相应的class生效,反之false表示不生效。
(2)接受多个类名:classnames(class1,class2,{ class3:false })
06. React 组件通信
父组件通过 props 给子组件传参,子组件通过触发父组件提供的回调函数来给父组件传递数据
React.Context
自定义事件
redux/mobx 之类的状态管理器
状态props提升, 将数据都放置在最近父亲组件
socket.io 在react 中
https://socket.io/how-to/use-with-react
context
创建context, context是一个存储数据的对象
1 2 import React , { createContext, useState, useContext } from 'react' ;const NodeContext = createContext ();
创建provider, 通过provider组件的value 向组件传递数据,向组件暴露state,
1 2 3 4 5 6 7 8 export const NodeProvider = ({ children } ) => { const [nodeUrl, setNodeUrl] = useState ('http://localhost:3001' ); return ( <NodeContext.Provider value ={{ nodeUrl , setNodeUrl }}> {children} {/* children 是指包含的所有子组件 */} </NodeContext.Provider > ); };
使用context
1 const { nodeUrl, setNodeUrl } = useContext (NodeContext );
(额外) 将其包装为一个自定义hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import React , { createContext, useState, useContext } from 'react' ;const NodeContext = createContext ();export const useNode = ( ) => useContext (NodeContext ); export const NodeProvider = ({ children } ) => { const [nodeUrl, setNodeUrl] = useState ('http://localhost:3001' ); return ( <NodeContext.Provider value ={{ nodeUrl , setNodeUrl }}> {children} </NodeContext.Provider > ); }; const { nodeUrl, setNodeUrl } = useNode ();
自定义hook和context联系区别
使用自定义hook内部状态:
适用于在单个组件中管理状态,不需要共享状态;
适用于状态只需要在自定义hook内部使用的情况,不需要暴露给其他组件;
适用于状态更新只需要在自定义hook内部处理,不需要通知其他组件。
使用Context共享状态:
适用于需要在多个组件中共享状态的情况;
适用于需要在不同的组件之间传递数据的情况;
适用于需要监听状态变化并及时通知其他组件更新的情况。
问题
1. 在 useEffect、useCallback、useMemo
中获取到的 state、props
为什么是旧值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function Counter() { const [count, setCount] = useState(0); useEffect(() => { const handleClick = function() { console.log('count: ', count); } window.addEventListener('click', handleClick, false) return () => { window.removeEventListener('click', handleClick, false) }; }, []); return <p onClick={() => setCount(count + 1)}>clicked {count} times</p>; }
还是上一个例子,如果此时给 useEffect
设置空数组为依赖项,那么无论 count
改变了多少次,点击 window
,打印出来的 count
依然是 0
2. useEffect
事件注册的闭包陷阱
1 2 3 4 5 6 7 8 9 useEffect(() => { AppStore.on("send-msg", ()=>{ console.log("Event: send-msg",chatId) update(chatId) }) return () => { AppStore.off("send-msg", update) } }, [])
原因:事件函数获取到的chatId
永远是旧的
办法:[chatId]
保证是最新值
3.Warning: React has detected a change in the order of Hooks called by DialogDetails. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
useContext useContext
undefined useState
MUI
mui5的menu anchorEl什么意思?
在mui5中,Menu组件是一个弹出式菜单,它可以在点击一个按钮或一个链接时弹出,然后允许用户从菜单中选择一个选项。
anchorEl是Menu组件中的一个属性,它指定了Menu组件相对于哪个元素进行定位。当用户点击指定的元素时,Menu组件将相对于该元素弹出。
例如,如果你想在一个按钮上创建一个Menu组件,你可以将这个按钮的元素作为anchorEl属性的值。这样当用户点击按钮时,Menu组件将会弹出在按钮的位置上。
进度和问题
[x] 刚开始,消息列表没有滑倒底部。:分清数据更新,视图更新流程: 更新数据后useEfffect准确视图
[x] 基本聊天刷新已经实现
[ ] react子组件异步函数有时候获取不到props值
[ ] 数据库速度慢,有时候刚插入,就要获取更新, 数据库还没插进去呢
CSS
word-wrap:属性允许长单词或 URL 地址换行到下一行。
text-overflow:;当文本溢出包含它的元素时,应该如何显示。
white-space属性指定元素内的空白怎样处理。是否环行
flex-grow: 1; 当父元素有剩余空间时,如何占用,默认为0
flex-basis
指定了 flex 元素在主轴方向上的初始大小。
object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。
user-select 属性规定是否能选取元素的文本。
flex: 1 1 75%; /* 三个值:flex-grow | flex-shrink | flex-basis */
align-self 属性定义flex子项单独在侧轴(纵轴)方向上的对齐方式。
mask:url()
允许使用者通过遮罩或者裁切特定区域的图片的方式来隐藏一个元素的部分或者全部可见区域。
swagger
swagger-ui-express
是一个用于在 Express.js 应用中集成 Swagger UI 的中间件。
Swagger UI 是一个前端界面,根据document生成,使得开发者可以方便地查看和测试 API。
swagger-jsdoc
是document 文档
1 2 3 4 5 6 7 8 9 10 11 12 const express = require ('express' );const swaggerUi = require ('swagger-ui-express' );const swaggerDocument = require ('./swagger.json' ); const app = express ();app.use ('/api-docs' , swaggerUi.serve , swaggerUi.setup (swaggerDocument)); app.listen (3000 , () => { console .log ('服务器运行在端口 3000' ); });
Nodejs
多线程
worker_threads
模块:
如mine挖矿while循环会占用阻塞线程,如果放在主线程,那么就会阻塞其他网络请求异步线程的返回。
主线程管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Worker } = require ('worker_threads' );const worker = new Worker ('./miner.js' );worker.on ('message' , (msg ) => { console .log ('Message from worker:' , msg); }); worker.on ('error' , (error ) => { console .error ('Worker error:' , error); }); worker.on ('exit' , (code ) => { if (code !== 0 ) { console .error (`Worker stopped with exit code ${code} ` ); } }); worker.postMessage ({ start : true });
worker线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const { parentPort } = require ('worker_threads' );parentPort.on ('message' , (message ) => { if (message.start ) { let mined = false ; while (!mined) { mined = true ; parentPort.postMessage ({ mined : true , block : {} }); } } });
workerdata基于消息机制通信,所以workerdata都是字符串或者基本类型传输,是浅拷贝,不能传递复杂对象。 可以通过序列化反序列化完成。
parentPort.postMessage({ type: “newBlock”, newBlock }); 可以直接传递对象
websocket
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它被设计为可以在客户端和服务器之间建立一个长时间存在的连接,这样客户端和服务器可以在任何时间相互发送数据,而不需要传统的 HTTP 请求和响应机制。
socket._socket.remoteAddress + ':' + socket._socket.remotePort
启动本地webserver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const WebSocket = require ('ws' );const wss = new WebSocket .Server ({ port : 8080 });wss.on ('connection' , function connection (ws ) { console .log ('A new client connected' ); ws.on ('message' , function incoming (message ) { console .log ('Received:' , message); ws.send ('Hello from server' ); }); ws.on ('close' , function ( ) { console .log ('Client disconnected' ); }); ws.on ('error' , function (error ) { console .error ('WebSocket error observed:' , error); }); ws.send ('Welcome new client!' ); }); console .log ('WebSocket server is running on ws://localhost:8080' );
连接到对端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const newPeer = 'ws://localhost:8080' ;const socket = new WebSocket (newPeer);socket.addEventListener ('open' , function (event ) { console .log ('WebSocket is connected' ); socket.send ('Hello Server!' ); }); socket.addEventListener ('message' , function (event ) { console .log ('Message from server:' , event.data ); }); socket.addEventListener ('close' , function (event ) { console .log ('WebSocket is closed now.' ); }); socket.addEventListener ('error' , function (event ) { console .error ('WebSocket error observed:' , event); }); socket.send ('Another message to server' );
send 和 write 区别
send
和 recv
:更通用,可以在 TCP 和 UDP 套接字中使用,支持额外的标志位。
write
和 read
:更常用于流式套接字(如 TCP),在 Node.js 中常用于 TCP 套接字。
通常使用 write
和 read
(或 data
事件)处理 TCP 套接字,而使用 send
和 message
事件处理 WebSocket。
express
### app.get(‘/blocks’, function (req, res) {})
app.listen([port], [hostname], [backlog], [callback])
返回一个 http.Server
实例。提供各种方法控制服务器。
如server.close
app.use 注册中间件
// 解析 application/json 类型的请求体
app.use(bodyParser.json());
模板引擎:
使用:
设置
views
, the directory where the template files are located. Eg: app.set('views', './views')
. This defaults to the views
directory in the application root directory.
view engine
, the template engine to use. For example, to use the Pug template engine: app.set('view engine', 'pug')
.
index.pug
1 2 3 4 5 html head title= title body h1= message
渲染
1 2 3 app.get ('/' , function (req, res ) { res.render ('index' , { title : 'Hey' , message : 'Hello there!' }) })
app.locals
locals
对象中的变量可以在整个应用程序中访问,并且在渲染视图时自动传递给模板引擎。
eg. formatters是自定义的属性变量
1 2 3 app.locals .formatters = { uppercase : str => str.toUpperCase (), lowercase : str => str.toLowerCase () };
Websocket 是一种自然的全双工、双向、单套接字连接 ,解决了 HTTP 协议中不适合于实时通信的问题。
客户端
const io = require(‘socket.io-client’);
io(url[, options])
url (字符串)默认的指向widnow.location
option (Object)forceNew (布尔型)是否重用当前已存在的链接。
Return Socket
密码库
elliptic
库 : 专门用来椭圆算法ECC
crypto
库:更加复杂广泛
密钥对生成格式:
SPKI :主要用于存储和传输公钥,常用于 X.509 证书等。
PKCS8 :主要用于存储和传输私钥,可以选择性地加密私钥。
ECDSA:
签名值格式为(r,s), 不同系统库使用不同编码格式表示值,最常见的两种格式是 IEEE P1363(windows web) 和 DER (openssk)
如p-256曲线,r,s均为32字节。
IEEE P1363 和 DER 编码格式的区别:
IEEE P1363 格式
结构 :r
和 s
被简单地连接在一起,形成一个固定长度的字节串。
长度 :r
和 s
的每个值都被填充到固定的长度,具体长度取决于椭圆曲线的大小。例如,对于 P-256 曲线,r
和 s
都是 32 字节长(共 64 字节)。
简单性 :没有额外的元数据或长度信息,因此非常简单,但缺乏灵活性。
DER 格式
结构 :DER(Distinguished Encoding Rules)是一种 ASN.1 编码规范。r
和 s
被编码为两个整数(INTEGER 类型),并通过 SEQUENCE 结构打包在一起。
灵活性 :DER 格式灵活地表示整数长度(没有固定的字节数限制),并包括元数据(如类型标识和长度)。
序列化 :DER 格式的签名通常比 IEEE P1363 格式稍长,因为它包含了类型和长度信息。
如r = 0x1234567890abcdef
,s = 0xfedcba0987654321
IEEE P1363 格式0000000000000000000000000000000000000000000000001234567890abcdef000000000000000000000000000000000000000000000000fedcba0987654321
der格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // r 的 DER 编码 02 // INTEGER 类型标识符 08 // r 的长度为 8 字节 1234567890abcdef // r 的值 // s 的 DER 编码 02 // INTEGER 类型标识符 08 // s 的长度为 8 字节 fedcba0987654321 // s 的值 // 完整的 DER 编码签名 30 // SEQUENCE 类型标识符 12 // 总长度为 18 字节 02 08 1234567890abcdef // r 的编码 02 08 fedcba0987654321 // s 的编码
.env
异步
Buffer vs ArrayBuffer
都是用来处理二进制数据的,比如文件读写、网络、加解密。
前者是Nodejs的,后者是标准JS对象。
定时器
场景:while 挖矿占用过高,通过settimeout限制。 但是settimeout是异步的,导致会直接返回undefined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function generateNextBlock (data ) { var timestamp = new Date ().toUTCString (); var hash = "" ; let nouce = 0 ; function whileNounce ( ) { hash = Block .caculateHash ( info.index , timestamp, data, info.previousHash , info.difficulty , nouce ); if (hasMatchesDifficulty (hash, info.difficulty )) { return new Block ( info.index , timestamp, info.difficulty , nouce, data, info.previousHash , hash ); } else { nouce ++; setTimeout (whileNounce, 100 ) } } return whileNounce (); }
解决: 不直接返回。只在符合条件返回。
回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function generateNextBlock (data, callback ) {. function whileNounce ( ) { if (hasMatchesDifficulty (hash, info.difficulty )) { const newblock = new Block ( info.index , timestamp, info.difficulty , nouce, data, info.previousHash , hash ); callback (newblock) } else { nouce ++; setTimeout (whileNounce, 100 ) } } whileNounce (); }
Promise异步 (async/await)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 function generateNextBlock (data ) { return new Promise ((resolve, reject ) => { var timestamp = new Date ().toUTCString (); var hash = "" ; let nonce = 0 ; function whileNounce ( ) { hash = Block .caculateHash ( info.index , timestamp, data, info.previousHash , info.difficulty , nonce ); if (hasMatchesDifficulty (hash, info.difficulty )) { const newBlock = new Block ( info.index , timestamp, info.difficulty , nonce, data, info.previousHash , hash ); resolve (newBlock); } else { nonce++; setTimeout (whileNounce, 100 ); } } whileNounce (); }); } generateNextBlock (data) .then (newBlock => { console .log ('生成的区块:' , newBlock); }) .catch (err => { console .error ('挖矿出错:' , err); });
JavaScript
ArrayBuffer:
字节数组
Uint8Array
: 无符号数组,
Map
const
const
关键字用于声明一个常量引用,这意味着一旦声明,变量的引用不能被重新赋值。但是,这并不意味着它所引用的对象或数组的内容是不可变的。可以使用 const
来声明类的实例,这个实例的引用不能被改变,但实例本身的属性和方法仍然可以被修改。
数组
a.concat(b)
将当前元素(子数组)合并到累积器 a
中
[1, 2].concat([3, 4])
的结果是 [1, 2, 3, 4]
。
flat()
嵌套数组 扁平化:.
JavaScript 的数组是一种泛型容器,它可以容纳任意类型的对象,但它并不保持对象的构造函数信息或类类型。
类对象放入数组 再拿出来就是Object丢失类型了
1 class Person { constructor (name, age ) { this .name = name; this .age = age; } greet ( ) { return `Hello, my name is ${this .name} .` ; } }
json只是一种数据格式, 可以表示字符串, 也可以表示js对象
unicode: 符号集,规定了符号对应的二进制。
utf-8:unicode的一种格式,规定unicode二进制的存储 划分方式。
UTF-8 的编码规则很简单,只有二条:
对于单字节的符号,字节的第一位设为0
,后面 7 位为这个符号的码点。因此对于英语字母,UTF-8 编码和 ASCII 编码是相同的。
对于n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的码点。
bitArray: 32-bit words
toBits():
符号的unicode二进制, 组装为bitArray
partial():
将不足32-bit的,扩充为bitArray
DOM
Element.scrollIntoView()
方法会滚动元素的父容器,使被调用 scrollIntoView() 的元素对用户可见。
类型判断
判断是否是数组:
if (Array.isArray(data)) {
console.error(“Invalid Transactions data”);
return data; // 创世区块不是数组
}
typeof 数组 返回的是object
Array
1 2 3 4 5 6 const ages = [32 , 33 , 16 , 40 ];const result = ages.filter (checkAdult);function checkAdult (age ) { return age >= 18 ; }
…
扩展运算符(…)是ES6的语法,用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。
类
导入导出
exports 用于js
nodejs导入:require、module.exports
JavaScript 和 Node.js有不同的模块系统:
JavaScript(ES6模块)
导出
允许在一个文件定义变量、函数、类,并导出
命名导出 (Named Export) :
可以导出多个值,每个值有一个名字。
1 2 3 4 5 export const name = 'Alice' ;export function sayHello ( ) { console .log ('Hello' ); }
默认导出 (Default Export) :
一个文件(模块)只能有一个默认导出,常用于导出主要功能或值
1 2 3 const mainFunction = ( ) => { };export default mainFunction;
导入
导入 命名导出:
1 import {name, sayHello} from './module.js'
导入 默认导出:
1 import mainFunc from './module.js'
重命名导入 命名导出:
1 import {name as myname, sayhello as hello} from './module.js'
Nodejs(CommanJS模块)
同样的,可以导入导出变量、函数、类
导出
使用module.exports
导出, exports
只是他的简写
1 2 3 4 5 6 7 module .exports = { name : 'alice' , hello : ()=> { console .log ('hello' ) }, Student , }
module.exports = new EventEmitter(); 单例,只有第一次加载时候创建
导入
使用require
导入。
1 2 3 const mymodule = require ('./module.js' )mymodule.name mymodule.hello ()
1 const {name,hello} = require ('./module.js' )
区别
语法 :
ES6 模块是语言层级的特性,支持静态分析,能够提前知道依赖关系。
CommonJS 模块在运行时解析依赖。
ramda库
时间
在 JavaScript 中,Date
对象提供了多种方法来操作和格式化日期和时间。
toISOString
:
返回一个 ISO 格式的日期字符串 (UTC 时间)。
格式为:YYYY-MM-DDTHH:mm:ss.sssZ
。
1 2 const date = new Date ();console .log (date.toISOString ());
toUTCString
:
返回一个基于世界时(UTC)的字符串表示形式。
这种格式通常用于 HTTP 标头等应用。
1 2 const date = new Date ();console .log (date.toUTCString ());
toLocaleString
:
返回一个表示日期的字符串,根据本地时间格式化。
可以接受两个可选参数,用于指定语言和格式化选项。
1 2 3 const date = new Date ();console .log (date.toLocaleString ()); console .log (date.toLocaleString ('en-GB' ));
toDateString
:
1 2 const date = new Date ();console .log (date.toDateString ());
toTimeString
:
1 2 const date = new Date ();console .log (date.toTimeString ());
toLocaleDateString
:
返回一个表示日期部分的字符串,根据本地时间格式化。
可以接受两个可选参数,用于指定语言和格式化选项。
1 2 3 const date = new Date ();console .log (date.toLocaleDateString ()); console .log (date.toLocaleDateString ('en-GB' ));
toLocaleTimeString
:
返回一个表示时间部分的字符串,根据本地时间格式化。
可以接受两个可选参数,用于指定语言和格式化选项。
1 2 3 const date = new Date ();console .log (date.toLocaleTimeString ()); console .log (date.toLocaleTimeString ('en-GB' ));
getTime
:
返回自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。
1 2 const date = new Date ();console .log (date.getTime ());
getTimezoneOffset
:
1 2 const date = new Date ();console .log (date.getTimezoneOffset ());
Date.now
:
返回自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数(静态方法)。
1 console .log (Date .now ());
Promise
Promise
是一种用于处理异步操作的对象。它代表一个在未来某个时间点可能会完成或失败的操作及其结果值。
Promise
构造器函数
主要用于包装不支持 promise(返回值不是 Promise
)的函数。
如setTimeout(()=>{},3000);
返回值是定时器的编号。(异步操作)
构造器参数实为一个异步函数,在内部进行异步任务,并且设定promise
对象的状态:resolved
,reject
构造promise
对象时,将参数(异步函数、成功函数、拒绝函数)绑定在promise
对象上, 并且执行:异步操作、设定promise
状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const myFirstPromise = new Promise ((resolve, reject ) => { }); function myAsyncFunction (url ) { return new Promise ((resolve, reject ) => { const xhr = new XMLHttpRequest () xhr.open ("GET" , url) xhr.onload = () => resolve (xhr.responseText ) xhr.onerror = () => reject (xhr.statusText ) xhr.send () }); }
2.then()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const resolvedProm = Promise .resolve (33 );let thenProm = resolvedProm.then (value => { console .log ("this gets called after the end of the main stack. the value received and returned is: " + value); return value; }); console .log (thenProm);setTimeout (() => { console .log (thenProm); });
3.catch()
当 Promise
为 rejected
时 ,处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var p1 = new Promise (function (resolve, reject ) { throw 'Uh-oh!' ; }); p1.catch (function (e ) { console .log (e); }); var p2 = new Promise (function (resolve, reject ) { setTimeout (function ( ) { throw 'Uncaught Exception!' ; }, 1000 ); }); p2.catch (function (e ) { console .log (e); }); var p3 = new Promise (function (resolve, reject ) { resolve (); throw 'Silenced Exception!' ; }); p3.catch (function (e ) { console .log (e); });
Promise.all()
背景:map里面每个元素都要异步函数返回
1 2 3 4 5 6 7 tx.inputs = tx.inputs .map (async (txin, index) => { console .log (`sign txin ${index} ` ) txin.signature = await MyCrypto .sign (tx.id , privateKey) console .log (`signed txin ${index} with signature ${txin.signature} ` ) return txin; });
这样写法不正确,每个返回值是promise
Promise.all() 会等待所有这些promise完成,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 async function signTransaction (tx, privateKey ) { const signedInputs = await Promise .all (tx.inputs .map (async (txin, index) => { txin.signature = await MyCrypto .sign (tx.id , privateKey); return txin; })); tx.inputs = signedInputs; tx.publicKey = address; return tx; }
await等待Promise.all返回结果
1 2 3 4 5 6 7 8 9 10 const promise1 = Promise .resolve (3 );const promise2 = 42 ;const promise3 = new Promise ((resolve, reject ) => { setTimeout (resolve, 100 , 'foo' ); }); Promise .all ([promise1, promise2, promise3]).then (values => { console .log (values); });
async/await
简化promise写法,async返回值是ProMise,
1 2 3 4 5 6 7 8 9 10 async function asyncFunction ( ) { try { const result = await someAsyncOperation (); console .log (result); } catch (error) { console .error ('Error:' , error); } }
一旦底层有异步函数async<上面所有调用都是async吗?
取决于你是否需要使用 await
关键字来等待异步操作完成。
如果一个函数中需要等待一个异步操作的完成并获取结果,那么这个函数必须使用 async
声明,并在需要的位置使用 await
关键字。await
只能在 async
函数中使用。
对象原型
prototype
属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。
而不在prototype
中的属性,只能被构造器自身使用。
构造器本身就是函数,你怎么可能在构造器这个函数中定义一个方法呢?
构造器函数也是一个对象类型,
对象的 __proto__
属性 = = 父亲的 proptotype
属性 ,指向一个对象。 原型对象是一个内部对象,应当使用 __proto__
访问
原型链找完了, 还没找到属性, 返回undefined
.
1 2 3 4 5 6 7 function Person (first, last, age, gender, interests ) { }; var person1 = new Person ('Bob' , 'Smith' , 32 , 'male' , ['music' , 'skiing' ]);person1.valueOf ()
浏览器首先检查,person1
对象是否具有可用的 valueOf()
方法。
如果没有,则浏览器检查 person1
对象的原型对象(即 Person
构造函数的 prototype 属性所指向的对象)是否具有可用的 valueof()
方法。
如果也没有,则浏览器检查 Person()
构造函数的 prototype 属性所指向的对象的原型对象(即 Object
构造函数的 prototype 属性所指向的对象)是否具有可用的 valueOf()
方法。这里有这个方法,于是该方法被调用。
window.subtle.crypto
前端window.crypto
crypto.webcrypto
是nodejs端对浏览器window.crypto实现
在密码学中,密钥的存储和表示有多种格式。这些格式用于定义密钥的结构和编码方式,以便在不同的系统和应用之间传递和使用密钥。以下是关于 raw
、pkcs8
、spki
和 jwk
这些密钥格式的详细解释:
1. Raw 格式
描述 : raw
格式表示原始的二进制密钥数据,通常是未经过任何编码或包装的形式。
用途 : 主要用于对称加密算法的密钥,如 AES 等,因为这些密钥通常是简单的二进制数据。
特征 :
简单、直接。
没有元数据(如密钥长度、使用限制等)。
2. PKCS #8 格式
描述 : PKCS #8 (Public-Key Cryptography Standards #8) 是一种标准格式,用于存储私钥 。它可以存储包括算法标识符在内的私钥信息,并且支持私钥加密保护。
用途 : 广泛用于存储私钥,包括 RSA、DSA 和 EC(椭圆曲线)私钥。
特征 :
可以选择加密私钥,提供额外的安全层。
一般使用 DER (Distinguished Encoding Rules) 或 PEM (Privacy Enhanced Mail) 编码。PEM 格式通常以 -----BEGIN PRIVATE KEY-----
开头,以 -----END PRIVATE KEY-----
结尾。
3. SPKI (SubjectPublicKeyInfo) 格式
描述 : SPKI 格式定义了公钥的结构,包括算法标识符和公钥值。它是 X.509 标准的一部分,用于描述公钥证书中的公钥信息。
用途 : 用于存储和传输公钥,特别是在 X.509 证书中。
特征 :
包含算法标识符,使得接收方能够识别和使用公钥。
同样可以使用 DER 或 PEM 编码。PEM 格式通常以 -----BEGIN PUBLIC KEY-----
开头,以 -----END PUBLIC KEY-----
结尾。
4. JWK (JSON Web Key) 格式
描述 : JWK (JSON Web Key) 是一种 JSON 数据结构,用于表示公钥或私钥。它是 JSON Web 系列标准的一部分,特别适合在现代 web 应用中使用。
用途 : 用于传输和存储公钥和私钥,特别是在 RESTful API 和现代 web 应用中。
特征 :
基于 JSON 格式,易于人类读取和处理。
支持多个密钥参数,如 kty
(密钥类型)、alg
(算法)、use
(用途)、key_ops
(密钥操作) 等。
能够表示对称和非对称密钥,包括 RSA 和 EC 公钥、私钥。
应用场景和选择
Raw 格式 : 适用于简单的对称密钥使用场景,不需要复杂的密钥管理。
PKCS #8 : 常用于需要强安全性和私钥管理的场景,如 TLS/SSL 证书和加密邮件。
SPKI : 在公钥基础设施 (PKI) 和证书管理系统中非常常见。
JWK : 特别适合现代 web 应用,支持易于传输的 JSON 格式,常用于 OAuth 2.0 和 OpenID Connect 等协议。
网站
scrimba : youtube : freecodecamp
codewars
[freecodecamp](#
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/ )
架构设计http://www.52im.net/thread-812-1-1.html
https://anran758.github.io/front-end-lab/topic/react.html#react-是单向数据流还是双向数据流-它还有其他特点吗