# Promise对象
# 什么是promise
promise是异步编程的一种解决方案,解决了回调地狱的问题
从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以使用同样的方法进行处理,它的强大之处还在于它的链式调用。
# promise特点
- 状态不受外界影响
- 状态一旦确定就不再改变
# promise缺点
- 无法取消执行
- 不设置回调函数,promise内部抛出的错误就无法返回外部
- 当状态处于pending时,无法知道当前处于什么阶段(刚开始还是已结束)
# API
# 手写promise
# promise.then
then 必须返回一个promise。也是因为这个规范,所以 promise 支持「链式调用」。
# 题目
# 使用Promise实现每隔1秒输出1,2,3
let arr = [1, 2, 3]
functin sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
function run() {
for (let i = 0; i < arr.length; i++) {
await sleep(1000)
console.log(i)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 限制异步操作的并发个数并尽可能快的完成全部
- 题目 有8个图片资源的url,已经存储在数组urls中。
urls类似于['https://image1.png', 'https://image2.png', ....]
而且已经有一个函数function loadImg,输入一个url链接,返回一个Promise,该Promise在图片下载完成的时候resolve,下载失败则reject。
但有一个要求,任何时刻同时下载的链接数量不可以超过3个。
请写一段代码实现这个需求,要求尽可能快速地将所有图片下载完成。
const urls = ['url1', 'url2', 'url3', 'url4', ...]
function loadImg(url) {
return new Promise((resolve, reject) =>{
const img = new Image()
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject('图片加载失败')
}
img.src = url
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 解决方案 用 Promise.race来实现,先并发请求3个图片资源,这样可以得到 3 个 Promise实例,组成一个数组promises ,然后不断的调用 Promise.race 来返回最快改变状态的 Promise,然后从数组(promises )中删掉这个 Promise 对象实例,再加入一个新的 Promise实例,直到全部的 url 被取完
function handle(urls, loadImg, num) {
let data = [].concat(urls)
let promiseArr = []
promiseArr = data.splice(0, num).map((i, index) => {
return loadImg(i).then(() => {
return index
})
})
(function loop() {
let p = Promise.resolve(promiseArr)
for(let i = 0; i < data.length; i++) {
p = p.then((index) => {
promiseArr[index] = loadImg(data[i]).then(() => {
return index
})
return Promise.resolve(promiseArr)
})
}
})()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21