JS详解-手写Promise!!!

前言:

针对js的深入理解,作者学习并撰写以下文章,由于理解认知有限难免存在偏差,请大家指正!所有定义来自mdn。

Promise介绍:

        对象表示异步操作最终的完成(或失败)以及其结果值.

        描述:

一个 Promise 是一个代理,它代表一个在创建 promise 时不一定已知的值。它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样返回值:异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值。

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled):意味着操作成功完成。
  • 已拒绝(rejected):意味着操作失败。

一个待定的 Promise 最终状态可以是已兑现并返回一个值,或者是已拒绝并返回一个原因(错误)。当其中任意一种情况发生时,通过 Promise 的 then 方法串联的处理程序将被调用。如果绑定相应处理程序时 Promise 已经兑现或拒绝,这处理程序将被立即调用,因此在异步操作完成和绑定处理程序之间不存在竞态条件。

如果一个 Promise 已经被兑现或拒绝,即不再处于待定状态,那么则称之为已敲定(settled)

Promise.resolve:

        Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。

构造MyPromise函数:

   // 构造函数// 定义类class MyPromise {// 添加构造函数constructor(func){// 定义resolve和reject方法const resolve = (value) => {console.log('resolve执行:',value)// // 判断状态是否为pending// if(this.status === 'pending'){//     // 修改状态为fulfilled//     this.status = 'fulfilled'//     // 保存成功的值//     this.value = value//     // 执行成功的回调函数//     this.onFulfilledCallbacks.forEach(fn => fn())// }}const reject = (value) => {console.log('reject执行:',value)}// 初始化状态func(resolve,reject)}}// 测试代码const p = new MyPromise((resolve,reject) => {console.log('执行器函数执行')resolve('成功')reject('失败')})

状态和原因:

含bug代码

    <h2>状态及原因</h2><script>// 1、添加原生Promise状态fulfilled/pending/rejected// 2、添加原生Promise原因resolve/reject// 3、调整resolve/reject方法// 4、状态不可逆// 为了方便和规范起见命名MyPromise的状态const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class MyPromise {// 状态初始化status = PENDINGresult = undefined// 添加构造函数constructor(func){// 定义resolve和reject方法const resolve = (value) => {// 修改状态并记录原因this.status = FULFILLEDthis.result = value}const reject = (value) => {// 修改状态并记录原因this.status = REJECTEDthis.result = value}// 初始化状态func(resolve,reject)}}// 测试代码const p = new MyPromise((resolve,reject) => {resolve('成功')reject('失败')})

在未添加自定义的状态不可逆时代码有误还是会按照js从上向下执行原则最后改变pending从sucees to fail.

接下来我们开始处理不可逆属性:

 // 定义resolve和reject方法const resolve = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = FULFILLEDthis.result = result}}const reject = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = REJECTEDthis.result = result}// 初始化状态func(resolve,reject)}

then方法:

成功失败回调:

tips:被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。

      const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class MyPromise {// 状态初始化// 添加状态status = PENDING// 添加原因result = undefined// 添加构造函数constructor(func){// 定义resolve和reject方法const resolve = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = FULFILLEDthis.result = result}}const reject = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = REJECTEDthis.result = result}}// 初始化状态func(resolve,reject)}then(onFulfilled,onRejected){// 根据mdn知道需要判断回调函数是否为函数,如果不是需要处理onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => valueonRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}// 判断状态if(this.status === FULFILLED){onFulfilled(this.result)}else if(this.status === REJECTED){onRejected(this.result)}}}// 测试代码const p = new MyPromise((resolve,reject) => {// resolve('success')reject('fail')})p.then((res) => {console.log('成功回调',res)},(err) => {console.log('失败抛出错误',err)})

异步多次调用:
 // 定义常量const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class MyPromise {// 状态初始化// 添加状态status = PENDING// 添加原因result = undefined// 私有属性handlers#handlers = [] //[{onFulfilled,onRejected}...]// 添加构造函数constructor(func){// 定义resolve和reject方法const resolve = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = FULFILLEDthis.result = result// 调用成功回调函数this.#handlers.forEach(({onFulfilled}) => {onFulfilled(result)})}}const reject = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = REJECTEDthis.result = result// 调用失败回调函数this.#handlers.forEach(({onRejected}) => {onRejected(result)})}}// 初始化状态func(resolve,reject)}then(onFulfilled,onRejected){// 根据mdn知道需要判断回调函数是否为函数,如果不是需要处理onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => valueonRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}// 判断状态// 同步调用if(this.status === FULFILLED){onFulfilled(this.result)}else if(this.status === REJECTED){onRejected(this.result)}//异步和多次调用else if(this.status === PENDING){// 添加回调函数this.#handlers.push({onFulfilled,onRejected})}}}// 测试代码const p = new MyPromise((resolve,reject) => {setTimeout(() => {resolve('success')reject('fail')},1000)})p.then((res) => {console.log('then1',res)},(err) => {console.log('then1',err)})p.then((res) => {console.log('then2',res)},(err) => {console.log('then2',err)})

异步任务:

核心api:
   // 异步任务 queueMicrotaskconsole.log('start')queueMicrotask(() => {console.log('queueMicrotask')})console.log('end')// 异步任务 MutationObserver// 1、创建观察器,并传入回调函数const obs = new MutationObserver(() => {console.log('mutationsList')})// 2、创建元素,并添加监听const divNode = document.createElement('div')// 参数1dom节点,参数2配置对象childList:true表示监听子节点变化obs.observe(divNode,{childList:true})// 3、修改元素内容,观察器触发MutationObserverdivNode.innerText = 'hello'
函数封装:
// 封装函数分别使用queueMicrotask和MutationObserver setTimeout实现异步任务function runAsyncTask(callback){// 使用queueMicrotaskif(typeof queueMicrotask === 'function'){queueMicrotask(callback)}else if (typeof MutationObserver === 'function'){// 使用MutationObserverconst observer = new MutationObserver(callback)const nodeDiv = document.createTextNode('div')observer.observe(nodeDiv,{childList:true})node.innerText = 'hello'}else{setTimeout((callback) ,0)}}

对then中的回调方法增加异步属性

        // 使用封装的异步函数then(onFulfilled,onRejected){// 根据mdn知道需要判断回调函数是否为函数,如果不是需要处理onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => valueonRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}// 判断状态// 同步调用if(this.status === FULFILLED){runAsyncTask(() => {onFulfilled(this.result)})}else if(this.status === REJECTED){runAsyncTask(() => {onRejected(this.result)})}//异步和多次调用else if(this.status === PENDING){// 添加回调函数this.#handlers.push({onFulfilled:()=>{runAsyncTask(() => {onFulfilled(this.result)})},onRejected:()=>{runAsyncTask(() => {onRejected(this.result)})}})}}

成功实现异步调用

链式编程:

获取返回值:
处理返回值和处理异常:

使用try-catch进行返回值处理和异常捕获,同时在then中内嵌的promise调用和回调函数的使用完成对上一个then的返回值的捕获和返回。

 // 1、返回新的promise对象 传入的函数是立刻调用的const p2 = new MyPromise((resolve,reject)=>{// 判断状态// 同步调用if(this.status === FULFILLED){runAsyncTask(() => {// 2、获取返回值try {const x = onFulfilled(this.result)// 2.1处理返回值resolve(x)} catch (error) {reject(error)}})}else if(this.status === REJECTED){runAsyncTask(() => {onRejected(this.result)})}//异步和多次调用else if(this.status === PENDING){// 添加回调函数this.#handlers.push({onFulfilled:()=>{runAsyncTask(() => {onFulfilled(this.result)})},onRejected:()=>{runAsyncTask(() => {onRejected(this.result)})}})}})return p2

处理返回promise:

tips:instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

x为返回的promise实例

runAsyncTask(() => {// 2、获取返回值try {const x = onFulfilled(this.result)if(x instanceof MyPromise){x.then(res => resolve(res),err => reject(err))}else{resolve(x)}} catch (error) {reject(error)}})
// 测试代码// console.log('start')const p = new MyPromise((resolve,reject) => {resolve(1)  //reject('fail')})p.then((res)=>{return new MyPromise((resolve,reject) => {resolve(2)})}).then((res) => {console.log('p2',res)},(err) => {console.log('p2',err)})

获取重复调用:

利用原生Promise报错模仿写自己的Promise返回相同值(Promise)的报错

Chaining cycle detected for promise #<Promise>
 // 处理重复引用const p2 = new MyPromise((resolve,reject)=>{if(this.status === FULFILLED){runAsyncTask(() => { try {const x = onFulfilled(this.result)// 判断是否重复if(x===p2){// 抛出异常Chaining cycle detected for promise #<Promise>throw new TypeError('Chaining cycle detected for promise #<Promise>')}if(x instanceof MyPromise){x.then(res => resolve(res),err => reject(err))}else{resolve(x)}} catch (error) {reject(error)}})

成功捕获错误!

对于reject同理,同样需要处理返回值和异常、处理返回promise、获取重复调用四个步骤,用于代码需要重复调用,所以我们将其封装成函数以进行复用

// 抽取函数function resolvePromise(p2,x,resolve,reject){if(x === p2){throw new TypeError('Chaining cycle detected for promise #<Promise>')}if(x instanceof MyPromise){x.then(res => resolve(res),err => reject(err))}else{resolve(x)}}

功能正常!

作为中立状态的pending也必不可少,同样需要处理返回值和异常、处理返回promise、获取重复调用四个步骤。

 // 添加回调函数this.#handlers.push({onFulfilled:()=>{runAsyncTask(() => {// 1、处理异常try {// 2、获取返回值const x =  onFulfilled(this.result)// 3、调用函数resolvePromise(p2,x,resolve,reject)} catch (error) {reject(error)}})},onRejected:()=>{runAsyncTask(() => {// 1、处理异常try {// 获取返回值const x = onRejected(this.result)resolvePromise(p2,x,resolve,reject)} catch (error) {reject(error)}})}})

仍可成功获取。

实例方法:

.catch()

Promise 实例的 catch() 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法。此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。

根据文档在then方法中添加已有catch方法,却发现无法调用reject中捕获异常功能,而是在调试throw error使用浏览器报错,故在自己定义的reject方法中使用try catch 捕获错误。

  const reject = (result) => {if(this.status === PENDING){// 修改状态并记录结果this.status = REJECTEDthis.result = result// 调用失败回调函数this.#handlers.forEach(({onRejected}) => {onRejected(result)})}}// 处理异常try {func(resolve,reject)  } catch (error) {reject(error)}then(onFulfilled,onRejected){// 根据mdn知道需要判断回调函数是否为函数,如果不是需要处理onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => valueonRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}// 处理重复引用const p2 = new MyPromise((resolve,reject)=>{if(this.status === FULFILLED){runAsyncTask(() => { try {const x = onFulfilled(this.result)resolvePromise(p2,x,resolve,reject)//         // 判断是否重复//     if(x===p2)//     {//         // 抛出异常Chaining cycle detected for promise #<Promise>//         throw new TypeError('Chaining cycle detected for promise #<Promise>')//     }//    if(x instanceof MyPromise){//        x.then(res => resolve(res),err => reject(err))//    }//    else{resolve(x)}} catch (error) {reject(error)}})}else if(this.status === REJECTED){runAsyncTask(() => {try {const x = onRejected(this.result)resolvePromise(p2,x,resolve,reject)} catch (error) {reject(error)}})}//异步和多次调用else if(this.status === PENDING){// 添加回调函数this.#handlers.push({onFulfilled:()=>{runAsyncTask(() => {// 1、处理异常try {// 2、获取返回值const x =  onFulfilled(this.result)// 3、调用函数resolvePromise(p2,x,resolve,reject)} catch (error) {reject(error)}})},onRejected:()=>{runAsyncTask(() => {// 1、处理异常try {// 获取返回值const x = onRejected(this.result)resolvePromise(p2,x,resolve,reject)} catch (error) {reject(error)}})}})}})return p2}catch(onRejected){return this.then(undefined,onRejected)}}
// 测试手写const p = new MyPromise((resolve,reject) => {// reject('fail')throw 'error!'})p.then(res=>{console.log('res:',res)}).catch(err => {console.log('err:',err)})

.finally

Promise 实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法。

无论错误还是成功都不会影响调用.finally时的输出。

finally(onFinally){return this.then(onFinally,onFinally)}

静态方法:

.resolve()

Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。

 // 添加静态方法static resolve(value){if(value instanceof MyPromise){return value}return new MyPromise((resolve,reject) => {resolve(value)})}// 测试手写MyPromise.resolve(new MyPromise((resolve,reject) => {//resolve(1)//reject('fail')//throw 'error'})).then(res => {console.log('res:',res)},err=>{console.log('err:',err)})MyPromise.resolve('ian').then(res=>{console.log('res:',res)})

.reject()

Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。

static reject(value){return new MyPromise((undefined,reject) => {reject(value)})}
.race()

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

static race(promises){// 1、返回Promise对象return new MyPromise((resolve,reject)=>{// 2、判断是否为数组if(!Array.isArray(promises)){return reject(new TypeError('You must pass an array')) }// 3、等待第一个敲定promises.forEach(p=>{//p.thenMyPromise.resolve(p).then(res => {resolve(res)},err => {reject(err)})})}) }
.all()

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

static all(promises){// 1、返回Promise对象return new MyPromise((resolve,reject)=>{// 2、判断是否为数组if(!Array.isArray(promises)){return reject(new TypeError('Argument is not iterable'))}// 3、空数组直接兑现promises.length === 0 && resolve(promises)// 4、处理全部兑现//     4.1、记录结果:使用索引来记录,保证结果的顺序和Promise数组的顺序一致//     4.2、判断是否全部兑现:通过兑现的次数来判断,保证可以获取道德所有结果const results = [] // 记录结果let count = 0 // 记录兑现次数promises.forEach((p,index)=>{MyPromise.resolve(p).then(res => {results[index] = res// 判断是否全部兑现count++count === promises.length && resolve(results)},err => {// 有一个失败则全部失败reject(err)})})})}

.allSettled()

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

无论是resolve还是reject都属于promise的pending敲定,使用resolve!
 

  static allSettled(promises){// 1、返回Promise对象return new MyPromise((resolve,reject)=>{// 2、判断是否为数组if(!Array.isArray(promises)){return reject(new TypeError('Argument is not iterable'))}// 3、空数组直接兑现promises.length === 0 && resolve(promises)// 4、处理全部兑现//     4.1、记录结果:使用索引来记录,保证结果的顺序和Promise数组的顺序一致const results = [] // 记录结果let count = 0 // 记录兑现次数promises.forEach((p,index)=> {MyPromise.resolve(p).then(res =>{// 4.2、处理兑现{status: FULFILLED,value: res}results[index] = {status: FULFILLED,value: res}count++count === promises.length && resolve(results)},err=>{// 4.3、处理拒绝{status: REJECTED,reason: err}results[index] = {status: REJECTED,reason: err}count++count === promises.length && resolve(results)})})})}
// 测试手写const p1 = MyPromise.resolve(1)const p2 = 2const p3 = new MyPromise((resolve,reject) => {setTimeout(() => {// resolve(3)reject('fail')},1000)})MyPromise.allSettled([p1,p2,p3]).then(res => {console.log('res:',res)},err => {console.log('err:',err)})

.any()

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

AggregateError 对象代表了包装了多个错误对象的单个错误对象。当一个操作需要报告多个错误时,例如 Promise.any(),当传递给它的所有承诺都被拒绝时,就会抛出该错误。

AggregateError 是 Error 的子类。

            static any(promises){// 1、返回Promise对象return new MyPromise((resolve,reject)=>{// 2、判断是否为数组if(!Array.isArray(promises)){return reject(new TypeError('Argument is not iterable'))}// 3、空数组直接拒绝promises.length === 0 && reject(new AggregateError(promises,'All promises were rejected'))// 4、处理第一个兑现//     4.1、记录结果:使用索引来记录,保证结果的顺序和Promise数组的顺序一致//     4.2、判断是否全部兑现:通过兑现的次数来判断,保证可以获取道德所有结果const errors = [] // 记录结果let count = 0 // 记录兑现次数promises.forEach((p,index)=>{MyPromise.resolve(p).then(// 第一个兑现res => {resolve(res)},err => {// 全部拒绝errors[index] = errcount++count === promises.length && reject(new AggregateError(errors,'All promises were rejected'))})})})}// 测试手写const p1 = new MyPromise((resolve,reject) => {setTimeout(() => {//resolve(1)reject(1)},2000)})const p2 = MyPromise.reject(2)const p3 = new MyPromise((resolve,reject) => {setTimeout(() => {//resolve(3)reject(3)},1000)})// MyPromise.any([]).then(res => {//MyPromise.any().then(res => {MyPromise.any([p1,p2,p3]).then(res => {console.log('res:',res)},err => {console.dir(err)})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/297819.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式 --5观察者模式

观察者模式 观察者模式的优缺点 优点 当一个对象改变的时候 需要同时改变其他对象的相关动作的时候 &#xff0c;而且它不知道有多少具体的对象需要改变 应该考虑使用观察者模式 。观察者模式的工作就是解除耦合 让耦合双方都依赖与抽象 而不是具体 是的各自改变都不会影响另…

Leetcode_2两数相加

文章目录 前言一、两数相加1.1 问题描述1.2 解法一&#xff1a;分别将链表转为数字&#xff0c;然后相加1.3 代码实现1.4 解法二&#xff1a;分别将对应位置数字相加1.5 代码实现 二、使用步骤1.引入库2.读入数据 前言 链表是一种物理内存非连续存储&#xff0c;非顺序的线性数…

golang 和java对比的优劣势

Golang&#xff08;或称Go&#xff09;和Java都是非常流行的编程语言&#xff0c;被广泛应用于各种领域的软件开发。尽管它们都是高级编程语言&#xff0c;但它们具有许多不同的特性和适用场景。本文将重点比较Golang和Java&#xff0c;探讨它们的优势和劣势。 性能方面&#…

Django之关系模型的序列化

一、关系模型的序列化-多查1 1.1、模型准备 from django.db import models# Create your models here. class Classes(models.Model):name = models.CharField(max_length=20, verbose_name=班级)class Student(models.Model):SEX_CHOICES = ((1,男)), (2, 女)name = models.C…

Python:百度AI开放平台——OCR图像文字识别应用

一、注册百度AI开放平台 使用百度AI服务的步骤为&#xff1a; 注册&#xff1a;注册成为百度AI开放平台开发者&#xff1b;创建AI应用&#xff1a;在百度API开放平台上创建相关类型的的AI应用&#xff0c;获得AppID、API Key和Secret Key&#xff1b;调用API&#xff1a;调用…

Mac删除软件,动一动手指,几秒就彻底删除 mac删除软件删不掉的解决方法 mac删除软件后怎么删除软件数据

当你入职新公司&#xff0c;接手前任员工使用的Mac电脑时&#xff0c;很可能会遇到一个非常普遍的问题&#xff1a;电脑中装有大量你不需要的软件。这些软件不仅占用宝贵的硬盘空间&#xff0c;还可能影响电脑的运行速度和效率。为了获得一个干净、清爽的使用体验&#xff0c;删…

Spark-Scala语言实战(12)

在之前的文章中&#xff0c;我们学习了如何在spark中使用键值对中的join,rightOuterJoin,leftOuterJoin三种方法。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢…

小林coding图解计算机网络|基础篇01|TCP/IP网络模型有哪几层?

小林coding网站通道&#xff1a;入口 本篇文章摘抄应付面试的重点内容&#xff0c;详细内容还请移步&#xff1a; 文章目录 应用层(Application Layer)传输层(Transport Layer)TCP段(TCP Segment) 网络层(Internet Layer)IP协议的寻址能力IP协议的路由能力 数据链路层(Link Lay…

Redis 主从复制,哨兵模式,集群

目录 主从复制 主从复制 作用 缺陷 主从复制流程 实现Redis主从复制 哨兵模式 主从复制切换的缺点 哨兵的核心功能 哨兵模式原理 哨兵模式的作用 哨兵结构组成 故障转移机制 主节点的选举 实现哨兵模式 集群(Cluster) redis群集有三种模式&#xff0c;主从复制…

【Linux】网络基础常识{OSI七层模型/ TCP/IP / 端口号 /各种协议}

文章目录 1.网络常识1.0DHCP协议1. 1IP地址/MAC地址/ARP协议是什么&#xff1f;IP/MACARP&#xff1a;IP ⇒ MAC 1.2手机连接wifi的原理 SSID与BSSID手机连接wifiSSID与BSSID 1.3手机如何通过“数据/流量”上网&#xff1f;1.4电脑连接wifi的原理&#xff1f;电脑通过热点上网…

SystemHelper已停止运行解决方案

当手机一开机就提醒 SystemHelper已停止运行&#xff0c;但手机也能正常使用就是部分软件打不开怎么办&#xff1f; 有此提示说明你的系统已经 Root 了并且你安装了某些不知名的软件或者 Magisk 模块导致系统环境发生了不可逆的修改&#xff0c;有 Magisk 建议还原官方 Boot 启…

快速入门Linux,Linux岗位有哪些?(一)

文章目录 Linux与Linux运维操作系统&#xff1f;操作系统图解 认识LinuxLinux受欢迎的原因什么是Linux运维Linux运维岗位Linux运维岗位职责Linux运维架构师岗位职责Linux运维职业发展路线计算机硬件分类运维人员的三大核心职责 运维人员工作&#xff08;服务器&#xff09;什么…

3.6k star, 免费开源跨平台的数据库管理工具 dbgate

3.6k star, 免费开源跨平台的数据库管理工具 dbgate 分类 开源分享 项目名: dbgate -- 免费开源跨平台的数据库管理工具 Github 开源地址&#xff1a; GitHub - dbgate/dbgate: Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under…

CVE-2021-30517:Type confusion bug in LoadSuperIC

前言 这个漏洞是一个比较老的洞&#xff0c;之所以分析这个漏洞&#xff0c;只要是想再学习一下 ICs 相关的知识。并该漏洞的利用是利用与 String/Function 之间的混淆&#xff0c;比较有意思。 环境搭建 sudo apt install python git checkout 7d5e5f6c62c3f38acee12dc4114…

vue快速入门(五)v-show与v-if

注释很详细&#xff0c;直接上代码 上一篇 新增内容 v-if与v-show底层的区别v-if与v-show的效果 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice…

【OpenCV】图像像素的遍历

1 前言 介绍两种遍历像素的方法&#xff08;非指针、指针&#xff09;。注意&#xff1a;.at() .ptr()的作用、用法。相关API&#xff1a; Mat对象.ptr() Mat对象.at() 2 代码及内容 #include "iostream" #include "opencv2/opencv.hpp"using namespac…

vue3表单参数校验+正则表达式

这里我们要实现在form表单中对表单项添加参数校验。 校验要求 我们的表单中有用户名、密码、电话号码、邮箱这四个项。 我们设置用户名为3到20位的非空字符 密码为3到25位非空字符 电话号码就用目前用的电话号码正则表达式&#xff0c;要求手机号码以 1 开头&#xff0c;第…

Plonky2.5:在Plonky2中验证Plonky3 proof

1. 引言 Plonky2.5为QED Protocol团队主导的项目&#xff0c;定位为&#xff1a; 在Plonky2 SNARK中验证Plonky3 STARK proof。 从而实现Plonky系列的递归证明。 开源代码实现见&#xff1a; https://github.com/QEDProtocol/plonky2.5https://github.com/Plonky3/Plonky3&a…

BoostCompass —— 搜索引擎

文章目录 一、项目简介二、Boost库简介1. 简介2. Boost 库的特点 三、项目主要模块1. 网页内容获取&#xff0c;数据预处理模块2. 建立正排索引和倒排索引&#xff0c;项目核心模块3. 编写 http_server 模块&#xff0c;进行网络开放 四、项目功能预览1. 项目文件预览2. 项目执…

如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性&#xff1f; 我们都知道&#xff0c;Redis是一个基于内存的键值存储系统&#xff0c;数据完全存放在内存中&#xff0c;这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据&#xff0c;通过将它们缓存在…