开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
promise的API:race、all、allSettled、any
笔者为了方便自己记忆,把这些方法大概抽离出了一个框架,这样子,写的时候,只需根据API的特性,向其中填入代码。
Promise.base = function (arr) {
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
arr[i].then(resolve, reject)
}
})
}
Promise.race
定义:只要
p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
Promise.race = function (arr) {
console.log('race')
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
arr[i].then(resolve, reject)
}
})
}
Promise.all
定义:
p
的状态由p1
、p2
、p3
决定,分成两种情况。(1)只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。(2)只要
p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
思路:
- all 在 resolve 状态下需要返回成功的数组,因此我们需要定义 result 变量
- 当数组遍历结束,则可以返回数组
Promise.all = function (arr) {
console.log('all')
return new Promise((resolve, reject) => {
let result = []
let count = 0
for (let i = 0; i < arr.length; i++) {
arr[i].then(data => {
result[i] = data
if (++count === arr.length) {
resolve(result)
}
}, err => {
reject(err)
})
}
})
}
Promise.allSettled
定义:
Promise.allSettled()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled
还是rejected
,包装实例才会结束。
思路:
- 需要返回一个数组
- 对于传入的数据,每一个都去处理相对应的状态
Promise.allSettled = function (arr) {
console.log('allSettled')
return new Promise((resolve, reject) => {
let result = []
let count = arr.length
for (let i = 0; i < arr.length; i++) {
arr[i].then((data) => {
result[i] = {
status: 'fufilled',
value: data
}
}, (err) => {
result[i] = {
status: 'rejected',
value: err
}
}).finally(() => {
if (!--count) {
resolve(result)
}
})
}
})
}
Promise.any()
Promise.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
思路:
- 当数据中有resolve的时候,我们之间 reslove 出去
- 全部 reject 的时候,才会调用 reject,因为需要 count 计数器来判断
Promise.any = function (arr) {
console.log('any')
return new Promise((resolve, reject) => {
let count = arr.length
for (let i = 0; i < arr.length; i++) {
arr[i].then((data) => {
resolve(data)
}, (err) => {
if (!--count) {
reject(new AggregateError(err))
}
})
}
})
}
原生的 ajax 封装成 promise
思路:需要实现的是链式调用,因此函数需要返回 Promise。当请求成功时,调用 resolve,将数据返回。
function ajax(method, url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 304) {
resolve(xhr.response)
}
}
}
xhr.send()
})
}
ajax('get', 'https://api.github.com/users/suiboyu').then(res => {
console.log(res)
})
实现一个同时允许任务数量最大为 n 的函数
思路:
- 写出基本框架
- 什么时候返回,当 finish 等于数组的长度,即完成所有的任务,就可以调用 resolve。
- 当有一个任务执行的时候,start 加一。任务执行完成,则 start 减一。
- 重复执行 run 函数。
function limitRunTask(tasks, n) {
return new Promise((resolve, reject) => {
let finish = 0, result = [], start = 0, index = 0
function run() {
if (finish === tasks.length) {
resolve(result)
return
}
while (start < n && index < tasks.length) {
start++
let current = index
tasks[index++]().then(v => {
start--
finish++
result[current] = v
run()
})
}
}
run()
})
}