异步请求的进化史
1. Promise常考题
概念:状态机,pending => 通过函数resolve转变为resolved;pending => 通过函数reject转变为rejected;
用法:a: p = new Promise((resolve,reject)=>{}); p.then((data)=>{},(error)=>{});// then第二个参数是捕获异常的 等价于.catch((error)=>{}) (如果同时存在,then里面的catch优先捕获到错误,实践结论)
b: 是实例用.then()的
c: Promise.all([p1,p2,p3]).then()// 全部返回成功才行;而且无论实例p1、p2、p3谁执行的快慢,最后的返回都是固定顺序p1、p2、p3的结果,数组形式[202106美团一面,耻辱啊]
d: Promise.race([]).then()// 只要一个返回成功就行;返回最先执行成功的那个
总结:Promise只是包装控制了异步程序流程,http请求还是xmlhttprequest
1.1 手写Promise实现原理
1.2 Promise.all()
2. async...await
概括:async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await,仅此而已。
优点:内置执行器;更好的语义;更广的适用性;
2.1 捕获异常
await func().catch((error)=>{}) // 因为await返回的是一个Promise对象
3. 手写题:JS按顺序执行多个异步函数
核心:利用Promise的resolve的特性
点击查看代码
let newarr = [
(done) => {
setTimeout(() => {
console.log('1')
done();
}, 3000)
},
(done) => {
setTimeout(() => {
console.log('2')
done();
}, 2000)
},
(done) => {
setTimeout(() => {
console.log('3');
done();
}, 1000);
}
]
// 实现功能函数,让数组中的函数,顺序执行
// 参链:[js按顺序执行多个异步函数] https://www.cnblogs.com/zhaoyongblog/p/12869497.html
// 能让异步代码保持顺序的,只有Promise的resolve函数,别的根本控制不住
async function mySort(arr = []){
if(Object.prototype.toString.call(arr) !== '[object Array]'){
return new Error('非数组类型,请检查输入~');
}
let arrList = [];
for(let item of arr){
let p = function(){
return new Promise((resolve)=>{
item(resolve);
});
}
arrList.push(p);
}
// console.log(arrList);
// // 方法一:
// let run = function(){
// if(!arrList.length) return;
// let fun = arrList.shift();// 每次返回的都是一个新的Promise对象
// fun().then(()=>{
// run();
// });
// }
// // 方法二:
// // let run = function(i){
// // if(i>=arrList.length) return;
// // let fun = arrList[i];
// // fun().then(()=>{
// // i++;
// // console.log('i',i);
// // run(i);
// // });
// // }
// run(0);
// 方法三:await 后面必须是个Promise对象?
// 官链:[await MDN] https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await
// 1. [返回值] = await [表达式]
// 2. await操作符后面跟一个Promise对象,只能在async函数中使用;如果不是一个Promise对象,将直接返回表达式(原来什么样就是什么样)
// 3. 表达式的resolve的值将作为返回值
// 官链:[async MDN] https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function
// 1. async函数是AsyncFunction构造函数的实例,是基于Promise的一种更简洁的写法,而不必刻意的使用链式调用。
// 2. 返回一个Promise,不管函数体里面是不是显式的返回了Promise
while(arrList.length){
await arrList.shift()();
}
}
mySort(newarr);
点击查看代码
const request = createRequestPool(3);
for (let i = 0; i < 5; i++) {
request('https://e.juejin.cn/extension/banner').then((res)=>{
console.log(res);
}).catch((error)=>{
console.log(error);
})
}
/**
* 记笔记,待验证
*/
function createRequestPool(poolSize) {
const reqs = [];
const temps = [];
return function (url) {
function runTask() {
// 循环添加到临时数组中
while (reqs.length && temps.length < poolSize) {
temps.push(reqs.shift());
}
// 遍历临时数组,发起请求
for (let i = 0; i < temps.length; i++) {
fetch(temps[i].url)
.then((data) => {
console.log('索引 then:',i);
// 移除当前请求,并返回结果
temps[i].resolve(data);
temps.splice(temps.indexOf(temps[i]), 1);
// 每完成一个,就需要执行队列中的任务
runTask();
})
.catch((err) => {
console.log('索引 catch:',i);
// 移除当前请求,并返回结果
temps[i].reject(err);
temps.splice(temps.indexOf(temps[i]), 1);
});
}
}
return new Promise((resolve, reject) => {
reqs.push({
url,
resolve,
reject
});
runTask();
});
}
}
5. 实现Promise.all
点击查看代码
// 参数是个数组,非数组,返回错误信息
// 数组里面有一个报错就结束全部请求,一切正常的话,返回一个数组(依据索引)来对应参数的顺序
// 返回的是一个Promise对象
Promise.myPromiseAll = function (arr = []){
if(Object.prototype.toString().call(arr) !== '[object Array]'){
return new Promise((resolve,reject)=>{
reject(new Error('参数非数组,请检查入参~'));
});
}
let count = 0;// 循环计数
let resultValue = [];// 结果存储
return new Promise((resolve,reject)=>{
for(let i = 0;i < arr.length;i++){
let curr = arr[i];
let currPromise = curr.then ? curr : Promise.resolve(curr);
currPromise.then((res)=>{
console.log(res);
resultValue[i] = res;
if(count == arr.length){
resolve(resultValue);
}
count++;
},(error)=>{
console.log(error);
reject(error);
});
}
});
}
6. 剥洋葱模型:
题目:
点击查看代码
let middleware = []
middleware.push((next) => {
console.log(1)
next()
console.log(1.1)
})
middleware.push((next) => {
console.log(2)
next()
console.log(2.1)
})
middleware.push((next) => {
console.log(3)
next()
console.log(3.1)
})
let fn = compose(middleware);
fn()
// 实现使得输出为1 2 3 3.1 2.1 1.1
function compose() {
}
题解一:利用函数的嵌套
点击查看代码
function compose(middleware) {
return function (){
dispatch(0);
function dispatch(i){
let fn = middleware[i];
if(!fn) return null;
fn(function next(){
dispatch(i+1);
});
}
}
}
let fn = compose(middleware);
fn();
题解二:支持异步和传参
点击查看代码
function compose(middleware){
return async function(){
await dispatch(0);
async function dispatch(i){
let fn = middleware[i];
if(!fn) return null;
await fn(function next(){
dispatch(i+1);
})
}
}
}
题解三:使用Promise,如何晋升为leader[技术过硬,懂业务,敢于做决策]
点击查看代码
function compose(middleware){
return function (...args){
dispatch(0);
function dispatch(i){
return new Promise((resolve)=>{
let fn = middleware[i];
if(!fn) resolve(null);
resolve(fn(function next(){
dispatch(i+1);
},...args));
});
}
}
}
参链:洋葱模型JS实现
参考链接:
async 函数的含义和用法 [阮一峰]
反思总结:
1. 每学一遍知识点,要有悟的过程和悟的结论,战胜懒惰,追求极致。20210618
2. 当前如果知识点晦涩难懂,也许是讲述的问题,换个文章去看,也许会对自己的思路。

浙公网安备 33010602011771号