Promise
是什么
Promise 是 JS 中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
从语法上来说: Promise 是一个构造函数
从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值
状态
pending
resolved/fulfilled
rejected
无论变为成功还是失败, 都会有一个结果数据
成功的结果数据一般称为 value, 失败的结果数据一般称为 reason
流程
优势
指定回调函数更加灵活,原先需要在异步任务前指定。如今异步任务在new时写入,成功/失败回调在then中绑定
支持链式调用,解决回调地狱问题
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
const promise=new Promise(function(resolve,reject){ if(操作是否成功){ resolve(value) }else{ reject(error) } })
promise.then(function(value){ },function(error){ })
|
实现一个简易的Promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| const a = new Promise((resolve, rejct) => { if ('成功') { resolve(value) } else { reject(error) } }) a.then((value) => { console.log(value) }, (error) => { throw new Error(error) })
const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected"
class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined this.resolveCallbacks = [] this.rejectCallbacks = []
const resolve = (value) => { if (this.status === PENDING) { this.status = FULFILLED this.value = value this.resolveCallbacks.forEach(fn => fn()) } } const reject = (reason) => { if (this.status === PENDING) { this.status = REJECTED this.reason = reason this.rejectCallbacks.forEach(fn => fn()) } }
try { executor(resolve, reject) } catch(e) { reject(e) } }
then(onFulfilled, onRejected) { if (this.status === FULFILLED) { onFulfilled(this.value) } if (this.status === REJECTED) { onRejected(this.reason) } if (this.status === PENDING) { this.resolveCallbacks.push(() => { onFulfilled(this.value) }) this.rejectCallbacks.push(() => { onRejected(this.reason) }) } } }
|
手写API
静态方法
Promise.all(iterable)
这个方法返回一个新的 promise 对象,等到所有的 promise 对象都成功或有任意一个 promise 失败。
如果所有的 promise 都成功了,它会把一个包含 iterable 里所有 promise 返回值的数组作为成功回调的返回值。顺序跟 iterable 的顺序保持一致。
一旦有任意一个 iterable 里面的 promise 对象失败则立即以该 promise 对象失败的理由来拒绝这个新的 promise。
Promise.allSettled(iterable)
等到所有 promise 都已敲定(每个 promise 都已兑现或已拒绝)。
返回一个 promise,该 promise 在所有 promise 都敲定后完成,并兑现一个对象数组,其中的对象对应每个 promise 的结果。
Promise.any(iterable)
接收一个 promise 对象的集合,当其中的任意一个 promise 成功,就返回那个成功的 promise 的值。
Promise.race(iterable)
等到任意一个 promise 的状态变为已敲定。
当 iterable 参数里的任意一个子 promise 成功或失败后,父 promise 马上也会用子 promise 的成功返回值或失败详情作为参数调用父 promise 绑定的相应处理函数,并返回该 promise 对象。
Promise.reject(reason)
返回一个状态为已拒绝的 Promise
对象,并将给定的失败信息传递给对应的处理函数。
Promise.resolve(value)
返回一个状态由给定 value 决定的 Promise
对象。如果该值是 thenable(即,带有 then
方法的对象),返回的Promise 对象的最终状态由 then 方法执行结果决定;否则,返回的 Promise 对象状态为已兑现,并且将该 value 传递给对应的 then 方法。
通常而言,如果你不知道一个值是否是 promise 对象,使用 Promise.resolve(value)
来返回一个 Promise 对象,这样就能将该 value 以 promise 对象形式使用。
实例方法
Promise.prototype.catch()
为 promise 添加一个被拒绝状态的回调函数,并返回一个新的 promise,若回调函数被调用,则兑现其返回值,否则兑现原来的 promise 兑现的值。
Promise.prototype.then()
为 promise 添加被兑现和被拒绝状态的回调函数,其以回调函数的返回值兑现 promise。若不处理已兑现或者已拒绝状态(例如,onFulfilled
或 onRejected
不是一个函数),则返回 promise 被敲定时的值。
Promise.prototype.finally()
为 promise 添加一个回调函数,并返回一个新的 promise。这个新的 promise 将在原 promise 被兑现时兑现。而传入的回调函数将在原 promise 被敲定(无论被兑现还是被拒绝)时被调用。
Promise.all
- Promise.all()接受一个promise的iterable类型
- 只有数组中全部的 Promise 都变为 resolve 的时候,返回一个成果结果的数组(按参数内的promise顺序排列,而不是promise完成的顺序)
- 只要有一个失败,状态就变成 rejected,将失败的那个结果给失败状态的回调函数
- 数组为空时会返回[]
使用例子
1 2 3 4 5 6 7 8 9 10 11 12 13
| const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); });
Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); }, (error) => { throw new Error(error) });
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Promise.all = (promises) => { let promises = Array.from(promises) return new Promise((resolve, reject) => { const n = promises.length if (n === 0) resolve([]) else { let results = [] let index = 0 let processData = (value, i) => { results[i] = value if (++index === n) resolve(results) } for (let i = 0; i < n; i++) { const curPromise = promises[i] if (curPromise instanceof Promise) { curPromise.then( data => processData(data, i), err => reject(err) ) } else { processData(curPromise, i) } } } }) }
|
Promise.race
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
数组为空时什么都不会返回
使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one'); });
const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two'); });
Promise.race([promise1, promise2]).then((value) => { console.log(value); });
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| promise.prototype.race = (promiseArray) => { promiseArray = Array.from(promiseArray) return new Promise((resolve, reject) => { const n = promiseArray.length for (let i = 0; i < n; i++) { const curPromise = promiseArray[i] if (curPromise instanceof Promise) { curPromise.then( (value) => resolve(value), (error) => reject(error) ) } else { resolve(curPromise) } } }) }
|
Promise.allSettled
Promise.allSettled() 可用于并行执行独立的异步操作,并收集这些操作的结果。
该函数接受一个 promise 数组(通常是一个可迭代对象)作为参数:
1
| const statusesPromise = Promise.allSettled(promises);
|
当所有的输入 promises
都被 fulfilled
或 rejected
时,statusesPromise
会解析为一个具有它们状态的数组
{ status: 'fulfilled', value: value }
— 如果对应的 promise 已经 fulfilled
- 或者
{status: 'rejected', reason: reason}
如果相应的 promise 已经被 rejected
使用
1 2 3 4 5 6 7 8 9 10
| const promise1 = Promise.resolve(3); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo')); const promises = [promise1, promise2];
Promise.allSettled(promises). then((results) => results.forEach((result) => console.log(result.status)));
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| promise.promise.allSettled = (promiseArray) => { promiseArray = Array.from(promiseArray) return new Promise((resolve, reject) => { const n = promiseArray.length const results = [] for (let i = 0; i < n; i++) { const curPromise = promiseArray[i] let index = 0 const addData = (status, d, i) => { let tmpObj if (status === 'fulfilled') { tmpObj = { status: status, value: d } } else if (status === 'rejected') { tmpObj = { status: status, reason: d, } } results[i] = tmpObj if (++index === n) resolve(res) } if (curPromise instanceof Promise) { curPromise.then( (value) => addData('fulfilled', value, i), (reason) => addData('rejected', reason, i) ) } else { addData('fulfilled', curPromise, i) } } }) }
|
Promise.any
- 如果有一个Promise成功,则返回这个成功结果
- 如果所有Promise都失败,则报错
使用
1 2 3 4 5 6 7 8 9 10
| const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); });
Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); });
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Promise.prototype.any = (promiseArray) => { promiseArray = Array.from(promiseArray) return new Promise((resolve, reject) => { const n = promiseArray.length if (n === 0) reject([]) let count = 0 for (let i = 0; i < n; i++) { const curPromise = promiseArray[i] if (curPromise instanceof Promise) { curPromise.then((value) => { resolve(value) }, (error) => { count++ if (count === n) { reject(new Error('All promises were rejected')) } }) } else { resolve(curPromise) } } }) }
|
Promise 控制并发数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| async function asyncPool(promiseArray, limit) { promiseArray = Array.from(promiseArray) const res = [] const executing = [] const n = promises.length for (promise of promises) { const p = Promise.resolve(promise) res.push(p) if (limit < n) { const e = p.then(() => executing.splice(executing.indexOf(e), 1)) executing.push(e) if (executing.length >= limit) { await Promise.race(executing) } } } return Promise.all(res) }
(async () => { const res = await asyncPool([promise1, promise2, promise3, promise4], 2); console.log(res); })();
|