[精讲]promise对象常用方法,与手写模拟

本文详细介绍了Promise对象的常用方法,包括then(),catch(),finally(),race(),all(),allSettled()以及静态方法resolve()和all()。同时,解释了Promise如何处理异步操作以及它们在宏任务和微任务中的执行顺序。此外,还提供了手写Promise.race()和all()方法的示例。
摘要由CSDN通过智能技术生成
promise对象常用方法
1、then() 方法

then() 方法会返回一个新的 Promise 对象,该对象会在前一个 Promise 对象执行成功后被异步解析。

promise.then(onFulfilled, onRejected)

其中,onFulfilledonRejected 都是回调函数。onFulfilled 在 Promise 对象被解析时被调用,onRejected 在 Promise 对象被拒绝时被调用。

例如,以下是一个使用 then() 方法的简单示例:

const promise=newPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello, world!');
  }, 1000);
});
​
promise.then((value) => {
  console.log(value);
}).catch((error) => {
  console.error(error);
});
2、catch() 方法

catch() 方法也会返回一个新的 Promise 对象,该对象会在前一个 Promise 对象执行失败后被异步解析。

promise.catch(onRejected)

其中,onRejected 是一个回调函数,在 Promise 对象被拒绝时被调用。

例如,以下是一个使用 catch() 方法的简单示例:

const promise=newPromise((resolve, reject) => {
  setTimeout(() => {
    reject(newError('An error occurred!'));
  }, 1000);
});
​
promise.catch((error) => {
  console.error(error);
});
3、finally() 方法

finally() 方法也会返回一个新的 Promise 对象,在前一个 Promise 对象被解析或拒绝后都会被异步解析。

promise.finally(onFinally)

其中,onFinally 是一个回调函数,在 Promise 对象被解析或拒绝时被调用。

例如,以下是一个使用 finally() 方法的简单示例:

const promise=newPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello, world!');
  }, 1000);
});
​
promise.finally(() => {
  console.log('The promise has been resolved!');
});
4、race()

Promise.race() 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会立即解决,并将该解决值或拒绝原因返回给后续处理程序。

Promise.race(iterable);

参数:

  • iterable:可迭代对象,如 Array。

返回值:

  • 一个 Promise 实例,该实例在迭代器中的某个 Promise 解决或拒绝后立即解决,将该解决值或拒绝原因返回给后续处理程序。

代码示例:

const promise1=newPromise((resolve, reject) =>setTimeout(resolve, 100, 'resolved in 100ms'));
const promise2=newPromise((resolve, reject) =>setTimeout(resolve, 200, 'resolved in 200ms'));
​
Promise.race([promise1, promise2])
  .then(result=>console.log(result));
// Output: 'resolved in 100ms'
手写Promise.race()方法
Promise.writtenrace=function(arr){
    returnnewPromise((resolve,reject)=>{
        if(!arr)returnresolve([])
        for(letvalofarr){
            Promise.resolve(val).then((data)=>{
                resolve(data)
            }).catch(err=>{
                reject(err)
            })
        }
    })
}
5、allSettled()

Promise.allSettled() 方法返回一个 promise,该 promise 在所有给定的 promise 已经完成或者拒绝后被解决。返回的 promise 在所有 promise 解决后解决,无论其解决方式是“成功”还是“失败”,并带有一个对象数组,每个对象表示对应的 promise 结果。

语法:

Promise.allSettled(iterable);

参数:

  • iterable:可迭代对象,如 Array。

返回值:

  • 一个 Promise 实例,该实例在所有给定的 promise 完成或拒绝后解决。解决时,将返回一个对象数组,每个对象都表示一个 promise 结果。如果 promise 数组为空,则返回解决的 Promise 实例将立即完成。

代码示例:

const promise1=Promise.resolve(3);
const promise2=newPromise((resolve, reject) =>setTimeout(reject, 100, 'reject'));
const promise3=newPromise((resolve, reject) =>setTimeout(resolve, 200, 'resolved'));
​
Promise.allSettled([promise1, promise2, promise3])
  .then(results=>console.log(results));
// Output: [
//  { status: "fulfilled", value: 3 },
//  { status: "rejected", reason: "reject" },
//  { status: "fulfilled", value: "resolved" }
// ]
6、resolve()

Promise.resolve 是 JavaScript 中的一个静态方法,它返回一个已经 resolve 的 Promise 对象。该方法的语法如下:

Promise.resolve(value)

其中,value 表示 Promise 对象 resolve 后的值,它可以是任意类型的数据,包括基本数据类型、对象、数组、函数等。

例如,下面的代码使用 Promise.resolve 返回一个已经 resolve 的 Promise 对象:

letpromise=Promise.resolve(1);
promise.then(value=> {
  console.log(value); // 1
});

上面的代码输出 1,说明 Promise 对象已经 resolve,并且返回了 resolve 后的数据。

如果传入的参数是一个 Promise 对象,则 Promise.resolve 方法会返回该 Promise 对象。

letpromise=Promise.resolve(Promise.resolve(1));
promise.then(value=> {
  console.log(value); // 1
});

上面的代码输出 1,说明 Promise 对象已经 resolve,并且返回了 resolve 后的数据。

7、all()方法

Promise.all 是 JavaScript 中的一个静态方法,它接收一个 Promise 对象数组作为参数,并返回一个 Promise 实例。该方法的语法如下:

Promise.all(iterable)

其中,iterable 表示一个 Promise 对象数组或可迭代对象,如数组、字符串等。

当所有的 Promise 对象都 resolve 时,Promise.all 返回的 Promise 实例 resolve,并且返回一个包含所有 Promise resolve 后的数据的数组。如果有任意一个 Promise 对象 reject,则 Promise.all 返回的 Promise 实例 reject,并且返回 reject 的原因。

例如,下面的代码使用 Promise.all 等待多个 Promise 对象都 resolve:

letp1=Promise.resolve(1);
letp2=Promise.resolve(2);
letp3=Promise.resolve(3);
​
Promise.all([p1, p2, p3]).then(values=> {
  console.log(values); // [1, 2, 3]
});

上面的代码输出 [1, 2, 3],说明所有的 Promise 对象都 resolve,且返回的数组包含了所有 Promise resolve 后的数据。

手写all方法
Promise.writeAll=function (arr) {
    // 创建一个 Promise 实例
    returnnewPromise((resolve, reject) => {
        // 如果数组长度为 0,则直接 resolve 一个空数组
        if (!arr.length) { resolve([]) } 
        else {
            // 记录已经 resolve 的 Promise 数量
            letokNum=0
            // 待处理promise数量
            letlen=arr.length
            // 用来存储每个 Promise resolve 后的数据
            letresArr= []
            // 遍历将处理结果保存起来
            for (leti=0; i<len; i++) {
                Promise.resolve(arr[i]).then((data) => {
                    // 每当一个 Promise resolve,okNum 加 1
                    okNum++
                    // 将该 Promise resolve 后的数据存储到 resArr 数组中
                    resArr[i] =data
                    // 当所有 Promise 都 resolve 后,resolve resArr 数组
                    if (okNum==len) {
                        resolve(resArr)
                    }
                }).catch((err) => {
                    // 如果有一个 Promise reject,则整个 Promise 都 reject
                    reject(err)
                })
            }
        }
    })
}
letarr= []
for(leti=0;i<3;i++){
    leta=newPromise((resolve)=>{
        setTimeout(resolve(i),(i+1)*1000)
    })
    arr.push(a)
}
​
letres=Promise.writeAll(arr)
console.log(res);   // Promise{<pending>}
setTimeout(()=>console.log(res),8000)   //Promise{[0,1,2]}
~/nodejs$ node app1.js
Promise { <pending> }
Promise { [ 0, 1, 2 ] }

宏任务与微任务

在 JavaScript 中,任务可以分为两类:宏任务(macro-task)和微任务(micro-task)。

宏任务是由浏览器发起的任务,如 DOM 渲染、用户交互事件、定时器等。当一个宏任务执行完成后,才会去检查是否存在微任务,如果存在,则会依次执行微任务队列中的任务,直到微任务队列为空。当微任务队列为空时,才会执行下一个宏任务。

微任务则是由 JavaScript 引擎发起的任务,如 Promise 回调、MutationObserver 等。当一个微任务加入到微任务队列后,只有当 JavaScript 引擎当前的执行栈为空时,才会执行微任务队列中的任务。这意味着,当一个宏任务中包含了多个微任务时,这些微任务会在该宏任务执行完成后被依次执行,而不是在该宏任务中立即执行。

因此,Promise 既是宏任务,也是微任务。当我们调用 Promise 的 then 方法时,它会将回调函数作为微任务添加到微任务队列中,等待 JavaScript 引擎当前的执行栈为空时执行。

以下是一个示例,展示了 Promise 的 then 方法作为微任务的执行顺序:

console.log('start');
​
setTimeout(() => {
  console.log('setTimeout');
}, 0);
​
Promise.resolve().then(() => {
  console.log('promise');
});
​
console.log('end');

在上述代码中,setTimeout 方法作为宏任务被添加到任务队列中,而 Promise 的 then 方法中的回调函数被添加到微任务队列中。因此,控制台的输出结果如下:

start
end
promise
setTimeout

可以看到,微任务队列中的 Promise 回调函数先被执行,而宏任务队列中的 setTimeout 回调函数则在 Promise 回调函数执行完成后被执行。

js手写模拟

手写模拟学习 [手写 Promise?看这一篇就够了 - 知乎 (zhihu.com)] (https://zhuanlan.zhihu.com/p/431677536) 这位大佬的文章,想要进一步深入学习请查阅。

classPromise {
  constructor(executor) {
    // 定义Promise的三种状态
    constPENDING='pending';
    constFULFILLED='fulfilled';
    constREJECTED='rejected';
​
    // 初始状态为pending
    this.status=PENDING;
    // 保存成功的结果
    this.value=undefined;
    // 保存失败的原因
    this.reason=undefined;
    // 保存成功回调的数组
    this.onFulfilledCallbacks= [];
    // 保存失败回调的数组
    this.onRejectedCallbacks= [];
​
    // resolve函数
    constresolve= (value) => {
      // 只有在pending状态下才能改变状态
      if (this.status===PENDING) {
        this.status=FULFILLED;
        this.value=value;
        // 依次执行保存的成功回调函数
        this.onFulfilledCallbacks.forEach((callback) =>callback(this.value));
      }
    };
​
    // reject函数
    constreject= (reason) => {
      // 只有在pending状态下才能改变状态
      if (this.status===PENDING) {
        this.status=REJECTED;
        this.reason=reason;
        // 依次执行保存的失败回调函数
        this.onRejectedCallbacks.forEach((callback) =>callback(this.reason));
      }
    };
​
    // 执行executor函数
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
​
  // then方法
  then(onFulfilled, onRejected) {
    // onFulfilled 或 onRejected 不是函数时,考虑到在原生Promise 中,promise.then().then(res => console.log(res)) 这段代码里,如果 .then() 括号中什么都不写的话,在后面的 then 中依旧是可以拿到前面传过来的参数。
    if(typeofonFulfilled!=='function') onFulfilled=value=>value
    if(typeofonRejected!=='function') onRejected=reason=> {throwreason}
    // 创建新的Promise对象
    constnewPromise=newPromise((resolve, reject) => {
      // 当前状态为fulfilled,执行成功回调函数
      if (this.status==='fulfilled') {
        try {
          // 执行成功回调函数,并将结果传递给下一个Promise
          resolve(onFulfilled(this.value));
        } catch (error) {
          reject(error);
        }
      }
      // 当前状态为rejected,执行失败回调函数
      elseif (this.status==='rejected') {
        try {
          // 执行失败回调函数,并将结果传递给下一个Promise
          resolve(onRejected(this.reason));
        } catch (error) {
          reject(error);
        }
      }
      // 当前状态为pending,保存回调函数
      else {
        this.onFulfilledCallbacks.push((value) => {
          try {
            // 执行成功回调函数,并将结果传递给下一个Promise
            resolve(onFulfilled(value));
          } catch (error) {
            reject(error);
          }
        });
​
        this.onRejectedCallbacks.push((reason) => {
          try {
            // 执行失败回调函数,并将结果传递给下一个Promise
            resolve(onRejected(reason));
          } catch (error) {
            reject(error);
          }
        });
      }
    });
​
    // 返回新的Promise对象
    returnnewPromise;
  }
}
  1. Promise 类包含一个 constructor 构造函数和一个 then 方法。

  1. 在 constructor 构造函数中,定义了 Promise 的三种状态:PENDING(进行中)、FULFILLED(已成功)、REJECTED(已失败),以及 Promise 对象的属性,包括状态、成功结果、失败原因、保存成功回调函数的数组和保存失败回调函数的数组。

  1. 在 constructor 构造函数中,定义了 resolve 和 reject 两个函数,用来改变 Promise 对象的状态,并依次执行保存的成功回调函数和失败回调函数。

  1. 在 constructor 构造函数中,调用 executor 函数,并在 try...catch 块中执行 resolve 或 reject 函数,以改变 Promise 对象的状态。

  1. 在 then 方法中,创建一个新的 Promise 对象 newPromise,并根据当前 Promise 对象的状态来执行成功回调函数或失败回调函数,或者保存回调函数。然后将 newPromise 返回。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学不会只能哭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值