文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript怎么实现手写promise

2023-07-06 01:25

关注

这篇文章主要介绍了JavaScript怎么实现手写promise的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript怎么实现手写promise文章都会有所收获,下面我们一起来看看吧。

需求

我们先来总结一下 promise 的特性:

使用:

const p1 = new Promise((resolve, reject) => {  console.log('1');  resolve('成功了');})console.log("2");const p2 = p1.then(data => {  console.log('3')  throw new Error('失败了')})const p3 = p2.then(data => {  console.log('success', data)}, err => {  console.log('4', err)})

JavaScript怎么实现手写promise

JavaScript怎么实现手写promise

以上的示例可以看出 promise 的一些特点,也就是我们本次要做的事情:

// 三个状态:PENDING、FULFILLED、REJECTEDconst PENDING = "PENDING";const FULFILLED = "FULFILLED";const REJECTED = "REJECTED";class Promise {  constructor(executor) {    // 默认状态为 PENDING    this.status = PENDING;    // 存放成功状态的值,默认为 undefined    this.value = undefined;    // 存放失败状态的值,默认为 undefined    this.reason = undefined;    // 调用此方法就是成功    let resolve = (value) => {      // 状态为 PENDING 时才可以更新状态,防止 executor 中调用了两次 resovle/reject 方法      if (this.status === PENDING) {        this.status = FULFILLED;        this.value = value;      }    };    // 调用此方法就是失败    let reject = (reason) => {      // 状态为 PENDING 时才可以更新状态,防止 executor 中调用了两次 resovle/reject 方法      if (this.status === PENDING) {        this.status = REJECTED;        this.reason = reason;      }    };    try {      // 立即执行,将 resolve 和 reject 函数传给使用者      executor(resolve, reject);    } catch (error) {      // 发生异常时执行失败逻辑      reject(error);    }  }  // 包含一个 then 方法,并接收两个参数 onFulfilled、onRejected  then(onFulfilled, onRejected) {    if (this.status === FULFILLED) {      onFulfilled(this.value);    }    if (this.status === REJECTED) {      onRejected(this.reason);    }  }}

调用一下:

const promise = new Promise((resolve, reject) => {  resolve('成功');}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

JavaScript怎么实现手写promise

这个时候我们很开心,但是别开心的太早,promise 是为了处理异步任务的,我们来试试异步任务好不好使:

const promise = new Promise((resolve, reject) => {  // 传入一个异步操作  setTimeout(() => {    resolve('成功');  },1000);}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

发现没有任何输出,我们来分析一下为什么:

new Promise 执行的时候,这时候异步任务开始了,接下来直接执行 .then 函数,then函数里的状态目前还是 padding,所以就什么也没执行。

那么我们想想应该怎么改呢?

我们想要做的就是,当异步函数执行完后,也就是触发 resolve 的时候,再去触发 .then 函数执行并把 resolve 的参数传给 then。

这就是典型的发布订阅的模式,可以看我这篇文章。

const PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';class Promise {  constructor(executor) {    this.status = PENDING;    this.value = undefined;    this.reason = undefined;    // 存放成功的回调    this.onResolvedCallbacks = [];    // 存放失败的回调    this.onRejectedCallbacks= [];    let resolve = (value) => {      if(this.status ===  PENDING) {        this.status = FULFILLED;        this.value = value;        // 依次将对应的函数执行        this.onResolvedCallbacks.forEach(fn=>fn());      }    }     let reject = (reason) => {      if(this.status ===  PENDING) {        this.status = REJECTED;        this.reason = reason;        // 依次将对应的函数执行        this.onRejectedCallbacks.forEach(fn=>fn());      }    }    try {      executor(resolve,reject)    } catch (error) {      reject(error)    }  }  then(onFulfilled, onRejected) {    if (this.status === FULFILLED) {      onFulfilled(this.value)    }    if (this.status === REJECTED) {      onRejected(this.reason)    }    if (this.status === PENDING) {      // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行      this.onResolvedCallbacks.push(() => {        onFulfilled(this.value)      });      // 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行      this.onRejectedCallbacks.push(()=> {        onRejected(this.reason);      })    }  }}

这下再进行测试:

const promise = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('成功');  },1000);}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

1s 后输出了:

JavaScript怎么实现手写promise

说明成功啦

then的链式调用

这里就不分析细节了,大体思路就是每次 .then 的时候重新创建一个 promise 对象并返回 promise,这样下一个 then 就能拿到前一个 then 返回的 promise 了。

const PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';const resolvePromise = (promise2, x, resolve, reject) => {  // 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise  Promise/A+ 2.3.1  if (promise2 === x) {     return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))  }  // Promise/A+ 2.3.3.3.3 只能调用一次  let called;  // 后续的条件要严格判断 保证代码能和别的库一起使用  if ((typeof x === 'object' && x != null) || typeof x === 'function') {     try {      // 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候)  Promise/A+ 2.3.3.1      let then = x.then;      if (typeof then === 'function') {         // 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty  Promise/A+ 2.3.3.3        then.call(x, y => { // 根据 promise 的状态决定是成功还是失败          if (called) return;          called = true;          // 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1          resolvePromise(promise2, y, resolve, reject);         }, r => {          // 只要失败就失败 Promise/A+ 2.3.3.3.2          if (called) return;          called = true;          reject(r);        });      } else {        // 如果 x.then 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.3.4        resolve(x);      }    } catch (e) {      // Promise/A+ 2.3.3.2      if (called) return;      called = true;      reject(e)    }  } else {    // 如果 x 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.4      resolve(x)  }}class Promise {  constructor(executor) {    this.status = PENDING;    this.value = undefined;    this.reason = undefined;    this.onResolvedCallbacks = [];    this.onRejectedCallbacks= [];    let resolve = (value) => {      if(this.status ===  PENDING) {        this.status = FULFILLED;        this.value = value;        this.onResolvedCallbacks.forEach(fn=>fn());      }    }     let reject = (reason) => {      if(this.status ===  PENDING) {        this.status = REJECTED;        this.reason = reason;        this.onRejectedCallbacks.forEach(fn=>fn());      }    }    try {      executor(resolve,reject)    } catch (error) {      reject(error)    }  }  then(onFulfilled, onRejected) {    //解决 onFufilled,onRejected 没有传值的问题    //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;    //因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后 then 的 resolve 中捕获    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };    // 每次调用 then 都返回一个新的 promise  Promise/A+ 2.2.7    let promise2 = new Promise((resolve, reject) => {      if (this.status === FULFILLED) {        //Promise/A+ 2.2.2        //Promise/A+ 2.2.4 --- setTimeout        setTimeout(() => {          try {            //Promise/A+ 2.2.7.1            let x = onFulfilled(this.value);            // x可能是一个proimise            resolvePromise(promise2, x, resolve, reject);          } catch (e) {            //Promise/A+ 2.2.7.2            reject(e)          }        }, 0);      }      if (this.status === REJECTED) {        //Promise/A+ 2.2.3        setTimeout(() => {          try {            let x = onRejected(this.reason);            resolvePromise(promise2, x, resolve, reject);          } catch (e) {            reject(e)          }        }, 0);      }      if (this.status === PENDING) {        this.onResolvedCallbacks.push(() => {          setTimeout(() => {            try {              let x = onFulfilled(this.value);              resolvePromise(promise2, x, resolve, reject);            } catch (e) {              reject(e)            }          }, 0);        });        this.onRejectedCallbacks.push(()=> {          setTimeout(() => {            try {              let x = onRejected(this.reason);              resolvePromise(promise2, x, resolve, reject)            } catch (e) {              reject(e)            }          }, 0);        });      }    });    return promise2;  }}

Promise.all

核心就是有一个失败则失败,全成功才进行 resolve

Promise.all = function(values) {  if (!Array.isArray(values)) {    const type = typeof values;    return new TypeError(`TypeError: ${type} ${values} is not iterable`)  }  return new Promise((resolve, reject) => {    let resultArr = [];    let orderIndex = 0;    const processResultByKey = (value, index) => {      resultArr[index] = value;      if (++orderIndex === values.length) {          resolve(resultArr)      }    }    for (let i = 0; i < values.length; i++) {      let value = values[i];      if (value && typeof value.then === 'function') {        value.then((value) => {          processResultByKey(value, i);        }, reject);      } else {        processResultByKey(value, i);      }    }  });}

关于“JavaScript怎么实现手写promise”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“JavaScript怎么实现手写promise”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯