专栏首页前端小码农简单实现一个Promise

简单实现一个Promise

理解一些基础概念

原型链,类,实例, 类属性,类方法, 实例属性,实例方法

class A {
    static b = '1'
    static classMethod() {
        return 'hello'
    }
}
const a = new A();
a.c = 5;
a.sayHello = function() {
    console.log('welcome')
}

A: 类

b: 类属性

classMethod: 类方法

a: 实例

a.c: 实例属性

ES6的类

static:静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

实现一个promise

Promise简介

要想自己实现一个Promise,我们首先要对Promise的用法有所了解;

Promise.resolve的特点:

  • 1.参数是一个 Promise 实例, 那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
  • 2.如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

Promise.all的特点:

  • 1.Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
  • 2.返回值组成一个数组

Promise.race的特点:

  • 1.Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
  • 2.返回那个率先改变的 Promise 实例的返回值

代码实现

class Promise {
    constructor(fn) {
        /**
         *  三种状态 
         *  pending:进行中
         *  fulfilled:已成功
         *  rejected: 已失败
         */
        this.status = 'pending';
        this.resoveList = []; // 成功后回调函数
        this.rejectList = []; // 失败后的回调函数

        fn(this.resolve.bind(this), this.reject.bind(this));
    }
    then(scb, fcb) {
        if (scb) {
            this.resoveList.push(scb);
        }
        if(fcb) {
            this.rejectList.push(fcb);
        }
        return this;
    }
    catch(cb) {
        if (cb) {
            this.rejectList.push(cb);
        }
        return this;
    }
    resolve(data) {
        if (this.status !== 'pending') return;
        this.status = 'fulfilled';
        setTimeout(() => {
            this.resoveList.forEach(s => {
                data = s(data);
            })
        })
    }
    reject(err) {
        if (this.status !== 'pending') return;
        this.status = 'rejected';
        setTimeout(() => {
            this.rejectList.forEach(f => {
                err = f(err);
            })
        })
    }
    /**
     * 实现Promise.resolve
     * 1.参数是一个 Promise 实例, 那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
     * 2.如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
    */ 
    static resolve(data) {
        if (data instanceof Promise) {
            return data;
        } else {
            return new Promise((resolve, reject) => {
                resolve(data);
            })
        }
    }
    // 实现Promise.reject
    static reject(err) {
        if (err instanceof Promise) {
            return err;
        } else {
            return new Promise((resolve, reject) => {
                reject(err);
            })
        }
    }
    /**
     * 实现Promise.all
     * 1. Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
     * 2. 返回值组成一个数组
    */
    static all(promises) {
        return new Promise((resolve, reject) => {
            let promiseCount = 0;
            let promisesLength = promises.length;
            let result = [];
            for(let i = 0; i < promises.length; i++) {
                // promises[i]可能不是Promise类型,可能不存在then方法,中间如果出错,直接返回错误
                Promise.resolve(promises[i])
                    .then(res => {
                        promiseCount++;
                        // 注意这是赋值应该用下标去赋值而不是用push,因为毕竟是异步的,哪个promise先完成还不一定
                        result[i] = res;
                        if(promiseCount === promisesLength) {
                        return resolve(result);
                        }
                    },(err) => {
                        return reject(err);
                    }
                )
            }
        })
    }
    /**
     * 实现Promise.race
     * 1. Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
     * 2. 返回那个率先改变的 Promise 实例的返回值
    */
    static race(promises) {
        return new Promise((resolve, reject) => {
            for(let i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i])
                    .then(res => {
                        return resolve(res);
                    },(err) =>{
                        return reject(err);
                    }
                )
            }
        })
    }
}

测试用例

1. Promise.then

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('resolve');
        resolve(222);
    }, 1000)
})

p.then(data => {
    setTimeout(() => {
        console.log('data', data);
    })
    return 3333;
}).then(data2 => {
    console.log('data2', data2);
}).catch(err => {
    console.error('err', err);
});

2. Promise.reject

const p1 = Promise.reject('出错了');
p1.then(null, function (s) {
    console.log(s); // 出错了
});

3. Promise.all && Promise.race

const q1 = new Promise((resolve, reject) => {
    resolve('hello')
});

const q2 = new Promise((resolve, reject) => {
    resolve('world')
});
Promise.all([q1, q2]).then(res => {
    console.log(res); // [ 'hello', 'world' ]
});
Promise.race([q1, q2]).then(res => {
    console.log(res); // hello
});

本文分享自微信公众号 - 牧码的星星(gh_0d71d9e8b1c3),作者:木子星兮i

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • async原理解析

    把上面代码的Generator函数 foo 可以写成 async 函数,就是这样:

    木子星兮
  • typeof和instanceof原理

    这里的类型值是值,变量是没有类型的,变量可以随时持有任何类型的值。JavaScript中变量是“弱类型”的,一个变量可以现在被赋值为 字符串类型,随后又被赋值为...

    木子星兮
  • 深入理解JavaScript 执行上下文

    只有理解了执行上下文,才能更好地理解 JavaScript 语言本身,比如变量提升,作用域,闭包等

    木子星兮
  • 《深入浅出Node.js》:Node异步编程解决方案 之 ES6 Promise

    在上一篇讲了异步编程解决方案之一的事件发布-订阅模式,使用事件模式时,执行流程需要被预先设定。即便是分支,也需要预先设定,这是由发布-订阅模式的运行机制决定的。...

    前端_AWhile
  • 你真的懂Promise吗

    在异步编程中,Promise 扮演了举足轻重的角色,比传统的解决方案(回调函数和事件)更合理和更强大。可能有些小伙伴会有这样的疑问:2020年了,怎么还在谈论P...

    浪里行舟
  • Promise的三兄弟:all(), race()以及allSettled()

    从ES6 开始,我们大都使用的是 Promise.all()和Promise.race(),Promise.allSettled() 提案已经到第4阶段,因此将...

    Fundebug
  • Salesforce Javascript(一) Promise 浅谈

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects...

    用户1169343
  • 你不知道的JavaScript(中卷)二

    1.最常见的块单位是函数。从现在到将来的“等待”,最简单的方法(但绝不是唯一的,甚至也不是最好的)是使用一个通常称为回调函数的函数

    硬核项目经理
  • web前端面试题对答篇一:谈谈你对Promise的理解

    回答这个问题时,个人不建议单纯的从Promise的细节知识点答起,因为这个问题的本质是拥有一定宏观性的,如果仅仅回复一些知识点恐怕是满足不了面试官胃口的。

    用户1272076
  • es6 Promise

    Promise 是异步编程的一种方案,简单说就是一个容器,里面保存着某个未来才会结束的事件的 结果,Promise 是一个对象,从它,可以获取异步操作的消息。 ...

    用户1197315

扫码关注云+社区

领取腾讯云代金券