解决异步问题,教你如何写出优雅的promise和async/await,告别callback回调地狱!

解决异步问题——promise、async/await

  • 一、单线程和异步
    • 1、单线程是什么
    • 2、为什么需要异步
    • 3、使用异步的场景
    • 二、promise
    • 1、promise的三种状态
    • 2、三种状态的表现和变化
      • (1)状态的变化
      • (2)状态的表现
    • 3、then和catch对状态的影响(重要)
    • 4、then和catch的链式调用(常考)
  • 三、async/await
    • 1、引例阐述
    • 2、async和await
    • 3、async/await和promise的关系
    • 4、异步的本质
    • 5、场景题
      • (1)async/await语法
      • (2)async/await的顺序问题
  • 四、写在最后

我们平常在写 js 中,经常只管程序能跑就行,但很少去深究它的原理。更别说还有一个同步和异步的问题了。因此,程序往往有时候出现莫名其妙的卡死或者有时候执行顺序达不到我们想要的结果时自己都不知道往哪里找错。下面的这篇文章中,将讲解同步和异步的问题,以及如何解决异步问题的promise、async/await方法。

在看本文之前,建议大家先对 event loop 有一个了解。可以先看我的上一篇文章了解event loop以及微任务宏任务的相关知识,这样到后面看本文的 async/await 的时候会更友好一些。

下面开始进行本文的讲解。

一、单线程和异步

1、单线程是什么

(1) JS 是单线程语言,只能同时做一件事情

  • 所谓单线程,就是只能同时做一件事情,多一件都不行,这就是单线程。

(2) 浏览器和 nodejs 已支持 JS 启动进程,如 Web Worker

(3) JSDOM 渲染共用同一个线程,因为 JS 可修改 DOM 结构

  • JS 可以修改 DOM 结构,使得它们必须共用同一个线程,这间接算是一件迫不得已的事情。
  • 所以当 DOM 在渲染时 JS 必须停止执行,而 JS 执行过程 DOM 渲染也必须停止。

2、为什么需要异步

当程序遇到网络请求或定时任务等问题时,这个时候会有一个等待时间。

假设一个定时器设置10s,如果放在同步任务里,同步任务会阻塞代码执行,我们会等待10s后才能看到我们想要的结果。1个定时器的等待时间可能还好,如果这个时候是100个定时器呢?我们总不能等待着1000s的时间就为了看到我们想要的结果吧,这几乎不太现实。

那么这个时候就需要异步,通过异步来让程序不阻塞代码执行,灵活执行程序。

3、使用异步的场景

(1)异步的请求,如ajax图片加载

//ajax
console.log('start');
$.get('./data1.json', function (data1) {console.log(data1);
});
console.log('end');

(2)定时任务,如setTimeout、setInterval

//setTimeout
console.log(100);
setTimeout(fucntion(){console.log(200);           
}, 1000);
console.log(300);
//setInterval
console.log(100);
setInterval(fucntion(){console.log(200);           
}, 1000);
console.log(300);

二、promise

早期我们在解决异步问题的时候,基本上都是使用callback回调函数的形式 来调用的。形式如下:

//获取第一份数据
$.get(url1, (data1) => {console.log(data1);//获取第二份数据$.get(url2, (data2) => {console.log(data2);//获取第三份数据$.get(url3, (data3) => {console.log(data3);//还可以获取更多数据});});
});

从上述代码中可以看到,早期在调用数据的时候,都是一层套一层, callback 调用 callback ,仿佛深陷调用地狱一样,数据也被调用的非常乱七八糟的。所以,因为 callback 对开发如此不友好,也就有了后来的 promise 产生, promise 的出现解决了 callback hell 的问题。

用一段代码先来了解一下 Promise

function getData(url){return new Promise((resolve, reject) => {$.ajax({url,success(data){resolve(data);},error(err){reject(err);}});});
}const url1 = '/data1.json';
const url2 = '/data2.json';
const url3 = './data3.json';
getData(url1).then(data1 => {console.log(data1);return getData(url2);
}).then(data2 => {console.log(data2);return getData(url3);
}).then(data3 => {console.log(data3);
}).catch(err => console.error(err));

大家可以看到,运用了 promise 之后,代码不再是一层套一层,而是通过 .then 的方式来对数据进行一个获取,这在写法上就已经美观了不少。那 promise 究竟是什么呢?接下来开始进行讲解。

1、promise的三种状态

  • pending :等待状态,即在过程中,还没有结果。比如正在网络请求,或定时器没有到时间。
  • fulfilled :满足状态,即事件已经解决了,并且成功了;当我们主动回调了 fulfilled 时,就处于该状态,并且会回调 then 函数。
  • rejected :拒绝状态,即事件已经被拒绝了,也就是失败了;当我们主动回调了 reject 时,就处于该状态,并且会回调 catch 函数。

总结:

  • 只会出现pending → fulfilled,或者pending → rejected 状态,即要么成功要么失败;
  • 不管是成功的状态还是失败的状态,结果都不可逆。

2、三种状态的表现和变化

(1)状态的变化

promise 主要有以上三种状态, pendingfulfilledrejected 。当返回一个 pending 状态的 promise 时,不会触发 thencatch 。当返回一个 fulfilled 状态时,会触发 then 回调函数。当返回一个 rejected 状态时,会触发 catch 回调函数。那在这几个状态之间,他们是怎么变化的呢?

1)演示1

先来看一段代码。

const p1 = new Promise((resolved, rejected) => {});console.log('p1', p1); //pending

在以上的这段代码中,控制台打印结果如下。

状态变化演示1

在这段代码中, p1 函数里面没有内容可以执行,所以一直在等待状态,因此是 pending

2)演示2

const p2 = new Promise((resolved, rejected) => {setTimeout(() => {resolved();});
});console.log('p2', p2); //pending 一开始打印时
setTimeout(() => console.log('p2-setTimeout', p2)); //fulfilled

在以上的这段代码中,控制台打印结果如下。

状态变化演示2

在这段代码中, p2 一开始打印的是 pending 状态,因为它没有执行到 setTimeout 里面。等到后续执行 setTimeout 时,才会触发到 resolved 函数,触发后返回一个 fulfilled 状态 promise

3)演示3

const p3 = new Promise((resolved, rejected) => {setTimeout(() => {rejected();});
});console.log('p3', p3);
setTimeout(() => console.log('p3-setTimeout', p3)); //rejected

在以上的这段代码中,控制台打印结果如下。

状态变化演示3

在这段代码中, p3 一开始打印的是 pending 状态,因为它没有执行到 setTimeout 里面。等到后续执行 setTimeout 时,同样地,会触发到 rejected 函数,触发后返回一个 rejected 状态的 promise

看完 promise 状态的变化后,相信大家对 promise 的三种状态分别在什么时候触发会有一定的了解。那么我们接下来继续看 promise 状态的表现。

(2)状态的表现

  • pending 状态,不会触发 thencatch
  • fulfilled 状态,会触发后续的 then 回调函数。
  • rejected 状态,会触发后续的 catch 回调函数。

我们来演示一下。

1)演示1

const p1 = Promise.resolve(100); //fulfilled
console.log('p1', p1);
p1.then(data => {console.log('data', data);
}).catch(err => {console.error('err', err);
});

在以上的这段代码中,控制台打印结果如下。

状态的表现演示1

在这段代码中, p1 调用 promise 中的 resolved 回调函数,此时执行时, p1 属于 fulfilled 状态, fulfilled 状态下,只会触发 .then 回调函数,不会触发 .catch ,所以最终打印出 data 100

2)演示2

const p2 = Promise.reject('404'); //rejected
console.log('p2', p2);
p2.then(data => {console.log('data2', data);
}).catch(err => {console.log('err2', err);
})

在以上的这段代码中,控制台打印结果如下。

状态的表现演示2

在这段代码中, p2 调用 promise 中的 reject 回调函数,此时执行时, p1 属于 reject 状态, reject 状态下,只会触发 .catch 回调函数,不会触发 .then ,所以最终打印出 err2 404

对三种状态有了基础了解之后,我们来深入了解 .then.catch 对状态的影响。

3、then和catch对状态的影响(重要)

  • then 正常返回 fulfilled ,里面有报错则返回 rejected
  • catch 正常返回 fulfilled ,里面有报错则返回 rejected

我们先来看第一条规则: then 正常返回 fulfilled ,里面有报错则返回 rejected

1)演示1

const p1 = Promise.resolve().then(() => {return 100;
})
console.log('p1', p1); //fulfilled状态,会触发后续的.then回调
p1.then(() => {console.log('123');
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示1

在这段代码中, p1 调用 promise 中的 resolve 回调函数,此时执行时, p1 正常返回 fulfilled , 不报错,所以最终打印出 123

2)演示2

const p2 = Promise.resolve().then(() => {throw new Error('then error');
});
console.log('p2', p2); //rejected状态,触发后续.catch回调
p2.then(() => {console.log('456');
}).catch(err => {console.error('err404', err);
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示2

在这段代码中, p2 调用 promise 中的 resolve 回调函数,此时执行时, p2 在执行过程中,抛出了一个 Error ,所以,里面有报错则返回 rejected 状态 , 所以最终打印出 err404 Error: then error 的结果。

我们再来看第二条规则catch 正常返回 fulfilled ,里面有报错则返回 rejected

1)演示1(需特别谨慎! !)

const p3 = Promise.reject('my error').catch(err => {console.error(err);
});
console.log('p3', p3); //fulfilled状态,注意!触发后续.then回调
p3.then(() => {console.log(100);
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示3

在这段代码中, p3 调用 promise 中的 rejected 回调函数,此时执行时, p3 在执行过程中,正常返回了一个 Error这个点需要特别谨慎!!这看起来似乎有点违背常理,但对于 promise 来说,不管时调用 resolved 还是 rejected ,只要是正常返回而没有抛出异常,都是返回 fulfilled 状态。所以,最终 p3 的状态是 fulfilled 状态,且因为是 fulfilled 状态,之后还可以继续调用 .then 函数。

2)演示2

const p4 = Promise.reject('my error').catch(err => {throw new Error('catch err');
});
console.log('p4', p4); //rejected状态,触发.catch回调函数
p4.then(() => {console.log(200);
}).catch(() => {console.log('some err');
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示4

在这段代码中, p4 依然调用 promise 中的 reject 回调函数,此时执行时, p4 在执行过程中,抛出了一个 Error ,所以,里面有报错则返回 rejected 状态 , 此时 p4 的状态为 rejected ,之后触发后续的 .catch 回调函数。所以最终打印出 some err 的结果。

4、then和catch的链式调用(常考)

学习完以上知识后,我们通过几道题来再总结回顾一下。

第一题:

Promise.resolve().then(() => {console.log(1);
}).catch(() => {console.log(2);
}).then(() => {console.log(3);
});

这道题打印的是 13 ,因为调用的是 promiseresolve 函数,所以后续不会触发 .catch 函数。

第二题:

Promise.resolve().then(() => {console.log(1);throw new Error('error');
}).catch(() => {console.log(2);
}).then(() => {console.log(3);
});

这道题打印的是 12 ,虽然调用的是 promiseresolve 函数,但是中间抛出了一个异常,所以此时 promise 变为 rejected 状态,所以后续不会触发 .then 函数。

第三题:

Promise.resolve().then(() => {console.log(1);throw new Error('error');
}).catch(() => {console.log(2);
}).catch(() => {  //这里是catchconsole.log(3);
});

这道题打印的是 123 ,跟第二题一样,中间抛出了一个异常,所以此时 promise 变为 rejected 状态,所以后续只触发 .catch 函数。

三、async/await

现代 js 的异步开发,基本上被 asyncawait 给承包和普及了。虽然说 promise 中的 .then.catch 已经很简洁了,但是 async 更简洁,它可以通过写同步代码来执行异步的效果。如此神奇的 asyncawait 究竟是什么呢?让我们一起来一探究竟吧!

1、引例阐述

先用一个例子来展示 promiseasync/await 的区别。假设我们现在要用异步来实现加载图片。

(1) 如果用 promise.then.catch 实现时,代码如下:

function loadImg(src){const picture = new Promise((resolve, reject) => {const img = document.createElement('img');img.onload = () => {resolve(img);}img.onerror = () => {const err = new Error(`图片加载失败 ${src}`);reject(err);}img.src = src;})return picture;
}const url1 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2144980717,2336175712&fm=58';
const url2 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=614367910,2483275034&fm=58';loadImg(url1).then(img1 => {console.log(img1.width);return img1; //普通对象
}).then(img1 => {console.log(img1.height);return loadImg(url2); //promise 实例
}).then(img2 => {console.log(img2.width);return img2;
}).then(img2 => {console.log(img2.height);
}).catch(ex => console.error(ex));

(2) 如果用 async 实现时,代码如下:

function loadImg(src){const picture = new Promise((resolve, reject) => {const img = document.createElement('img');img.onload = () => {resolve(img);}img.onerror = () => {const err = new Error(`图片加载失败 ${src}`);reject(err);}img.src = src;})return picture;
}const url1 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2144980717,2336175712&fm=58';
const url2 = 'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1990552278.jpg';!(async function () {// img1const img1 = await loadImg(url1);console.log(img1.width, img1.height);// img2const img2 = await loadImg(url2);console.log(img2.width, img2.height);
})();

大家可以看到,如果用第二种方式的话,代码要优雅许多。且最关键的是,通过 asyncawait ,用同步代码就可以实现异步的功能。接下来我们开始来了解 asyncawait

2、async和await

  • 背景:解决异步回调问题,防止深陷回调地狱 Callback hell
  • PromisePromise then catch 是链式调用,但也是基于回调函数;
  • async/awaitasync/await同步语法,彻底消灭回调函数,是消灭异步回调的终极武器。

3、async/await和promise的关系

(1) async/awaitpromise 并不互斥,两者相辅相成。

(2) 执行 async 函数,返回的是 promise 对象。

(3) await 相当于 promisethen

(4) try…catch 可以捕获异常,代替了 promisecatch

接下来我们来一一(2)(3)(4)演示这几条规则。

第一条规则: 执行 async 函数,返回的是 promise 对象。

async function fn1(){return 100; //相当于return promise.resolve(100);
}const res1 = fn1(); //执行async函数,返回的是一个Promise对象
console.log('res1', res1); //promise对象
res1.then(data => {console.log('data', data); //100
});

在以上的这段代码中,控制台打印结果如下。

async/await第一条规则

大家可以看到,第一个 res1 返回的是一个 promise 对象,且此时 promise 对象的状态是 fulfilled 状态,所以可以调用后续的 .then 并且打印出 data 100

第二条规则: await 相当于 promisethen

!(async function (){const p1 = Promise.resolve(300);const data = await p1; //await 相当于 promise的thenconsole.log('data', data); //data 300
})();!(async function () {const data1 = await 400; //await Promise.resolve(400)console.log('data1', data1); //data1 400
})();

在以上的这段代码中,控制台打印结果如下。

async/await第二条规则

大家可以看到, p1 调用 resolve 回调函数,所以此时 p1 属于 fulfilled 状态,之后 const data = await p1 中的await,相当于 promisethen ,又因为此时 p1 属于 fulfilled 状态,所以可以对 .then 进行调用,于是输出 data 300 。同理在第二段代码中, await 400 时, 400 即表示 Promise.resolved(400) ,因此属于 fulfilled 状态,随后调用 .then ,打印出 data1 400 结果。

再来看一段代码:

!(async function (){const p2 = Promise.reject('err1');const res = await p4; //await 相当于 promise的thenconsole.log('res', res); //不打印
})();

在以上的这段代码中,控制台打印结果如下。

async/await第三条规则

大家可以看到, p2 调用 reject 回调函数,所以此时 p2 属于 reject 状态。但因为await是触发 promise 中的 .then ,所以此时 res 不会被触发,于是后续不会对await进行操作,控制台也就不对 console.log('res', res); 进行打印。

第三条规则: try…catch 可以捕获异常,代替了 promisecatch

!(async function () {const p3 = Promise.reject('err1'); //rejected 状态try{const res = await p3;console.log(res);}catch(ex){console.error(ex); //try…catch 相当于 promise的catch}
})();

在以上的这段代码中,控制台打印结果如下。

async/await第三条规则

大家可以看到, p3 调用 reject 回调函数,所以此时 p3 属于 rejected 状态,因此它不会执行 try 的内容,而是去执行 catch 的内容, try…catch 中的 catch 就相当于 promise 中的 catch ,且此时 p3 属于 rejected 状态,因此执行 catch ,浏览器捕获到异常,报出错误。

4、异步的本质

从上面的分析中,不管是 promise 还是 async/await ,都是解决异步问题。但是呢,异步的本质还是解决同步的问题,所以,异步的本质是:

  • async/await 是消灭异步回调的终极武器;
  • JS 是单线程的,需要有异步,需要基于 event loop
  • async/await 是一个语法糖,但是这颗糖非常好用!!

我们来看两道 async/await 的顺序问题,回顾 async/await

第一题:

async function async1(){console.log('async start'); // 2await async2();//await 的后面,都可以看做是callback里面的内容,即异步。//类似event loop//Promise.resolve().then(() => console.log('async1 end'))console.log('async1 end'); // 5
}async function async2(){console.log('async2'); //3
}console.log('script start');  // 1
async1();
console.log('script end'); // 4

在以上的这段代码中,控制台打印结果如下。

异步的本质1

从上面这段代码中可以看到,先执行同步代码 1 ,之后执行回调函数 async1() ,在回调函数 async1() 当中,先执行同步代码 2 ,之后遇到 await ,值得注意的是, await 的后面,都可以看作是 callback 里面的内容,即异步内容,所以,先执行 await 中对应的 async2() 里面的内容,之后把 await 后面所有的内容放置到异步当中。继续执行 4 ,等到 4 执行完时,整个同步代码已经执行完,最后,再去执行异步的代码,最终输出 5 的内容。

同样的方式来来分析第二题。

第二题:

async function async1(){console.log('async1 start'); //2await async2();// 下面三行都是异步回调,callback的内容console.log('async1 end'); //5await async3();// 下面一行是回调的内容,相当于异步回调里面再嵌套一个异步回调。console.log('async1 end 2'); //7
}async function async2(){console.log('async2'); //3
}async function async3(){console.log('async3'); //6
}console.log('script start'); //1
async1();
console.log('script end'); //4

在以上的这段代码中,控制台打印结果如下。

异步的本质2

这里就不再进行分析啦!大家可以根据第一个案例的步骤进行分析。

5、场景题

最后的最后,我们再来做两道题回顾我们刚刚讲过的 async/await 知识点。

(1)async/await语法

async function fn(){return 100;
}
(async function(){const a = fn(); //?? Promiseconst b = await fn(); //?? 100
})();
(async function(){console.log('start');const a = await 100;console.log('a', a);const b = await Promise.resolve(200);console.log('b', b);const c = await Promise.reject(300); //出错了,再往后都不会执行了console.log('c', c);console.log('end');
})(); //执行完毕,打印出哪些内容?
//start
//100
//200

(2)async/await的顺序问题

async function async1(){console.log('async1 start'); // 2await async2();//await后面的都作为回调内容 —— 微任务console.log('async1 end'); // 6
}async function async2(){console.log('async2'); // 3
}console.log('script start'); // 1setTimeout(function(){ //宏任务 —— setTimeoutconsole.log('setTimeout'); // 8
}, 0);//遇到函数,立马去执行函数
async1();//初始化promise时,传入的函数会立刻被执行
new Promise(function(resolve){ //promise —— 微任务console.log('promise1'); // 4resolve();
}).then(function(){ //微任务console.log('promise2'); // 7
});console.log('script end'); // 5//同步代码执行完毕(event loop —— call stack 被清空)
//执行微任务
//(尝试触发 DOM 渲染)
// 触发event loop,执行宏任务

这里就不再进行一一解析啦!大家可以前面知识点的学习总计再回顾理解。

四、写在最后

关于 js 的异步问题以及异步的解决方案问题就讲到这里啦!u1s1, promiseasync/await 在我们日常的前端开发中还是蛮重要的,基本上写异步代码时候都会用到 async/await 来解决。啃了16个小时总结了event loop 和 promise 、async/await 问题,希望对大家有帮助。

同时,里面可能有一些讲的不好或者不容易理解的地方也欢迎评论区评论或私信我交流~

关注公众号 星期一研究室 ,不定期分享学习干货~

如果这篇文章对你有用,记得点个赞加个关注哦~

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

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

相关文章

使用 Visual Studio 2019 批量添加代码文件头

应用场景介绍在我们使用一些开源项目时,基本上都会在每个源代码文件的头部看到一段版权声明。一个项目或解决方案中源代码文件的个数少则几十,多则几千甚至更多,那么怎么才能给这么多文件方便地批量添加或者修改一致的文件头呢?在…

7-3 模板题 (10 分)(思路+详解)

一:题目 二:思路 1.读题读不懂,那就分析给出的示例,本题意思就是给出一串数,然后找出找出该元素之后,第一个大于 该元素的下标(这一串数的下标是从一开始的)如果找不到比起大的,那就…

提升对前端的认知,不得不了解Web API的DOM和BOM

了解Web API的DOM和BOM引言正文一、DOM操作1、DOM的本质2、DOM节点操作(1)property形式(2)attribute形式3、DOM结构操作(1)新增/插入节点(2)获取子元素列表,获取父元素&a…

Dapr微服务应用开发系列1:环境配置

题记:上篇Dapr系列文章简要介绍了Dapr,这篇来谈一下开发和运行环境配置本机开发环境配置安装Docker为了方便进行Dapr开发,最好(其实不一定必须)首先在本机(开发机器)上安装Docker。安装方式可以…

leetcode704二分法:(左闭右闭+左闭右开)

前言 又重温了一遍<肖生客的救赎> 其中安迪的一句话一直回荡我的脑中&#xff1a;“人生可以归结为一种简单的选择&#xff1a;不是忙着活&#xff0c;就是忙着死。” 多深刻&#xff0c;多简单&#xff0c;又多令人深省&#xff0c; 哪有那么多选择 哪有那么多时间去花…

你真的理解事件绑定、事件冒泡和事件委托吗?

一文了解Web API中的事件绑定、事件冒泡、事件委托引言正文一、事件绑定1、事件和事件绑定时什么&#xff1f;2、事件是如何实现的&#xff1f;二、事件冒泡1、事件模型2、事件模型解析&#xff08;1&#xff09;捕获阶段&#xff08;2&#xff09;目标阶段&#xff08;3&#…

欢迎来到 C# 9.0(Welcome to C# 9.0)

翻译自 Mads Torgersen 2020年5月20日的博文《Welcome to C# 9.0》&#xff0c;Mads Torgersen 是微软 C# 语言的首席设计师&#xff0c;也是微软 .NET 团队的项目群经理。C# 9.0 正在成形&#xff0c;我想和大家分享一下我们对下一版本语言中添加的一些主要特性的想法。对于 C…

367. 有效的完全平方数(二分法)

一&#xff1a;题目 二:思路 完全平方数:若一个数能表示成某个整数的平方的形式&#xff0c;则称这个数为完全平方数 思路:1.我们将num先折半,因为它是某个整数的平方&#xff0c;而这个数的范围肯定不会超过num的一半 2.那么这就相当于在[left,num/2]中查找某个数&#xff0c…

译 | Azure 应用服务中的程序崩溃监控

点击上方蓝字关注“汪宇杰博客”原文&#xff1a;Yun Jung Choi, Puneet Gupta翻译&#xff1a;汪宇杰应用程序崩溃经常发生。崩溃是指代码中的异常未得到处理并终止进程。这些未处理的异常也称为二次机会异常&#xff08;second chance exceptions&#xff09;。当您的应用程序…

使用Seq搭建免费的日志服务

Seq简介Seq是老外开发的一个针对.NET平台非常友好的日志服务。支持容器部署&#xff0c;提供一个单用户免费的开发版本。官网&#xff1a;https://datalust.co/seq使用文档&#xff1a;https://docs.datalust.co/docsSeq主体功能如下所示&#xff1a;支持主流的编程语言&#x…

leetcode27:移除元素(暴力+双指针)

一&#xff1a;题目 二&#xff1a;暴力双指针 1&#xff1a;暴力解法 (1):思路 1.在数组当中 我们想要删除一个元素 得靠覆盖也就是后面的元素往前覆盖其想要删除的元素 但是注意的是我们真实的数组中的元素个数是不变的 因为我们只是将后面的元素移到起前面 并未真正的删除…

三分钟Docker-推送本地镜像到仓库

在上篇文章中&#xff0c;我们完成了应用程序容器化&#xff0c;把webapi项目构建镜像并容器化运行。本文将会演示如何把自己构建的镜像上传到docker官网的仓库和自己私有仓库本地镜像推送到官网的registry1.创建仓库点击Docker Desktop图标->Repositories-》create 跳转到…

你知道304吗?图解强缓存和协商缓存

http协议—常见状态码&#xff0c;请求方法&#xff0c;http头部&#xff0c;http缓存一、http状态码1、引例阐述2、状态码分类3、常见状态码4、关于协议和规范二、http 方法1、传统的methods2、现在的methods3、Restful API&#xff08;1&#xff09;Restful API是什么&#x…

leetcode844. 比较含退格的字符串(栈+双指针)

一:题目 二:思路代码 1:利用栈 (1):思路 1.利用栈 我们将字符串中的单个元素都入栈 当遇到’#的时候将将栈顶元素弹出 (2):上码&#xff08;方法一&#xff09; class Solution { public:/**思路:1.利用栈 我们将字符串中的单个元素都入栈 当遇到#的时候将将栈顶元素弹出*…

efcore技巧贴-也许有你不知道的使用技巧

前言.net 环境近些年也算是稳步发展。在开发的过程中&#xff0c;与数据库打交道是必不可少的。早期的开发者都是DbHelper一撸到底&#xff0c;到现在的各种各样的ORM框架大行其道。孰优孰劣谁也说不清楚&#xff0c;文无第一武无第二说的就是这个理。没有什么最好的&#xff0…

关于前端性能优化问题,认识网页加载过程和防抖节流

前端性能优化—网页加载过程、性能优化方法、防抖和节流一、网页加载过程1、加载资源的形式2、加载资源的过程3、渲染页面的过程4、关于window.onload 和 DOMContentLoaded二、性能优化1、性能优化原则2、性能优化的方法3、让加载更快4、让渲染更快三、防抖和节流1、防抖 debou…

javax.net.ssl.SSLHandshakeException: No appropriate protocol

一:报错 二:解决 找到jdk 1.8安装目录&#xff0c;找到C:\Program Files\Java\jre里面的lib\security 下面有个java.security将jdk.tls.disabledAlgorithms后面的SSLv3, TLSv1, TLSv1.1都删除掉.&#xff08;大概位置是在700多行&#xff09; 三:上方并未解决的 我的jdk是这…

『软件工程9』结构化系统分析——解决软件“做什么”问题

结构化系统分析——解决软件“做什么”问题一、系统分析的任务和过程1、系统分析的任务2、系统分析的过程&#xff08;1&#xff09;问题识别&#xff08;2&#xff09;分析与综合&#xff08;3&#xff09;编制文档&#xff08;4&#xff09;系统分析评审二、结构化分析方法1、…

.NET5.0 Preview 8 开箱教程

.NET5.0 Preview 8 开箱教程前言首先&#xff0c;看到 .NET5.0 Preview 8 发布后&#xff0c;作为一枚基层应用开发人员&#xff0c;很想要体验一下新版本的魅力&#xff1b;这可能就是程序员对新技术的一种执着吧。其实从官方宣布 .NETCore 将更名为 .NET5 开始&#xff0c;我…

leetcode977. 有序数组的平方(暴力+双指针)

一:题目 二:暴力双指针 1:暴力 class Solution { public:vector<int> sortedSquares(vector<int>& nums) {vector<int> v;for(int num : nums){int temp pow(num,2);v.push_back(temp);} sort(v.begin(),v.end());return v;} };2:双指针 思路:1.利…