万字详细总结 Promise(期约)及其方法

news2024/11/26 8:41:46

万字详细总结 Promise(期约)及其方法

ES6之前的异步编程

异步行为是 javascript 的基础操作。我们在开发的过程中往往需要执行一个操作并得到一个结果(例如从后端请求数据),但是由于 javascript 是单线程,所以就用异步任务处理这些耗时的操作,避免 javascript 主线程阻塞(捋一捋 JavaScript 事件循环机制这篇文章详细介绍 javascript 异步的来龙去脉)。

但是怎么拿到异步任务的结果呢? 广泛的策略就是给异步任务提供一个回调函数,当异步任务成功时把结果当做参数传给这个回调函数继续处理,该回调函数称为成功回调。那么任务出错时怎么处理呢? 我们也可以定义一个回调函数,把错误理由作为参数传给它,由它负责后续处理,该回调函数称为失败回调。最后若有多个异步任务,并且后一个异步任务的执行需要前一个异步任务的结果的情况就需要嵌套回调,即把后一个异步任务作为前一个异步任务的成功回调函数。基于以上讨论,我们可以得到如下代码:

function myAsync(value, success, failure) {
  setTimeout(() => {
    try {
       if (/*异步任务失败条件*/) {
         throw new Error('error');
       }
      success(value * 2);
    } catch (error) {
      failure(error)
    }
  }, 500);
}
const success = (value) => {
  myAsync(value, () => console.log(value), () => console.log(value))
}
const failure = (err) => {
  console.log(err)
}
myAsync(1, success, failure);

这里的就形成了异步任务的嵌套,不够直观?没关系,我们看下面的例子:

setTimeout(() => {
  // 经过一系列操作拿到结果 value
  setTimeout(() => {
    // 经过一系列操作拿到结果 value
    setTimeout(() => {
      // 经过一系列操作拿到结果 value
      //······
    }, 500)
  }, 500)
}, 500);

因为在早期只支持定义回调函数来表明异步操作,所以通常需要深度嵌套的函数来解决串联多个异步操作。这就是大名鼎鼎的回调地狱。当嵌套深度过深的时候就会耗费大量的心智去分析代码,显然不利于后期维护。

Promise 期约

由于回调函数的种种问题,于是在 ES6 中基于 Promise/A+ 规范进行完善和支持,Promise 期约诞生了。用它来代替回调函数处理异步任务。

Promise 基本概念及使用

Promise 实例化

Promise 是一个对象,可以通过 new 操作符实例化,实例化时必须要传入执行器函数(它的作用是初始化期约的异步行为和控制期约状态转换),否则会报错。这里还需要注意的是尽管 Promise 是处理异步任务的,但是执行器函数是同步执行的

console.log(0);
const p = new Promise(() => {
  console.log(1);
})
console.log(2);

在这里插入图片描述

可以看到 0、1、2 是顺序打印的,足以说明执行器函数是同步执行的(不明白的话一定要看看这篇文章捋一捋 JavaScript 事件循环机制)。

期约状态机

期约不仅是一个对象,还是一个有状态的对象,它一共有三种状态:

  • 待定(pending)
  • 解决(fulfilled || resolved)
  • 失败(rejected)

期约最初一般为待定(pending)状态,表示异步任务正在执行,还不知道成功与否;若异步任务执行成功,状态将变为解决状态;若异步任务执行失败,状态将变为失败状态。并且状态只能由待定变为解决或失败,状态的改变只由异步任务的成功失败决定,任何其他操作都无法影响其状态。当状态改变后,无论你做什么都不会再次改变,并且你任何时候取值状态都是一样的。这个结论很重要!!!

const p = new Promise(() => {
  console.log(1);
})
console.log(p);

在这里插入图片描述

这里我打印了 Promise 实例 p,由结果可以看到它的状态为待定(pending)。

切换 Promise 状态

从上面的输出可以看到在实例化 Promise 时只传给它了一个执行器函数,所以我们只能在这下手了。

其实执行器函数可以有两个函数参数,这两个函数参数一般写为resolvereject调用resolve函数会把期约的状态有待定变为解决(resolved),调用reject函数会把期约的状态由待定变为失败(rejected)。并且Promise状态的改变只能依靠这两个函数,如果未调用任何一个,那么期约的状态将会是待定(pending) 这两个函数都是可选的

文首说过,我们往往会需要异步任务执行成功后的结果,哪怕失败也要拿到失败理由。但是注意结果和失败理由都是属于 Promise 内部私有的,除非 Promie 扔出来(我是这么理解的),否则我们永远也拿不到。而我们可以将结果作为参数传给resolve扔出来,将失败理由作为参数传给reject扔出来。

const p1 = new Promise((resolve) => {
  resolve(123);//将状态变为解决,并把结果 123 作为参数扔出来
})
const p2 = new Promise((resolve, reject) => {
  reject('error!!!');//将状态变为失败,并把失败理由 error!!! 作为参数扔出来
})
const p3 = new Promise((resolve, reject) => {
  resolve(123);
  reject('fail');
})
const p4 = new Promise((resolve, reject) => {
  reject('fail');
  resolve(123);
})
setTimeout(() => {
  console.log(p1);
  console.log(p2);
  console.log(p3);
  console.log(p4);
}, 0);

在这里插入图片描述

由 p3、p4 的打印结果可以看出状态一旦改变,状态就不会再变了。最后两个报错是因为没有处理异步失败时抛出的错误。

Promise 的静态方法

Promise.resolve

期约初始并不一定非得是待定状态,Promise.resolve()方法可以直接实例化一个解决了的期约。

const p1 = Promise.resolve('success');//等价于下面一行代码
const p2 = new Promise((resolve) => resolve('success'));
console.log(p1);
console.log(p2);

在这里插入图片描述

这个函数的参数就是异步任务成功的结果。

const p1 = Promise.resolve(1);
const p2 = Promise.resolve({ name: '孤城浪人' });
const p3 = Promise.resolve(true);
const p4 = Promise.resolve(function () { });
const p5 = Promise.resolve([1, 2, 3]);
const p6 = Promise.resolve(new Error('error!!!'));
const p7 = Promise.resolve(new Promise(() => 1));
const p8 = Promise.resolve(new Promise((resolve) => resolve(1)));
const p9 = Promise.resolve(new Promise((resolve, reject) => reject('error!!!')));
const p10 = Promise.resolve(1, 2, 3);
const p11 = Promise.resolve();
console.log(p1);
···

在这里插入图片描述

由上面的示例可以得到如下结论:

  • Promise.resolve() 方法可以将所有非 Promise 值转为一个状态为解决(resolved)的期约,且结果作为参数传入的值,即使参数是一个错误对象(注意这可能会导致不符合预期的行为)。如:p1、p2、p3、p4、p5、p6。

  • 当传入的参数不止一个时,会自动忽略从第二个参数开始的所有后续参数,如 p10,输出后结果只有第一个参数 1,忽略了 2、3 。

  • Promise.resolve() 还是幂等的,即当传入的参数本身也是一个期约,本方法会原封不动地返回这个期约。如 p7、p8、p9,可以看到本方法返回的期约就是传入的 Promise 实例。

  • 如果不传入参数,那么也会返回一个状态为解决(resolved)的期约,只不过结果为 undefined。如 p11。

Promise.reject

这个方法会返回一个状态为失败(rejected) 的期约并抛出一个异步错误。注意 Promise.reject() 不是幂等的。无论你传入的参数是什么,总是返回一个状态为rejected的期约。拒绝理由就是传入的第一个参数。

const p1 = Promise.reject(1);
const p2 = Promise.reject({ name: '孤城浪人' });
const p3 = Promise.reject(true);
const p4 = Promise.reject(function () { });
const p5 = Promise.reject([1, 2, 3]);
const p6 = Promise.reject(new Error('error!!!'));
const p7 = Promise.reject(new Promise(() => 1));
const p8 = Promise.reject(new Promise((resolve) => resolve(1)));
const p9 = Promise.reject(new Promise((resolve, reject) => reject('error!!!')));
const p10 = Promise.reject(1, 2, 3);
const p11 = Promise.reject();
console.log(p1);
···

在这里插入图片描述

由以上示例可以得到如下结论:

  • 如果不传入参数,那么也会返回一个状态为解决(resolve)的期约,只不过拒绝理由为 undefined。如 p11。

  • 当传入的参数不止一个时,会自动忽略从第二个参数开始的所有后续参数,如 p10,输出后结果只有第一个参数 1,忽略了 2、3 。

注意:抛出的异步错误不能被try/catch捕获。因为拒绝期约的错误并没有抛到执行同步代码的线程里,而是通过浏览器异步消息队列来处理的

try {
  throw new Error('error')
} catch (err) {
  console.log('捕获了错误' + err);
}
try {
  Promise.reject(new Error('promise error'));
} catch (err) {
  console.log('捕获了promise错误' + err);
}

在这里插入图片描述

try/catch 捕获了第一个代码块抛出的错误,却没有捕获到期约抛出的错误。

Promise.all

Promise.all()方法用于将一组期约,包装成一个新的期约,新的期约只会在每个包含的期约都解决完后才会解决。

特点:

  • 所有的参数期约状态都变为解决(resolved),包装期约状态才为解决(resolved),结果为所有期约成功结果组成的数组。如 p5。

  • 若期约状态没有为失败(rejected)的,但有待定( pending) 的,包装期约状态为待定(pending),如 p6。

  • 若有期约状态为失败(rejected),那么包装期约状态为失败(rejected)。并且第一个状态变为失败的期约的失败理由将会是新期约失败的理由,如 p7、p8。

  • Promise.all接受的是一个空数组,那么就等价与Promise.resolve()方法,如 p9。

  • Promise.all接受的不是一组期约,那么就会将每一个元素通过Promise.resolve()转换为期约。

const p0 = new Promise(() => { });
const p1 = new Promise((resolve) => resolve('amazing'));
const p2 = new Promise((resolve) => resolve('success'));
const p3 = new Promise((resolve, reject) => reject('fail'));
const p4 = new Promise((resolve, reject) => reject('rejected'));
const p5 = Promise.all([p1, p2]);
const p6 = Promise.all([p0, p2]);
const p7 = Promise.all([p0, p2, p3]);
const p8 = Promise.all([p0, p2, p3, p4]);
const p9 = Promise.all([]);
const p10 = Promise.all([1, 2]);
setTimeout(() => {
  console.log(p5);// Promise {<fulfilled>: ['amazing','success']}
  console.log(p6);// Promise {<pending>}
  console.log(p7);// Promise {<rejected>: 'fail'}
  console.log(p8);// Promise {<rejected>: 'fail'}
  console.log(p9);// Promise {<fulfilled>: []}
  console.log(p10);// Promise {<fulfilled>: [1,2]}
}, 0);

Promise.any

本方法接受一组期约作为参数,包装成一个新的期约返回。新的期约只有在所有期约都失败后才会结束。

特点:

  • 只要参数期约有一个变成解决(resolved)状态,包装期约就会变成解决(resolved)状态,如 p5;

  • 只有所有参数期约都变成失败(rejected)状态,包装期约才会变成失败(rejected)状态,如 p6。

  • 若没有期约状态为解决(resolved),但有待定(pending)状态的期约,包装期约状态为待定(pending),如 p7。

  • Promise.any接受的是一个空数组,那么就等价与Promise.reject()方法,如 p8。

  • Promise.any接受的不是一组期约,那么就会将元素通过Promise.resolve()转换为期约,如 p9。

const p0 = new Promise(() => { });
const p1 = new Promise((resolve) => resolve('amazing'));
const p2 = new Promise((resolve) => resolve('success'));
const p3 = new Promise((resolve, reject) => reject('fail'));
const p4 = new Promise((resolve, reject) => reject('rejected'));
const p5 = Promise.any([p1, p2]);
const p6 = Promise.any([p0, p2]);
const p7 = Promise.any([p0, p3]);
const p8 = Promise.any([]);
const p9 = Promise.any([1, 2]);
setTimeout(() => {
  console.log(p5);// Promise {<fulfilled>: 'amazing'}
  console.log(p6);// Promise {<fulfilled>: 'success'}
  console.log(p7);// Promise {<pending>}
  console.log(p8);// Promise {<rejected>: AggregateError: All promises were rejected}
  console.log(p9);// Promise {<fulfilled>: 1}
}, 0);

Promise.race

Promise.race()方法同样是将多个期约,包装成一个新的期约,是一组集合中最先解决或拒绝的期约的镜像。若已有期约落定,但之后又有期约失败,会静默处理

特点:

  • 本方法无论是解决还是拒绝,只要是第一个落定状态的期约,就会包装其解决值或拒绝理由并返回新期约,新期约状态与第一个落定的期约状态一致。

  • Promise.race接受的是一个空数组,那么就等价与new Promise(()=>{})方法,如 p8。

  • Promise.race接受的不是一组期约,那么就会将元素通过Promise.resolve()转换为期约,如 p9。

const p0 = Promise.resolve('p0');
const p1 = Promise.reject('p1');
const p2 = new Promise((resolve, reject) => setTimeout(reject('p2'), 50000));
const p5 = Promise.race([p0, p1]);
const p6 = Promise.race([p1, p0]);
const p7 = Promise.race([p1, p2]);
const p8 = Promise.race([]);
const p9 = Promise.race([1, 2]);
setTimeout(() => {
  console.log(p5);// Promise {<fulfilled>: 'p0'}
  console.log(p6);// Promise {<rejected>: 'p1'}
  console.log(p7);// Promise {<rejected>: 'p1'}
  console.log(p8);// Promise {<pending>}
  console.log(p9);// Promise {<fulfilled>: 1}
}, 0);

Promise.allSettled

Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个期约,并返回一个新的期约。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是解决(fulfilled)还是拒绝(rejected)),返回的期约才会发生状态变更。

特点:

  • 返回的期约状态只有两种可能:所有期约状态都落定后,返回的期约状态为解决(resolved),若还有任意一个期约状态未落定,返回的期约状态为待定(pending),如 p5、p6。

  • 若返回的期约状态为解决(resolved),拿到的结果为数组,每个元素都是一个对象,该对象为期约对应异步操作结果,如p7、p8、p9。

// 拒绝,拒绝理由
{status: 'rejected', reason: 'p1' }
// 解决,结果
{status: 'fulfilled', value: 1}
const p0 = new Promise(() => { });
const p1 = Promise.reject('p1');
const p2 = new Promise((resolve, reject) => setTimeout(reject('p2'), 50000));
const p5 = Promise.allSettled([p0, p1]);
const p6 = Promise.allSettled([p1, p0, p2]);
const p7 = Promise.allSettled([p1, p2]);
const p8 = Promise.allSettled([]);
const p9 = Promise.allSettled([1, 2]);
setTimeout(() => {
  console.log(p5);// Promise {<pending>}
  console.log(p6);// Promise {<pending>}
  console.log(p7);// Promise {<fulfilled>: [{status: 'rejected', reason: 'p1' },{ status:'rejected', reason: 'p2' }]
  console.log(p8);// Promise {<fulfilled>: []}
  console.log(p9);// Promise {<fulfilled>: [{status: 'fulfilled', value: 1},{ status:'fulfilled', value: 2}]}
}, 0);

Promise 实例方法

每一个 Promise 实例都具有一些方法,它们是连接外部同步代码与内部异步代码之间的桥梁。这些方法可以访问异步操作返回的数据,处理期约成功和失败的输出或添加只有期约状态落定时才执行的代码。

Promise.prototype.then

then方法是定义在原型对象Promise.prototype上的,这个方法接受两个参数。第一个参数是期约进入resolved状态执行的回调函数,第二个参数是期约进入rejected状态执行的回调函数,它们都是可选的

由于期约状态只能改变一次,所以这两个参数一定是互斥的。并且then方法会返回一个新的 Promise 实例。

const p1 = new Promise((resolve) => resolve('success'));
const p2 = new Promise((resolve, reject) => reject('fail'));
const p3 = p1.then((res) => {
  console.log(res);//success
})
p2.then(null, (err) => {
  console.log(err);//fail
})
setTimeout(() => {
  console.log(p3 === p1);//false,证明p2是新实例
}, 0);
p1.then('success');//静默忽略

在这里插入图片描述

当期约状态变为解决(resolved)就会执行then方法的第一个参数函数并将结果传给回调函数。该函数的返回值实际上会使用 Promise.resolve 方法包装成新的期约,如果没有提供这个处理程序,就会用该方法包装上一个期约解决之后的值,如 p6,如果没有返回值,会用该方法包装 undefined,如 p3。很多特性都符合静态方法 Promise.resolve() 的特性,如 p4、p5。

const p1 = new Promise((resolve) => resolve('success'));
const p2 = new Promise((resolve, reject) => reject('fail'));
const p3 = p1.then((res) => { });
const p4 = p1.then((res) => '孤城浪人');
const p5 = p2.then(null, (err) => err + '^-^')
const p6 = p1.then();
const p7 = p1.then(() => new Error('error'));
const p8 = p1.then((res) => new Promise((resolve, reject) => reject('失败啦')));
const p9 = p1.then((res) => { throw Error('又失败啦') });
setTimeout(() => {
  console.log(p3);// Promise {<fulfilled>: undefined}
  console.log(p4);// Promise {<fulfilled>: '孤城浪人'}
  console.log(p5);// Promise {<fulfilled>: 'fail^-^'}
  console.log(p6);// Promise {<fulfilled>: 'success'}
  console.log(p7);// Promise {<fulfilled>: Error: error at http://127.0.0.1:5500/sc.html:119:30}
  console.log(p8);// Promise {<rejected>: '失败啦'}
  console.log(p9);// Promise {<rejected>: Error: 又失败啦 at http://127.0.0.1:5500/sc.html:117:42}
}, 0);

如果 Promise 实例状态变为失败(reject)就会执行then方法的第二个参数函数,并把失败理由传入,经过处理后(不是返回一个失败状态的 Promise 实例,非 p8),返回一个成功状态的 Promise 实例,如 p7。原因很简单,上一个 Promise 失败了,但是我已经成功处理了,当然应该返回一个成功的 Promise 实例了。

若在then方法方法中抛出一个错误,那么会返回一个状态为失败(rejected)的 Promise 实例。如 p9。

链式调用

const p1 = new Promise((resolve) => resolve('success'));
p1.then((res) => res + ' 孤城浪人',(res) => res)
  .then((res) => console.log(res));// success 孤城浪人

当前then方法的参数函数的参数,是上一个then执行的参数函数的返回值。如上代码,第一个then方法会执行第一个参数函数,得到参数 success,处理后返回 success 孤城浪人并交给下一个then函数要执行的参数函数。

Promise.prototype.catch

Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于给期约添加拒绝处理程序。只接受一个参数即拒绝处理程序。他返回一个新的 Promise 实例

const p1 = new Promise((resolve) => resolve('success'));
const p2 = new Promise((resolve, reject) => reject('fail'));
const p3 = new Promise((resolve, reject) => { throw new Error('error') });
let p4 = p1.catch((err) => console.log(err));
p2.catch((err) => console.log(err));
p3.catch((err) => console.log(err));

在这里插入图片描述

可以看到 p1 的状态为解决(resolved),所以 p1.catch并不会执行。那么 p4 是什么呢?输出看看,
在这里插入图片描述

它的状态和 p1 一样,再看看下面的代码

const p5 = p1.then(null, (err) => console.log(err));// Promise {<fulfilled>: 'success'}

它们输出一样,其实如果一个状态为解决(resolved)的 Promise 实例调用了.catch方法,就相当于调用了.then(null,() => {···})方法,但是成功处理程序未定义,那么就会用Promise.resolve包装上一个期约,就相当于p1.then()

  • 如果 Promise 状态已经变成resolved,再抛出错误是无效的。如 p4 对应的.catch未执行。

  • Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。同时catch只能捕获在它执行之前抛出的错误。如 p5 未能捕获处理在它之后抛出的错误。

const p0 = new Promise((resolve) => resolve('success'));
const p1 = new Promise((resolve, reject) => { throw new Error('error') });
const p2 = new Promise(function (resolve, reject) {
  resolve('ok');
  throw new Error('test');
});
let p3 = p1.catch((err) => console.log(err + ' p3'));
let p4 = p2.catch((err) => console.log(err + ' p4'));
let p5 = p0.catch((err) => console.log(err)).then((err) => { throw new Error('p0 出错啦,p5捕获处理') });
let p6 = p0.then(() => { throw new Error('p0 出错啦, p6捕获处理') }).catch((res) => console.log(res + '冒泡'))

在这里插入图片描述

你也许会以为若异步任务失败被catch捕获处理后就会停止向后执行,其实不然,程序依旧会继续执行。

const p1 = new Promise((resolve, reject) => { throw new Error('error') });
let p2 = p1.catch((err) => err + ' p2').then((res) => console.log(res)); // Error: error p2

Promise.prototype.finally

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。在大多数情况下它都会原样返回父期约。

只有两种情况不会原样返回父期约,finally()处理程序中显示的抛出了错误或返回一个待定(pending)或失败(rejected)状态的期约,则会方法最终会返回相应的期约(待定或失败),如 p5、p6、p7。

const p1 = new Promise((resolve) => resolve('success'));
const p2 = new Promise((resolve, reject) => reject('fail'));
const p3 = p1.finally(() => { });
const p4 = p2.finally(() => Promise.resolve(12));
const p5 = p2.finally(() => Promise.reject('出错了'));
const p6 = p2.finally(() => new Promise(() => { }));
const p7 = p2.finally(() => new Error('error'));
setTimeout(() => {
  console.log(p3);
  console.log(p4);
  console.log(p5);
  console.log(p6);
  console.log(p7);
}, 0);

在这里插入图片描述

Promise 的缺点

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

非常感谢阮一峰老师ECMAScript 6 入门的帮助。

总结

ES6 的 Promise 提出的目的是为了解决“回调地狱”的问题。它是一个有状态的对象,可以使用 new 操作符实例化,但在实例化时必须要传入执行器函数,该函数是同步执行的。接收两个参数函数,调用第一个参数可以将期约状态变为解决(resolved),也可以将异步任务的结果传给它,这样外界就能拿到该结果。Promise(期约)及其方法详细总结),也可以将失败理由作为参数传给它。如果未调用任何一个参数函数,那么期约的状态就为待定(pending)

期约的知识比较琐碎,但是很重要。我之前就是感觉半懂不懂的,导致在开发的时候使用总是比较虚,最近决定要好好研究一下,才有了这篇文章。我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

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

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

相关文章

[附源码]Python计算机毕业设计Django个性化名片网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

视频播放 (二) 自定义 MediaPlayer

1. 说明 1.1 使用Mediaplayer和surfaceView进行视频播放&#xff0c;并实现&#xff1a;感应生命周期、支持无缝续播、宽高比适配以及全屏模式 1.2 创建一个播放控制View&#xff0c;并以ViewModel驱动 2. 配置信息 2.1 AndroidManifest.xml 添加网络权限 <uses-permission…

Docker入门-上篇

Docker容器技术的使用&#xff0c;现在它已经不仅仅只是运维人员的专属技能了&#xff0c;对于我们开发人员同样需要具备&#xff0c;在很多中小公司中云环境的项目搭建和项目部署依然还是我们开发人员干的事&#xff0c;所以多学一门技术总是没错的。 1.Docker介绍 Docker最…

Ubuntu下解压文件(提取文件总是报错)文件是zip 格式

删除非空文件夹&#xff1a;在该目录下打开终端&#xff1a;sudo rm -r 文件夹名 回到不能解压问题&#xff08;unzip总是容易出问题&#xff09; 安装7zip&#xff1a;sudo apt-get install p7zip-full 解决办法1&#xff08;解压出来好的数据&#xff09;: 使用7z解压文件&…

附录6-JS中的一些概念

1 深拷贝与浅拷贝 在这几个地方涉及到了拷贝 23. 节点_Suyuoa的博客-CSDN博客 复制节点 node.cloneNode() 深拷贝实质上是拷贝要拷贝的对象自身&#xff0c;浅拷贝实质上是对要拷贝对象的引用。 当你浅拷贝复制A为B的时候&#xff0c;改动B会给A造成影响 当你深拷贝复制A…

极速Go语言入门(超全超详细)-进阶篇

基础篇可访问此链接: 基础篇1:https://blog.csdn.net/asd1358355022/article/details/127905011?spm1001.2014.3001.5501 基础篇2:https://blog.csdn.net/asd1358355022/article/details/128039005?spm1001.2014.3001.5501 文章目录GO语言类型断言文件操作打开、关闭、读取文…

第二证券|券商12月金股出炉!多只地产股成热门,科创仍是中长期主线

跟着券商12月金股战略陈述连续出炉&#xff0c;主流组织的配备风向也浮出水面。 到券商我国记者发稿时&#xff0c;已有10多家券商发布12月金股战略陈述&#xff0c;从职业散布来看&#xff0c;信息技术、工业范畴的金股数量最多&#xff0c;其次是材料、可选消费、医疗。值得一…

前端二倍图

物理像素&物理像素比&#xff1a; 物理像素点指的是屏幕显示的最小颗粒&#xff0c;是物理真实存在的&#xff0c;这是厂商在出厂时设置好了我们开发时候1px不是一定等于1个物理像素的Pc端页面&#xff0c;1px等于1个物理像素点&#xff0c;但是移动端就不尽相同一个px能显…

打包发布自己的app

创建自己的app 一、 安装HBuilderX 二、 引入代码&#xff0c;引入组件 三、 配置app信息 四、 云打包 1、第一步 2、第二步 3、证书创建是用的jdk8创建的&#xff0c;软件里带教程&#xff0c;也可以用公共测试证书。 五、打出的包是apk文件&#xff0c;配合我的搭建网…

ROG幻15电脑开机自动安装软件怎么U盘重装系统

ROG幻15电脑开机自动安装软件怎么U盘重装系统。今天和大家一起来分享如何解决ROG幻15电脑开机的时候会自动安装软件的问题。用户反馈开机之后自动后台安装很多软件&#xff0c;导致无法操作卡死。这个情况我们可以使用U盘来重装一些系统&#xff0c;这样就可以解决问题&#xf…

(二)正则表达式——捕获

&#xff08;二&#xff09;正则表达式——捕获 正则捕获的懒惰性 实现正则捕获的方法&#xff1a;exec exec返回的结果&#xff1a; 懒惰性 这就是正则捕获的懒惰性&#xff1a;默认只捕获第1个 lastIndex&#xff1a;下次匹配的开始位置 懒惰的原因&#xff1a;默认lastIndex…

视频播放 (一) VideoView的使用

1. 配置参数 1.1 AndroidManifest.xml 文件添加网络权限 <uses-permission android:name"android.permission.INTERNET" /> 1.2 http 明文请求设置 android:usesCleartextTraffic"true" 1.3 activity 配置屏幕变化&#xff0c;不重新加载 Activity …

多数据中心多活相关知识

Cell&#xff1a;业务可封闭收敛最小执行分片&#xff1b;业务对请求空间按一定维度&#xff08;比如会员、门店等&#xff09;划分分片。 LDC&#xff1a;逻辑数据中心&#xff0c;是由多个业务可封闭 cell 组成的集合单元&#xff0c;拥有独立的基础中间件系统&#xff08;包…

树莓派4b通过docker安装部署jenkins

借鉴&#xff1a;https://blog.csdn.net/wz_coming/article/details/113523610 树莓派的docker安装及其他操作请看&#xff1a;https://blog.csdn.net/weixin_44578029/article/details/127987795 前言 我的环境是树莓派4b&#xff0c;安装的官方64 debian11系统 arm架构 4h…

[附源码]SSM计算机毕业设计疫情状态下病房管理平台JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Kafka第一讲:应用场景及架构设计详解

本节是Kafka专题第一篇&#xff0c;主要介绍Kafka的发展历史、应用场景以及Kafka的基本架构&#xff0c;后续还会对Kafka的生产者、Broker、消费者、集群做详细讲解&#xff0c;敬请期待。 1.kafka的发展历史及应用场景 1.1kafka的定位 可以实现如下功能&#xff1a; 1.2为什…

『航班乘客满意度』场景数据分析建模与业务归因解释 ⛵

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; 数据分析实战系列&#xff1a;https://www.showmeai.tech/tutorials/40 &#x1f4d8; 机器学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/41 &#x1f4d8; 本文地址&#xff1a;https://www.sho…

vue+elementUI实现级联表格el-table级联多选

vueelementUI实现级联表格el-table级联多选 <template><div id"app"><el-button type"primary" click"getAllSelect()">获取选中集合</el-button><el-table:data"renderDynamic"ref"lendontable"…

DataFun: 微信NLP算法微服务治理

管理问题 性能问题 PyInter&#xff1a;暂未开源&#xff0c;有开源打算 调度问题 P50&#xff1a; 响应的中位数P999&#xff1a;耗时最慢的千分之一 让p999下降为p50的1.5倍

DIY正则图片下载工具

一、初心&#xff1a;如果您擅长正则表达式&#xff0c;可以自定义抓取自定义网页的图片。 二、效果&#xff1a; 目前支持 <img>标签抓取图片正则。更多正则欢迎分项。支持base64图片预览。 三、使用方法&#xff1a; 修改正则表达式&#xff1a;选中即可。同时工具几…