热爱点什么吧

vite 项目中 debug vue3.x 源码

之前在 vue-cli 创建的项目中调试 Vue2.x 源码时,只修改 package.json 中 module 字段对应的文件内容,对应的改动就会在浏览器刷新后体现出来,但这在由 vite 创建的 vue3.x 的项目中却行不通,原因有三: vue3.x 是一个 monorepo,源码被分成了好几部分 vite 的 pre-bundle 机制 vite 设置的浏览器缓存机制 后面两个好解决,只需分别将创建 viteServer 的 server.force 设置为 true(即将 package.json 里 scripts 中 "dev": "vite" 改为 "dev": "vite --forece") 和浏览器控制台 network 栏激活 Disable cache 即可,这两步完成之后其实就可以在浏览器中调试源码了: 修改 vue3.x package.json 中 module 字段对应的文件,以及其 dependencies 的 package.json 中 module 字段对应的文件 在编辑器中手动保存(不用任何改动,只在那个文件窗口下 cmd + s 即可)一下 vite.config.js 文件 这两步之后即可看到源码中的改动体现在浏览器中了,所以,这就完了? 当然不是,天知道每次改动一个文件之后还要再到另一个文件窗口中按一下 cmd + s 才能让浏览器刷新有多憨批,所以自动保存 vite.

CSS 规范相关一点杂记

规范本身相关 制定规范的工作由一个叫 W3C 的组织承担 即便是那些与规范有关联的文档,也不一定就是标准,从规范文档到最终称为推荐标准,中间会经过一系列流程,从最初的 Draft 状态到最终 Recommendation 状态 而且已经是 Recommendation 状态的也不一定就是一成不变,随着 Web 的发展,后续可能会被别的规范所更新 在 CSS3 及其以前,CSS 的规范都是作为一个整体统一演进,比如 CSS2 到 CSS3 即是 CSS 从 level 2 更新到 level 3,但从那以后 CSS 规范被分为不同的模块独立更新,所以从此便没有 CSS level 4 一说,有的只是 CSS module level 一般 W3C 会在每年年末的时候发布一个关于当年 CSS 规范更新工作的 snapshot,通过这个总览一些相关的信息 css current work https://www.w3.org/Style/CSS/current-work How to Read W3C Specs https://alistapart.com/article/readspec/ Understanding the CSS Specifications https://www.w3.org/Style/CSS/read Visual Formatting Model 相关 CSS 按照一系列特定的规则将 由 element 和 text 组成的 DOM tree 转换成 box tree,这些特定规则就是所谓的 visual formatting model。DOM 上需要在浏览器上渲染出来的东西都对应 box tree 上的某个(或些) box 一个 element 可能会创建多个 box,比如 display 值为 list-item 的会创建两个 box,其中包含子 box 的那个被称为 principal box 引用一个 box 的 CSS 某个属性,即是指创建它的那个 element 对应的 CSS 属性 浏览器的 media type 是 screen,除此之前了 CSS 规范还包含其他的 CSS 属性,比如 print、tty 等其他各式 media type 暂时只考虑 media type 为 screen 的浏览器,对应的 root element 则指 html 元素 概念 Display 属性的值 实际上目前 box 的 display 属性值都是缩写,各种值其实蕴含 inner display type 和 outer display type 两种,outer display type 则分为 block 和 inline 两种(不考虑 run-in),它的取值决定了它自身是参与怎样的 formatting context 在其 containing block 中进行 layout 的;而 inner display type 就分好多种了,比如 table、flex、flow 等,它的取值决定了其包含的内容在其内部是以何种规则进行 layout 的。平时写的 display 值为 block、flex、inline 等其实都是只指明了一种 type 的缩写,只需要只定义一种是因为另一种 type 已经由 CSS 规范规定好,比如 block 值实际的意义是 inner type 为 flow 且 outer type 为 block,而 flex 的值意义为 inner type 为 flex 且 outer type 为 block。

window 下的 api 分类整理笔记

window 下的 api 主要分为 ECMAScript API、DOM API、HTML API(其实很多 API 都算是包含在 HTML API 里的,只不过被细分出来,比如 DOM API)、CSSOM 相关的 API,以及剩余的占绝大多数的 Web api(有被纳入规范的和未被纳入规范的,这些 API 都是为浏览器提供特定的功能,比如音视频相关、蓝牙相关等)。这些 Web API 由可能最先由某个组织(比如 W3C、WHATWG、WICG 等)提出,然后被浏览器厂商实现(不一定被纳入标准)。 CSSOM View API 为 DOM 的 element 扩展了一些与 view 相关的(比如距离、长宽之类)的属性和方法。 // appVersion: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36" ;(function f() { const allPropsNames = { ecma: [ 'Object', 'Function', 'Array', 'Number', 'parseFloat', 'parseInt', 'Infinity', 'NaN', 'undefined', 'Boolean', 'String', 'Symbol', 'Date', 'Promise', 'RegExp', 'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', 'AggregateError', 'globalThis', 'JSON', 'Math', 'Intl', 'ArrayBuffer', 'Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array', 'Uint8ClampedArray', 'BigUint64Array', 'BigInt64Array', 'DataView', 'Map', 'BigInt', 'Set', 'WeakMap', 'WeakSet', 'Proxy', 'Reflect', 'Atomics', 'FinalizationRegistry', 'WeakRef', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', 'unescape', 'eval', 'isFinite', 'isNaN' ], dom: [ 'Event', 'CustomEvent', 'EventTarget', 'AbortController', 'AbortSignal', 'NodeList', 'HTMLCollection', 'MutationObserver', 'MutationRecord', 'Node', 'Document', 'DOMImplementation', 'DocumentType', 'DocumentFragment', 'ShadowRoot', 'Element', 'NamedNodeMap', 'Attr', 'CharacterData', 'Text', 'CDATASection', 'ProcessingInstruction', 'Comment', 'AbstractRange', 'StaticRange', 'Range', 'NodeIterator', 'TreeWalker', 'NodeFilter', 'DOMTokenList', 'XPathResult', 'XPathExpression', 'XPathEvaluator', 'XSLTProcessor', 'DOMError', 'XMLDocument' ], html: [ 'BarProp', 'BeforeUnloadEvent', 'BroadcastChannel', 'CanvasGradient', 'CanvasPattern', 'CanvasRenderingContext2D', 'CloseEvent', 'CustomElementRegistry', 'DOMParser', 'DOMStringList', 'DOMStringMap', 'DataTransfer', 'DataTransferItem', 'DataTransferItemList', 'DragEvent', 'ElementInternals', 'ErrorEvent', 'EventSource', 'External', 'FormDataEvent', 'HTMLDocument', 'HTMLAllCollection', 'HTMLAnchorElement', 'HTMLAreaElement', 'HTMLAudioElement', 'HTMLBRElement', 'HTMLBaseElement', 'HTMLBodyElement', 'HTMLButtonElement', 'HTMLCanvasElement', 'HTMLDListElement', 'HTMLDataElement', 'HTMLDataListElement', 'HTMLDetailsElement', 'HTMLDialogElement', 'HTMLDirectoryElement', 'HTMLDivElement', 'HTMLElement', 'HTMLEmbedElement', 'HTMLFieldSetElement', 'HTMLFontElement', 'HTMLFormControlsCollection', 'HTMLFormElement', 'HTMLFrameElement', 'HTMLFrameSetElement', 'HTMLHRElement', 'HTMLHeadElement', 'HTMLHeadingElement', 'HTMLHtmlElement', 'HTMLIFrameElement', 'HTMLImageElement', 'HTMLInputElement', 'HTMLLIElement', 'HTMLLabelElement', 'HTMLLegendElement', 'HTMLLinkElement', 'HTMLMapElement', 'HTMLMarqueeElement', 'HTMLMediaElement', 'HTMLMenuElement', 'HTMLMetaElement', 'HTMLMeterElement', 'HTMLModElement', 'HTMLOListElement', 'HTMLObjectElement', 'HTMLOptGroupElement', 'HTMLOptionElement', 'HTMLOptionsCollection', 'HTMLOutputElement', 'HTMLParagraphElement', 'HTMLParamElement', 'HTMLPictureElement', 'HTMLPreElement', 'HTMLProgressElement', 'HTMLQuoteElement', 'HTMLScriptElement', 'HTMLSelectElement', 'HTMLSlotElement', 'HTMLSourceElement', 'HTMLSpanElement', 'HTMLStyleElement', 'HTMLTableCaptionElement', 'HTMLTableCellElement', 'HTMLTableColElement', 'HTMLTableElement', 'HTMLTableRowElement', 'HTMLTableSectionElement', 'HTMLTemplateElement', 'HTMLTextAreaElement', 'HTMLTimeElement', 'HTMLTitleElement', 'HTMLTrackElement', 'HTMLUListElement', 'HTMLUnknownElement', 'HTMLVideoElement', 'HashChangeEvent', 'History', 'ImageBitmap', 'ImageBitmapRenderingContext', 'ImageData', 'Location', 'MediaError', 'MessageChannel', 'MessageEvent', 'MessagePort', 'MimeType', 'MimeTypeArray', 'Navigator', 'OffscreenCanvas', 'OffscreenCanvasRenderingContext2D', 'PageTransitionEvent', 'Path2D', 'Plugin', 'PluginArray', 'PopStateEvent', 'PromiseRejectionEvent', 'RadioNodeList', 'SharedWorker', 'Storage', 'StorageEvent', 'SubmitEvent', 'TextMetrics', 'TextTrack', 'TextTrackCue', 'TextTrackCueList', 'TextTrackList', 'TimeRanges', 'TrackEvent', 'ValidityState', 'WebSocket', 'Window', 'Worker', 'Worklet', 'Option', 'Image', 'Audio' ], cssom: [ 'MediaList', 'getComputedStyle', 'StyleSheet', 'CSSStyleSheet', 'StyleSheetList', 'CSSRuleList', 'CSSRule', 'CSSStyleRule', 'CSSImportRule', 'CSSGroupingRule', 'CSSPageRule', 'CSSNamespaceRule', 'CSSStyleDeclaration', 'CSS', 'CSSMediaRule', 'CSSConditionRule', 'CSSSupportsRule', 'MediaQueryListEvent', 'MediaQueryList', 'scroll', 'screenLeft', 'screenTop' ], cssomView: [ 'matchMedia', 'screen', 'moveTo', 'moveBy', 'scrollTo', 'scrollBy', 'resizeTo', 'resizeBy', 'innerWidth', 'innerHeight', 'scrollX', 'pageXOffset', 'scrollY', 'pageYOffset', 'screenX', 'screenY', 'outerWidth', 'outerHeight', 'devicePixelRatio', 'Screen' ], xmlHttpRequest: [ 'FormData', 'XMLHttpRequest', 'XMLHttpRequestEventTarget', 'XMLHttpRequestUpload', 'ProgressEvent' ], fetch: ['fetch', 'Response', 'Request', 'Headers'], webgl: [ 'WebGLBuffer', 'WebGLFramebuffer', 'WebGLProgram', 'WebGLRenderbuffer', 'WebGLShader', 'WebGLTexture', 'WebGLUniformLocation', 'WebGLActiveInfo', 'WebGLShaderPrecisionFormat', 'WebGLRenderingContext', 'WebGLContextEvent', 'WebGLQuery', 'WebGLSampler', 'WebGLSync', 'WebGLTransformFeedback', 'WebGLVertexArrayObject', 'WebGL2RenderingContext' ], worker: [ 'ServiceWorker', 'ServiceWorkerContainer', 'ServiceWorkerRegistration', 'NavigationPreloadManager' ], cssTypedOm: [ 'CSSStyleValue', 'StylePropertyMapReadOnly', 'StylePropertyMap', 'CSSUnparsedValue', 'CSSVariableReferenceValue', 'CSSKeywordValue', 'CSSNumericValue', 'CSSUnitValue', 'CSSMathValue', 'CSSMathSum', 'CSSMathProduct', 'CSSMathNegate', 'CSSMathInvert', 'CSSMathMin', 'CSSMathMax', 'CSSNumericArray', 'CSSTransformValue', 'CSSTransformComponent', 'CSSTranslate', 'CSSRotate', 'CSSScale', 'CSSSkew', 'CSSSkewX', 'CSSSkewY', 'CSSPerspective', 'CSSMatrixComponent', 'CSSPositionValue', 'CSSImageValue' ], webIdl: ['DOMException'], url: ['URL', 'URLSearchParams'], streams: [ 'ReadableStream', 'ReadableStreamDefaultReader', 'ReadableStreamBYOBReader', 'ReadableStreamDefaultController', 'ReadableByteStreamController', 'ReadableStreamBYOBRequest', 'WritableStream', 'WritableStreamDefaultWriter', 'WritableStreamDefaultController', 'TransformStream', 'ByteLengthQueuingStrategy', 'CountQueuingStrategy' ], storage: ['StorageManager'], notification: ['Notification'], encode: [ 'TextDecoder', 'TextEncoder', 'TextDecoderStream', 'TextEncoderStream' ], backgroundFetch: [ 'BackgroundFetchManager', 'BackgroundFetchRegistration', 'BackgroundFetchRecord' ], backgroundTask: ['IdleDeadline'], bluetooth: [ 'Bluetooth', 'BluetoothCharacteristicProperties', 'BluetoothDevice', 'BluetoothRemoteGATTCharacteristic', 'BluetoothRemoteGATTDescriptor', 'BluetoothRemoteGATTServer', 'BluetoothRemoteGATTService', 'BluetoothUUID' ], cssRules: [ 'CSSPropertyRule', 'CSSKeyframesRule', 'CSSKeyframeRule', 'CSSFontFaceRule', 'CSSCounterStyleRule' ], fontFaceLoad: ['FontFaceSetLoadEvent', 'FontFace'], clipboard: ['Clipboard', 'ClipboardItem', 'ClipboardEvent'], credential: [ 'Credential', 'FederatedCredential', 'PasswordCredential', 'PublicKeyCredential' ], encryptedMediaExtensions: [ 'MediaKeys', 'MediaKeySession', 'MediaKeyStatusMap', 'MediaKeySystemAccess', 'MediaKeyMessageEvent', 'MediaEncryptedEvent' ], fileSystemAccess: [ 'FileSystemHandle', 'FileSystemFileHandle', 'FileSystemDirectoryHandle', 'FileSystemWritableFileStream', 'showOpenFilePicker', 'showSaveFilePicker', 'showDirectoryPicker' ], gamePad: [ 'Gamepad', 'GamepadButton', 'GamepadEvent', 'GamepadHapticActuator' ], geo: [ 'Geolocation', 'GeolocationCoordinates', 'GeolocationPosition', 'GeolocationPositionError' ], indexDB: [ 'IDBCursor', 'IDBCursorWithValue', 'IDBDatabase', 'IDBFactory', 'IDBIndex', 'IDBKeyRange', 'IDBObjectStore', 'IDBOpenDBRequest', 'IDBRequest', 'IDBTransaction', 'IDBVersionChangeEvent' ], mediaStream: [ 'BlobEvent', 'MediaDevices', 'MediaStream', 'MediaStreamTrack', 'MediaStreamTrackEvent' ], webVTT: ['VTTCue'], webHID: ['HID', 'HIDDevice', 'HIDInputReportEvent', 'HIDConnectionEvent'], webCodecs: [ 'AudioData', 'AudioDecoder', 'AudioEncoder', 'EncodedAudioChunk', 'EncodedVideoChunk', 'ImageDecoder', 'ImageTrack', 'ImageTrackList', 'VideoDecoder', 'VideoEncoder', 'VideoColorSpace', 'VideoFrame' ], webSpeech: [ 'SpeechSynthesisErrorEvent', 'SpeechSynthesisEvent', 'SpeechSynthesisUtterance' ], webMIDI: [ 'MIDIInputMap', 'MIDIOutputMap', 'MIDIAccess', 'MIDIPort', 'MIDIInput', 'MIDIOutput', 'MIDIMessageEvent', 'MIDIConnectionEvent' ], webCrypto: ['Crypto', 'CryptoKey', 'SubtleCrypto'], webAuth: [ 'CredentialsContainer', 'AuthenticatorResponse', 'AuthenticatorAttestationResponse', 'AuthenticatorAssertionResponse' ], webAudio: [ 'AnalyserNode', 'AudioBuffer', 'AudioBufferSourceNode', 'AudioContext', 'AudioDestinationNode', 'AudioListener', 'AudioNode', 'AudioParam', 'AudioProcessingEvent', 'AudioScheduledSourceNode', 'AudioWorklet', 'AudioWorkletNode', 'BaseAudioContext', 'BiquadFilterNode', 'ChannelMergerNode', 'ChannelSplitterNode', 'ConstantSourceNode', 'ConvolverNode', 'DelayNode', 'DynamicsCompressorNode', 'GainNode', 'IIRFilterNode', 'MediaElementAudioSourceNode', 'MediaStreamAudioDestinationNode', 'MediaStreamAudioSourceNode', 'OfflineAudioCompletionEvent', 'OfflineAudioContext', 'OscillatorNode', 'PannerNode', 'PeriodicWave', 'WaveShaperNode', 'StereoPannerNode' ], webAnimation: [ 'Animation', 'AnimationEffect', 'AnimationEvent', 'AnimationTimeline', 'AnimationPlaybackEvent', 'DocumentTimeline', 'KeyframeEffect' ], touchEvent: ['Touch', 'TouchEvent', 'TouchList'], serviceWorker: [ 'Cache', 'CacheStorage', 'PeriodicSyncManager', 'SyncManager' ], sensor: [ 'AbsoluteOrientationSensor', 'Accelerometer', 'GravitySensor', 'Gyroscope', 'LinearAccelerationSensor', 'OrientationSensor', 'RelativeOrientationSensor', 'Sensor', 'SensorErrorEvent' ], wakeLock: ['WakeLock', 'WakeLockSentinel'], payment: [ 'PaymentAddress', 'PaymentMethodChangeEvent', 'PaymentRequest', 'PaymentRequestUpdateEvent', 'PaymentResponse', 'PaymentManager', 'PaymentInstruments' ], presentation: [ 'Presentation', 'PresentationAvailability', 'PresentationRequest', 'PresentationConnectionAvailableEvent', 'PresentationConnection', 'PresentationConnectionCloseEvent', 'PresentationReceiver', 'PresentationConnectionList' ], geometry: [ 'DOMRectReadOnly', 'DOMRect', 'DOMRectList', 'DOMQuad', 'DOMMatrixReadOnly', 'DOMMatrix', 'DOMPointReadOnly', 'DOMPoint' ], trustedType: [ 'TrustedHTML', 'TrustedScript', 'TrustedScriptURL', 'TrustedTypePolicyFactory', 'TrustedTypePolicy' ], wasm: ['WebAssembly'], file: ['Blob', 'File', 'FileList', 'FileReader'], deviceOrientation: [ 'DeviceOrientationEvent', 'DeviceMotionEventAcceleration', 'DeviceMotionEventRotationRate', 'DeviceMotionEvent' ], push: ['PushManager', 'PushSubscription', 'PushSubscriptionOptions'], lqbz: [ .

杂记

杂 Q: source map 是什么?如何使用? A: source map 一个保存转换前、后文件内容位置对应信息的 json 格式的文件。位置关系保存在 mapping 字段的值中,通过这个值和特定的算法可以从转化后的文件中的任意位置找到源文件中与之对应的位置,源文件内容存在于 sourcesContent 字段中。浏览器通过处理后的文件结尾的 //# sourceMappingURL=url 来加载对应的 map 文件,进而借之还原转换前的 js 文件,以便为开发者提供友好的调试体验。url 可以是一个指向某处 map 文件的资源连接,也可以是一个由对应内容转换的 base64 链接。像 rollup、webpack、esbuild 等 bundler 工具都支持 inline(对应打包后文件末尾注释的 base64) 和 external(对应独立的 map 文件)的生成方式。当一个支持 source map 的浏览器加载 map 文件后,当打包后文件报错时,浏览器可以从打包文件中的报错位置定位到源文件中对应的位置。 Q: CSP(Content Security Policy) 是什么? A: CSP 是一系列检测(上报)和减轻特定类型的 Web 攻击(主要是 XSS)的策略,通过配置返回 html 文件时的 Content-Security-Policy: ${policy-token} header 或在返回的 html 文件中设置 <meta http-equiv="Content-Security-Policy" content="${policy-token}"> 来生效 上述 policy-token 由一系列 directives 组成,每个 directives 通过 ; 分隔,directives 又由为 directive-name 和 directive-value 组成,ANBF 定义如下: policy-token = [ directive-token *( ";" [ directive-token ] ) ] directive-token = *WSP [ directive-name [ WSP directive-value ] ] directive-name = 1*( ALPHA / DIGIT / "-" ) directive-value = *( WSP / <VCHAR except ";" and ","> ) 不支持 CSP 的浏览器默认使用同源策略。对于 web server 不返回 CSP header 的情况,浏览器也默认使用同源策略

vue2 自定义指令笔记以及在埋点上的简单应用

简介 Vue 允许开发者注册自定义指令,可以是通过 Vue.directives 注册全局指令或是在组件的 options 里添加 directives 属性。前者接受两个参数,第一个参数是指令名,第二个参数是定义指令的值(可以是一个包含指令各个 hooks 的函数的对象或者是一个只对 bind 和 update hook 生效的简写函数),后者是一个包含以指令名为属性以及对应定义指令的值为值的对象。 指令 hook 函数和对应参数 定义指令的对象包括 bind、inserted、update、componentUpdated、unbind 五个 hook,每个 hook 对应一个在对应时机执行的函数,函数的参数为: el:含指令所绑定的 DOM 元素 binding:包含指令相关信息(包括指令名、绑定值、绑定的参数、修饰符等)的对象 vnode:指令被解析为其 data.directives 属性的 vnode oldVnode:更新前的 vnode,仅在 update、componentUpdated 有值 可以猜测指令只在一般组件和 HTML 元素上生效,而在函数式组件和像 template、slot、component 对应的标签以及 keep-alive、transition 这样 abstract 组件上不生效的,因为指令 hook 的第一个参数是一个 DOM 元素,后面的几种情况并不能永远确定一个唯一的 el 传给 hook。事实上通过从源码粗略搜索关键字也可以确认不适用指令的情况中,指令对应的 vnode.data.directives 并未被处理。 指令的大致机制 指令注册的机制 就是通过 Vue.directives 和 options.directives API 使得某个组件可以通过 vm.$options.directives.directiveName 可以访问到对应的指令对象。 指令作用的机制 通过搜索 directives 在 vdom 相关的模块可以知道「指令是通过 vdom 的 module 机制生效的」。vdom 的 module 是用于处理 vdom 的各种 attribute 的机制,比如 style、class、events 等,这些 module 如同定义指令的对象一样也是一个由一个个 hook 名和对应函数值组成的对象,只不过 module 的 hook 是 vdom 的 hook。通过在 vdom 的 hook 里触发指令对应的 hook 从而使指令生效。而触发指令 hook 的时对应函数的第二个参数 binding 相关的信息则由通过 template 模板编译(或是手写 render 直接传参)而来的 vnode.

Vue2.6 slot 笔记

什么是 slot?——精确的定义不好下,可以类比为电脑主板上用于插网卡、内存条等各种硬件的那些东西。因为有那些插槽,人们可以在上面插上不同的网卡和内存条。 slot 有什么用?——先设想,如果没有 slot,那些硬件就必须集成在主板上,显然不是一种灵活的做法,slot 就赋予了这种灵活性。 拿电脑主板打比方后,Vue 的 slot 的作用也就是一样的:赋予组件直接将 vnode 填充到组件的渲染内容中特定地方的能力。slot 相关的用法 Vue 文档有详述,本篇主要记录 slot 的实现原理,v2.6 之前的 slot attribute 的即将废弃的写法不作讨论,主要说明 v-slot 写法的 slot。 renderSlot 先从有 slot 的组件的 render 方法说起,比如下面的组件: <template> <div> <slot></slot> </div> </template> <script> export default { name: 'Hello' } </script> 的 render 函数会是: function() { var _vm = this var _h = _vm.$createElement var _c = _vm._self._c || _h return _c("div", [_vm._t("default")], 2) } 其中 _vm._t 就是 renderSlot

Vue2 函数式组件

函数式组件简介 何为函数式组件?——当组件对应的 options 对象中 functional 属性值为 true 时,这个组件就是一个函数式组件 函数式组件与一般组件有何不同?——它没有响应式的数据(组件对应的 options 里没有 data、computed 等与 state 相关的属性);也不像一般组件一样有通过 options 创建的 vm 实例(自然也没有那一系列的生命周期),所以在函数式组件内部的方法中也没有 this 可以访问,它所拥有的只是一个包含 props、children、slots、scopedSlots、parent、listeners、injections 属性的 functionalRenderContext 对象,这个对象供函数式组件的 render 方法访问,以达到父组件向其传值以及访问函数式组件渲染内容的目的 为什么要有函数式组件?——有些时候一个组件并不需要创建和维护自己的内部状态,而只用完全根据 props 的值来决定渲染的内容,创建 vm 会略显多余,此时则是函数式组件的用武之地,相比于创建 vm 实例并执行一系列生命周期 hooks,创建一个 functionalRenderContext 对象的开销则小得多 函数式组件内部机制 不管是何种组件,调用自身 render 方法的结果都是返回一个 vnode 实例用于 patch,函数式组件也不例外,与一般组件的 render 方法不同的是函数式组件的 render 方法多了个 functionalRenderContext 对象用来弥补没有与之对应的 vm 实例所带来的的不足:没有内部状态固然不用创建 vm,但与此同时 props、children 之类的东西也没了。所以函数式组件的内部机制主要在于 functionalRenderContext 对象的创建,也即对象包含的属性的创建。与函数式组件相关的源码大致如下: function createComponent(Ctor, data, context, children, tag) { // ... const propsData = extractPropsFromVNodeData(data, Ctor, tag) if (Ctor.

x86 32 位保护模式笔记

概念 32 位保护模式 32 位保护模式(后面统一简称保护模式)是区别于 16 位 CPU 任何程序可以访问任何内存空间的模式(自保护模式出来后,16 位 CPU 运行的模式被称为实模式),在这种模式下所有对内存的访问都要通过一个段选择子的东西,而要被访问的内存也必须先在一个叫做 GDT(全局描述符表) 的东西中定义,这个段选择子实质上就是全局描述符表中某个描述符的索引,通过段选择子找到对应的描述符,然后通过描述符里的记录的相关段的信息再去访问对应的内存。32 保护模式下的段不再像实模式下的段一样需要是以 16 的整数倍为起始地址了,它可从任何地址开始,所以 32 位保护模式下的段就可以理解为描述符描描述的内存中的某一连续空间。全局描述符表又通过一个叫 GDTR(全局描述符表寄存器) 的东西里的内容来定义。 相比于实模式,32 位保护模式的数据总线、地址总线的长度都是 32 位。通用寄存器也扩展到了 32 位:EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP,而且依然可以通过 AX、AL、AH 来访问 EAH 的低 16 位、低 8 位以及第 8 到 16 位。但段寄存器依然保持 16 位,此外新增了两个段寄存器 FS、GS。 GDT 顾名思义,如中断向量表类似,GDT 是一个表,每个表项是一个描述内存中某块区域的段描述符,用 64 位来描述内存段的属性,包括: 基址(32 位) 大小(20 位) 类型(1 位,可用于区分系统段和用户段) 子类(4 位,比如用户段又分代码段、数据段) 描述符特权级 DPL(2 位,0,1,2,3,越小说明级别最高) 是否在内存(1 位) AVL(1 位,硬件没用上) L,是否是 64 位代码段(1 位,保留位) D/B,兼容 286 的保护模式(1 位) 段大小单位(1 位,分为 1B 和 4KB) 32 位基址覆盖了 4GB 的内存空间。20 位段大小以及对应段大小的单位可以为 4KB 表明一个段最大可以是 4GB。

8086 中断笔记

中断机制 何为中断?中断是一种打断处理器当前运行流程进而获得其控制权的机制。可以说如果没有中断这种机制,那么处理器就是个只会朝着某个方向一直冲的铁憨憨,别人叫它,它也不一定能正确地理会,哪怕键盘敲烂了都没有。每个中断都对应一个编号,处理器处理中断时,根据编号找到它对应的中断处理程序的入口地址,拿到中断处理程序地址后,将之前程序的上下文(CS, IP, FLAGS)入栈保存并将 IF 和 TF 清零,然后跳转到中断处理程序入口处执行。中断处理程序执行完毕后调用 iret 指令(作用就是将之前保存的上下文再按正确顺序出站)返回之前的程序继续执行。处理器响应中断跳到其对应的中断处理程序执行的过程即控制权从原来的程序转移到新程序的过程。与一般的子程序一样,中断处理程序内部要要用到的寄存器在使用之前应该将它们的数据保存入栈,在返回之前再恢复原状,以免破坏外部程序的状态。 中断分类 处理器提供两种途径触发中断,一种是从处理器外部通过向一个叫做 8259A 的可编程中断控制器发送信号来产生中断,另一种是处理器内部自行产生中断(由程序直接调用中断指令,或是某些条件下处理器执行指令时自己产生),前者产生的叫外中断,后者叫内中断。外中断又分为可屏蔽中断和不可屏蔽中断。 外部中断 可屏蔽中断的信号通过 INTR 信号线传递,最终被处理器处理需要经过两道关卡,第一个是 8259A,8259A 可以控制是否为从外部收到的中断信号生成对应的中断通知给处理器,外部硬件产生的中断信号只有被 8259A 生成对应的中断通知给处理器才有可能被处理器处理;过了 8259A 那关才能进到第二关:处理器中标志寄存器的 IF 位的值。如果是处理器从 8259A 那里收到中断事件时,当前的 IF 位为 0,那么这个中断也不会被处理,只有 IF 位为 1 才会被处理。 不可屏蔽中断的信号则通过 NMI 信号线传递。顾名思义,与可屏蔽中断相比,不可屏蔽中断产生时,处理器必须处理。正因如此,不可屏蔽中断通常意味着一些灾难性事件,比如即将断电、内存检测异常、总线校验错误等。显然它的优先级也比可屏蔽终端要高(当同时有多个中断产生时)。NMI 中断编号为 2。 内部中断 内部中断分为通过 INT 指令产生的中断(称为 software interrupt)和处理器自己产生的中断。前者除了 INT 指令外,还有断点中断指令 INT3 (中断编号为 3)和溢出中断指令 INTO(中断编号为 4)。后者则包括处理器做除法运算时除数为零时产生的除数为零中断(中断编号为 0)、处理器执行完一条指令发现 TF 标记位为 1 时产生的单步调试中断(中断编号为 1)。 常见中断优先级 中断优先级由高到低: 除数为 0、INT n、INTO NMI INTR 单步调试中断 中断向量表 8086 处理器可以支持 256 种中断,从 0 编号到 255。每个编号对应一个中断处理程序的入口地址,这个入口地址为一个偏移地址和段地址组成的二元组,这个二元组就是中断向量,256 个二元组组成的表也就是中断向量表。这个表从 0 号中断向量开始依次存储在 0x00000~0x003ff 对应的 1KB 内存空间,每个中断向量占 4 个字节,低地址 2 个字节存储偏移地址,高地址 2 个字节存储段地址。也就是说对于 256 个中断中的某个 n 号中断,其对应的中断向量为 (4*n, 4*n+2)。

MacOs 下调试 8086 汇编

所需工具 x86 DOS 模拟器:dosbox DOS 上运行调试工具:DEBUG.EXE 汇编器(链接器):DOS 上运行的 MASM.EXE、LINK.EXE 或者直接使用 MacOs 自带的 nasm dosbox 配置 去 https://www.dosbox.com/download.php?main=1 下载对应 dmg 文件 点击,运行里面的 dosbox,弹出一个窗口 打开 ~/Library/Preferences/DOSBox 0.74-3-3 Preferences 文件,在文件末尾 [autoexec] 下添加 mount C: ~/dosbox C: 不加上面两个命令的话,每次都要重复输入。挂载目录可按照自己喜好来选,配置文件名中的 0.74-3-3 可能会因实际的 dosbox 软件版本不同而有所差异。 创建挂载目录 dosbox(第 3 步配置文件添加的命令中的挂载目录) 将 DEBUG.EXE、MASM.EXE、LINK.EXE 等可执行文件丢到 dosbox 目录,如果使用的是 MacOs 自带的 nasm 汇编器,那么 DEBUG.EXE 和 MASM.EXE 就不需要了,编译过程在 MacOS 的 shell 里完成就行 重新打开 dosbox 之后通过汇编器生成的 EXE 文件都让它生成到 ~/dosbox 目录下,然后使用 debug filename.