10分钟原生实现promise、all、allSettled函数

本文深入讲解Promise的基础概念及高级用法,包括异常处理、原生实现、并行和串行控制等。通过具体实例帮助读者掌握Promise的工作原理,并提供实际应用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. promise的异常捕获

  • 如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误
  • then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获
  • 如果Promise状态已经变成resolved,再抛出错误是无效的。promise状态只能变一次
  • 如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
  • 『冒泡』:会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
  • catch()返回一个promise对象,后面可以继续跟then()方法

2. 原生实现promise

特性:

  1. new Promise接受一个函数executor
    executor参数为resolvereject
    resolve可以将promise对象的状态变为成功状态
    reject可以将promise对象的状态变为失败状态
  2. promise对象的then方法来注册成功状态或者失败状态要执行的函数
  3. then可以链式调用,then方法返回promise对象,状态取决于上一个promise的对象的状态
  4. resolve可以接受一个简单值也可以接受一个promise对象,当传入的是一个promise对象时,只有当该对象成功或失败,resolve才会成功
  5. then中成功或失败执行的函数的返回值
  • 有简单类型返回值,作为then方法返回的promise对象的成功状态的值
  • 当返回一个thenable对象(带有then方法的对象)的时候,只有是成功状态才能执行下一个then

使用ES6的面向对象方式

class MyPromise {
  constructor(executor) {
    this.initValue()
    this.initBind()
    try {
      executor(this.resolve, this.reject)
    }
    catch(err) {
      this.reject(err)
    }
  }
  initValue() {
    this.PromiseState = 'pending'
    this.PromiseResult = undefined
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
  }
  initBind() {
    // resolve函数的this永远指向MyPromise实例
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }
  resolve(value) {
    if (this.PromiseState !== 'pending') return
    this.PromiseState = 'fulfilled'
    this.PromiseResult = value
    while(this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.PromiseResult)
    }
  }
  reject(value) {
    if (this.PromiseState !== 'pending') return
    this.PromiseState = 'rejected'
    this.PromiseResult = value
    while(this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.PromiseResult)
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = onFulfilled instanceof Function ? onFulfilled : value => value
    onRejected = onRejected instanceof Function ? onRejected : error => { throw(error) }

    // 链式调用,必须返回一个promise
    return new MyPromise((resolve, reject) => {
      setTimeout(() => {
        const resolvePromise = (cb) => {
          try {
            // 当前的promise状态取决于上一个方法的执行结果(也就是onFulfilled和onRejected的执行结果)
            const result = cb(this.PromiseResult)
            // 如果onFulfilled函数返回一个promise,那么需要看then之后的结果
            if (result instanceof MyPromise) {
              result.then(resolve, reject)
            } 
            // 如果onFulfilled函数返回一个普通数据,那么直接resolve置为成功
            else {
              resolve(result)
            }
          }
          catch(error) {
            reject(error)
            throw new Error(err)
          }
        }
        if (this.PromiseState === 'fulfilled') {
          resolvePromise(onFulfilled)
        }
        else if (this.PromiseState === 'rejected') {
          resolvePromise(onRejected)
        }
        else if (this.PromiseState === 'pending') {
          this.onFulfilledCallbacks.push(onFulfilled.bind(this))
          this.onRejectedCallbacks.push(onRejected.bind(this))
        }
      })
    })
  }
}

3. promise.all()

接受一个数组,且数组中每一项都是promise的实例,该函数返回值也是一个promise的实例,当数组中所有的项都fulfilled才会执行then(),否则只要有一个rejected,那么该状态就会变为rejected
原生实现

function myPromiseAll(iterable) {
    return new Promise((resolve,reject) => {
        const promises = Array.from(iterable);
        // 定义Promise对象resolve的数组
        const result = [];
        // 定义一个计数器用来判断是否所有的promise执行完毕
        let count = 0;
        // 并发执行每一个promise
        for (let i = 0; i < promises.length; i++) {
            Promise.resolve(promises[i]).then(res => {
                result[i] = res;
                count++;
                if (count === promises.length) {
                    resolve(result);
                }
            }).catch(err => reject(err))
        }
    })
}
var p1=Promise.resolve(1),
    p2=Promise.resolve(2),
    p3=Promise.resolve(3);
 
 myPromiseAll([p1,p2,p3]).then(function(value){
 	console.log(value)
 
 })

4. promise.race()

接收值和返回值和promise.all()完全一样。
只要有一个状态改变,不管是fulfilled还是rejected,该状态都会随着改变。

function myPromiseRace(promises) {
	return new Promise((resolve, reject) => {
	     promises.forEach(promise => {
	         if (promise instanceof MyPromise) {
	             promise.then(res => {
	                 resolve(res)
	             }, err => {
	                 reject(err)
	             })
	         } else {
	             resolve(promise)
	         }
	     })
	 })
}

5. promise.allSettled()

接收一个Promise数组,数组中如有非Promise项,则此项当做成功
把每一个Promise的结果,集合成数组,返回

Promise.myAllSettled = function(promises) {
  return new Promise(function(resolve) {
    const results = [];
    let resolvedCount = 0;
    const count = promises.length;
    promises.forEach((curPro, index) => {
        Promise.resolve(curPro).then(
        (data) => {
        resolvedCount++;
        results[index] = {
          status: "fullfilled",
          value: data,
        };
      },
      (reason) => {
        resolvedCount++;
        results[index] = {
          status: "rejected",
          reason,
        };
      })
      .finally(() => {
        if (resolvedCount >= count) {
          resolve(results);
        }
      });
    })
  })
}

6. promise.any

接收一个Promise数组,数组中如有非Promise项,则此项当做成功
如果有一个Promise成功,则返回这个成功结果
如果所有Promise都失败,则报错

function myPromiseAny(promises) {
	return new Promise((resolve, reject) => {
            let count = 0
            promises.forEach((promise) => {
                promise.then(val => {
                    resolve(val)
                }, err => {
                    count++
                    if (count === promises.length) {
                        reject(new AggregateError('All promises were rejected'))
                    }
                })
            })
        })
    }
}

7. 实际运用题

  1. 封装一个request,当失败时可以进行重试,可以设置重试次数和间隔时间,promise.retry()
function request(options, retryTimes = 3, time = 3000) {
  return new Promise((resolve, reject) => {
    const retry = function(resolve, reject){
      fetch(options).then(() => {
        resolve();
      }).catch(() => {
        retryTimes--;
        if (retryTimes >= 0) {
          setTimeout(() => {
            retry(resolve, reject);
          }, time)
        }
        else reject();
      })
    }
    retry(resolve, reject);
  });
}
request('https://example.com/api/data', 3, 1000)
  .then(response => {
    console.log('成功了')
  })
  .catch(error => {
    console.log('失败!!')
  });

8. async await实现promise.all()

async function myPromiseAll(arr) {
  let arr1 = [];
  try {
    for (let i = 0; i < arr.length; i++) {
      let h = await arr[i]
      arr1.push(h)
    }
  } catch (err) {
  }
  return arr1
}

myPromiseAll().then(res => {
  console.log(res);
});
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值