【Js】js学习字典

一、promise

Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

promise.all()该方法用于将多个Promise实例,包装成一个新的Promise实例。

var p=Promise.all([p1,p2,p3]);

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

关于promise.all()的使用及说明

比如当数组里的P1,P2都执行完成时,页面才显示。 值得注意的是,返回的数组结果顺序不会改变,即使P2的返回要比P1的返回快,顺序依然是P1, P2
Promise.all成功返回成功数组,失败返回失败数据,一但失败就不会继续往下走
Promise.all可以将多个Promise实例包装成一个新的Promise实例。

同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

关键代码:将所有异步操作存储到数组pros中,Promise.all(pros)执行所有异步操作

let pros = []
data.forEach(element => {
    pros.push( this.getJsonFile(element.json,element.fileName) )
});
Promise.all(pros).then(val => {
    this.fontsList = [...val]
})

示例:

// 获取字体所有json文件展示
getIconFonts(isFresh) {
    req.post(window.context.uc+`/system/file/v1/queryIconFiles`).then(rep => {
        if(rep && rep.data) {
            // 将所有异步操作存储到数组pros中
            let pros = []
            data.forEach(element => {
                pros.push( this.getJsonFile(element.json,element.fileName) )
            });
            // 执行所有异步操作后处理数据
            Promise.all(pros).then(val => {
                this.fontsList = [...val]
                this.uploadFonts = [...this.fontsList]
            })
        }
    });
},
// 通过id获取json文件
getJsonFile(fileId, fileName) {
    return new Promise((resolve, reject) => {
        req.get(window.context.uc +'/system/file/v1/preview?fileId=' + fileId).then(rep => {
            if(rep && rep.data) {
                let data = {
                    fileName,
                    ...rep.data
                }
                // 返回处理后的数据
                resolve(data)
            }
        })
    })
}

Promise.all实现限制并发请求函数

Promise.all 的简单解释

// 当以下数组中promise1, promise2, promise3都resolve之后,触发promise.all的then函数。
Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

需求解释

所谓并发请求,即有待请求接口100个,限制每次只能发出10个。即同一时刻最多有10个正在发送的请求。

每当10个之中有一个请求完成,则从待请求的接口中再取出一个发出。保证当前并发度仍旧为10。

直至最终请求完成。

设计思路

简单思路如下:(假设并发请求函数名字为limitedRequest)

· 设定一个数组(命名为:pool),用于后续Promise.all的使用
· 当limitedRequest被调用的时候,首先一次性发出10个请求,并放入到pool中
· 每一个请求完成后的回调函数中继续触发下一个请求,而下一个请求返回Promise,他的回调函数继续绑定同样的回调函数,即循环调用。(看不懂就直接看代码更易懂)
· 直到全部请求完成,停止。

代码实现

具体代码如下

// 模仿一个fetch的异步函数,返回promise
function mockFetch(param) {
  return new Promise((resovle) => {
    setTimeout(() => {
      resovle(param);
    }, 2000);
  });
}

function limitedRequest(urls, maxNum) {
  const pool = [];
  // 处理maxNum比urls.length 还要大的情况。
  const initSize = Math.min(urls.length, maxNum);
  for (let i = 0; i < initSize; i++) {
      // 一次性放入初始的个数
    pool.push(run(urls.splice(0, 1)));
  }
  // r 代表promise完成的resolve回调函数
  // r 函数无论什么样的结果都返回promise,来确保最终promise.all可以正确执行
  function r() {
    console.log('当前并发度:', pool.length);
    if (urls.length === 0) {
      console.log('并发请求已经全部发起');
      return Promise.resolve();
    }
    return run(urls.splice(0, 1));
  }
  // 调用一次请求
  function run(url) {
    return mockFetch(url).then(r);
  }
  // 全部请求完成的回调
  Promise.all(pool).then(() => {
    console.log('请求已经全部结束');
  });
}
// 函数调用
limitedRequest([1, 2, 3, 4, 5, 6, 7, 8], 3);
let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})
 
let p2 = new Promise((resolve, reject) => {
  resolve('success')
})
 
let p3 = Promse.reject('失败')
 
Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})
 
Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})
let wake = (time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time / 1000}秒后醒来`)
    }, time)
  })
}
 
let p1 = wake(3000)
let p2 = wake(2000)
 
Promise.all([p1, p2]).then((result) => {
  console.log(result)       // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
  console.log(error)
})
 
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和
Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果
获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,
偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,
使用Promise.all毫无疑问可以解决这个问题。
注意:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,
并不会触发Promise.all()的catch方法。
 
示例代码:
 
const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);
 
const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
 
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));// ["hello", Error: 报错了]
 
p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个
新的 Promise 实例,p2指向的实际上是这个实例。
该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实
例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
 
而如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。如下:
 
const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result);
 
const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result);
 
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));// Error: 报错了

最终返回结果
$ node .\src\views\doc\detail\index.js
当前并发度: 3
当前并发度: 3
当前并发度: 3
当前并发度: 3
当前并发度: 3
当前并发度: 3
并发请求已经全部发起
当前并发度: 3
并发请求已经全部发起
当前并发度: 3
并发请求已经全部发起
请求已经全部结束

promise.race( )

Promise.race是赛跑的意思,也就是说Promise.race([p1, p2, p3])里面的结果哪个获取的快,就返回哪个结果,不管结果本身是成功还是失败

使用场景: Promise.all和Promise.race都是有使用场景的。 有些时候我们做一个操作可能得同时需要不同的接口返回的数据,这时我们就可以使用Promise.all; 有时我们比如说有好几个服务器的好几个接口都提供同样的服务,我们不知道哪个接口更快,就可以使用Promise.race,哪个接口的数据先回来我们就用哪个接口的数据

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  },1000)
})
 
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('failed')
  }, 500)
})
 
Promise.race([p1, p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)  // 打开的是 'failed'
})

下面来看几个简洁易懂的例子:

1.await 可以获得多个promise 的返回结果

2. Promise.all 返回的也是promise,所以可以直接await Promise.all();

1. 使用Promise

function fn(){
    return new Promise((resolve,reject)=>{
        let randomNum = parseInt(Math.random()*6+1);
        console.log(randomNum);
        if(randomNum>3){
            resolve('买'); 
        }
        else{
            reject('不买');
        }
    })
}
Promise.all([fn(),fn()]).then(
  (x)=>{console.log(x,'success')},(y)=>{console.log(y,'error');
});

Promise.all 里面参数为一个数组,数组的每一项是一个返回promise 的函数调用then 的第一个参数是所有promise都成功的调用,返回结果是一个数组,数组的每一项为函数promise 的返回结果。then 的第二个参数:返回结果有一个失败则执行失败的回调,拿到的是第一个失败的值

2. 使用await

await 是可以获得多个promise 返回结果的,Promise.all()返回的也是promise结果。所以想要使用await 拿到多个promise的返回值,可以直接await Promise.all();

function fn(){
    return new Promise((resolve,reject)=>{
        let randomNum = parseInt(Math.random()*6+1);
        console.log(randomNum);
        if(randomNum>3){
            resolve('买'); 
        }
        else{
            reject('不买');
        }
    })
}
async function test(){
    try{
    let res = await Promise.all([fn(),fn()]);
    console.log(res,'success');
    }
    catch(error){
        console.log(error,'error');
    }
}
test();

Promise.all([fn(),fn()]) 都返回resolve(); 才能够拿到成功的返回值Promise.all([fn(),fn()]) 有一个返回reject(), 则进入catch(error), 拿到失败的返回值

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值