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.mzph.cn/news/793571.shtml

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

相关文章

C++:逻辑运算符-非与或(19)

!非!a如果a为假&#xff0c;那么当前他就是真&#xff0c;如果a是真&#xff0c;那么他直接就是假&&与a&&ba与b都为真&#xff0c;那么就是真&#xff0c;如果两个里面有一个为假那么就是假||或a||ba或b有一个为真&#xff0c;那么就是真 非&#xff08;!&…

【数据结构与算法】力扣 203. 移除链表元素

题目描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a; head [1,2,6,3,4,5,6], val 6 输出&#xff1a; [1,2,3,4,5]示例 2&#xff1a; 输…

一文弄懂CNN/RNN/GAN/Transformer等架构

1. 引言 本文旨在友好地介绍深度学习架构&#xff0c;包括卷积神经网络&#xff08;CNN&#xff09;、循环神经网络&#xff08;RNN&#xff09;、生成对抗网络&#xff08;GAN&#xff09;、transformer 和 encoder-decoder 架构。 闲话少说&#xff0c;让我们直接开始吧。 …

【OpenCV】图像像素的遍历

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

正则表达式(2)

文章目录 专栏导读1、贪婪与非贪婪2、转义匹配 专栏导读 ✍ 作者简介&#xff1a;i阿极&#xff0c;CSDN 数据分析领域优质创作者&#xff0c;专注于分享python数据分析领域知识。 ✍ 本文录入于《python网络爬虫实战教学》&#xff0c;本专栏针对大学生、初级数据分析工程师精…

国外服务器托管需要了解哪些信息

国外服务器托管服务提供了一种在国外租用并管理服务器的方式&#xff0c;适用于需要特定地域服务或对本地法规有特殊要求的企业和个人。那么想要进行国外服务器托管需要了解哪些信息呢?Rak部落小编为您整理发布国外服务器托管相关内容。 以下是一些关于国外服务器托管服务的详…

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

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

STM32单片机智能电表交流电压电流程序设计(电流 电压互感器TV1005M+TA1005M)

资料下载地址&#xff1a;STM32单片机智能电表交流电压电流程序设计(电流 电压互感器TV1005MTA1005M) 1、摘要 5、基于STM32F103单片机智能电表交流电压电流设计 本设计由STM32单片机核心板电路交流电压电流检测模块电路WIFI模块电路指示灯电路组成。 1、通过电压互感器TV100…

XML --java学习笔记

XML(全称EXtensible Markup Language&#xff0c;可扩展标记语言) 本质是一种数据的格式&#xff0c;可以用来存储复杂的数据结构&#xff0c;和数据关系 XML的特点 XML中的“<标签名>”称为一个标签或一个元素&#xff0c;一般是成对出现的XML中的标签名可以自己定义…

Doris实践——信贷系统日志分析场景的实践应用

目录 前言 一、早期架构演进 1.1 架构1.0 基于Kettle MySQL离线数仓 1.2 架构2.0 基于 Presto / Trino统一查询 二、基于Doris的新一代架构 三、新数仓架构搭建经验 3.1 并发查询加速 3.2 数仓底座建设 四、Doris助力信DolphinScheduler 和 Shell 贷业务场景落地 4.…

【Git】命令行使用体验大大优化的方法

Git的优化使用 相信很多人&#xff0c;在使用git作为版本管理工具时都会感受到它的方便&#xff0c;但是也会有一些问题困扰着我们&#xff0c;让我们觉得使用体验不是很好。我在使用git的过程中就发现了几个问题&#xff1a;写commit费时、怎么做多人开发的代码审查等等。今天…

基于springboot+vue+Mysql的在线考试系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Linux操作系统之防火墙、redis安装

目录 一、防火墙 1、防火墙的类别 2、安装iptables(四表五链&#xff09; 一、防火墙 1、防火墙的类别 安全产品 杀毒 针对病毒&#xff0c;特征篡改系统中文件杀毒软件针对处理病毒程序 防火墙 针对木马&#xff0c;特征系统窃密 防火墙针对处理木马 防火墙分为两种 硬件…

Codeforces Round 824 (Div. 2) D. Meta-set

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5; c…

设计模式——工厂模式01

工厂模式 定义&#xff1a;工厂模式是创建子类实例化对象的一种方式&#xff0c;屏蔽了创造工厂的内部细节。把创建对象与使用对象进行拆分&#xff0c;满足单一职责。如果需要向工厂中添加新商品&#xff0c; 只需要扩展子类再重写其工厂方法&#xff0c;满足开闭原则。 设计…

第十一届能源与环境研究国际会议-可再生能源走向脱碳化(ICEER 2024)即将召开!

能源和环境是当今世界至关重要的研究和教育领域&#xff0c;持续的气候危机和对可持续发展战略的迫切需求&#xff0c;需要从能源科学到地球工程等广泛领域的变革性工程解决方案和创新。ICEER 2024为来自学术界&#xff0c;研究中心和全球工业界的工程师&#xff0c;研究人员和…

以太网布局指南

2层板 顶层走信号线以及地平面底层走信号线以及地平面信号走线应至少沿一条边被接地或接地走线包围如果使用地走线&#xff0c;应接本层接地平面&#xff0c;与上层接地平面解耦。 4层板 当信号走线被重新引用到功率平面时&#xff0c;在地平面和功率平面之间需要去耦电容器(0…

SAP HCM 多成本中心薪酬过账标准程序解读

SAP HCM薪酬过账会涉及到CO对象&#xff0c;CO对象主要是成本中心、WBS、内部订单、订单等&#xff0c;成本中心有多个维护地方0001信息类型0027信息类型等&#xff0c;那么成本中心多个地方维护&#xff0c;优先级是如何&#xff0c;0027>1018>0001,也就是说人身上的优先…

【数据结构(一)】初识数据结构

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你学更多数据结构知识 目录 1.前言2.集合架构3.时间和空间复杂度3.1算法效率3.2时间复杂度3.2.1大O的渐进…

Golang | Leetcode Golang题解之第10题正则表达式匹配

题目&#xff1a; 题解&#xff1a; func isMatch(s string, p string) bool {m, n : len(s), len(p)matches : func(i, j int) bool {if i 0 {return false}if p[j-1] . {return true}return s[i-1] p[j-1]}f : make([][]bool, m 1)for i : 0; i < len(f); i {f[i] m…