• 周六. 4月 20th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

写一个Promise实现

admin

11月 28, 2021

promise

​ promise是ES6中新增的异步编程解决方案, 在代码中的表现是一个对象。通过Promise就可以实现用同步的流程来表示异步的操作,通过Promise就可以避免回调函数层层嵌套(回调地狱)问题。

new Promise(function(resolve, reject){});
// promise对象不是异步的, 只要创建promise对象就会立即执行存放的代码
// promise对象是通过状态的改变来实现通过同步的流程来表示异步的操作的, 只要状态发生改变就会自动触发对应的函数

状态

pending:   默认状态,只要没有告诉promise任务是成功还是失败就是pending状态
fulfilled(resolved): 只要调用resolve函数, 状态就会变为fulfilled, 表示操作成功
rejected:  只要调用rejected函数, 状态就会变为rejected, 表示操作失败
注意点: 状态一旦改变既不可逆, 既从pending变为fulfilled, 那么永远都是fulfilled; 既从pending变为rejected, 那么永远都是rejected

监听Promise状态改变,resolved –> then();rejected –> catch()

then方法

1. 在修改promise状态时, 可以传递参数给then方法中的回调函数.
2. 同一个promise对象可以多次调用then方法,当该promise对象的状态发生改变时所有then方法都会被执行.
3. then方法每次执行完毕后会返回一个新的promise对象.
4. 可以通过上一个promise对象的then方法给下一个promise对象的then方法传递参数.无论是在上一个promise对象成功的回调还是失败的回调传递的参数,都会传递给下一个promise对象成功的回调.
5. 如果then方法返回的是一个Promise对象, 那么会将返回的Promise对象的执行结果中的值传递给下一个then方法
let promise = new Promise(function (resolve, reject) {
    // resolve("111"); // 将状态修改为成功
    reject("aaa"); // 将状态修改为失败
});
let ppp = new Promise(function (resolve, reject) {
    resolve("222"); // 将状态修改为成功
    // reject("bbb"); // 将状态修改为失败
});
let p2 = promise.then(function (data) {
    console.log("成功1", data);
    return ppp;
}, function (data) {
    console.log("失败1", data);
    return "bbb";
});
p2.then(function (data) {
    console.log("成功2", data);
}, function (data) {
    console.log("失败2", data);
});
// 失败1 aaa
// 成功2 bbb

catch方法

catch 其实是 then(undefined, () => {}) 的语法糖

1.  如果需要分开监听, 也就是通过then监听成功通过catch监听失败, 那么必须使用链式编程, 否则会报错.
不使用链式编程的原因是, 如果promise的状态是失败, 但是没有对应失败的监听就会报错;then方法会返回一个新的promise, 新的promise会继承原有promise的状态,如果新的promise状态是失败, 但是没有对应失败的监听也会报错.

all静态方法

1. all方法接收一个数组.
2. 如果数组中有多个Promise对象, 只有都成功才会执行then方法, 并且会按照添加的顺序, 将所有成功的结果重新打包到一个数组中返回给我们.
3. 如果数组中不是Promise对象, 那么会直接执行then方法.
let p1 = new MyPromise(function (resolve, reject) {
    // resolve("111");
    reject("aaa");
});
let p2 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("222");
    }, 5000);
});
let p3 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("333");
    }, 3000);
});

let pp = MyPromise.all([p1, p2, p3]);
/* MyPromise 实现在下面
p1.then 执行then方法会直接走到if(this.status === REJECTED)方法里面,执行失败回调函数,结果:
    then REJECTED ƒ (error) {console.log('失败回调函数', error)}
    失败回调函数 aaa
执行.catch 方法,再次执行catch 方法里传入的失败回调,结果:
    then REJECTED ƒ (e) {
                        console.log('try 捕获异常')
                        reject(e);
                    }
    try 捕获异常
*/

race方法

1. all方法接收一个数组,
2. 如果数组中有多个Promise对象, 谁先返回状态就听谁的, 后返回的会被抛弃
3. 如果数组中不是Promise对象, 那么会直接执行then方法
MyPromise.race([p1, p2, p3]).then(function (value) {
    console.log("成功", value);
}).catch(function (e) {
    console.log("失败", e);
});

手写Promise

1.Promise特点
    1.1. 创建时必须传入一个函数, 否则会报错
    1.2. 传入的函数形参需要两个回调函数
    1.3. 刚创建的Promise对象状态是pending
    1.4. 状态一旦发生改变就不可再次改变
    1.5. 可以通过then来监听状态的改变
        1.5.1. 如果添加监听时状态已经改变, 立即执行监听的回调
        1.5.2. 如果添加监听时状态还未改变, 那么状态改变时候再执行监听回调
        1.5.3. 同一个Promise对象可以添加多个then监听, 状态改变时所有的监听按照添加顺序执行
2.
    2.1. then方法每次执行完毕都会返回一个新的Promise对象
    2.2. 上一个Promise对象的then可以给下一个Promise的then传递数据
        2.2.1. 无论上一个是在成功的回调还是失败的回调传递的参数都会传递给下一个成功的回调
        2.2.2. 如果上一个传递的是Promise对象, 那么传给下一个的成功还是失败由传递的Promise状态决定
3.
    3.1. then方法返回的Promise对象的状态和前一个Promise的状态默认相同
    3.2. 后一个Promise对象的then可以捕获前一个Promise then的异常
    3.3. catch方法就是then方法的语法糖 then(undefined, function(){});
// 1.
let promise = new Promise(function (resolve, reject) {
    resolve();
    // reject();
});
promise.then(function (data) {
    console.log("成功1", data);
}, function (data) {
    console.log("失败1", data);
});

// 2.
let promise = new MyPromise(function (resolve, reject) {
    resolve("111");
    // reject("aaa");
});
let ppp = new MyPromise(function (resolve, reject) {
    // resolve("222");
    reject("bbb");
});
let p2 = promise.then(function (data) {
    console.log("成功1", data);
    return "222"; // p2.then返回 成功2 222
    // return ppp; // p2.then返回 失败2 bbb
}, function (data) {
    console.log("失败1", data);
    // return "bbb"; // promise返回失败, 执行这里 p2.then返回 成功2 bbb
    return ppp; // 执行这里 p2.then返回 失败2 bbb
});
p2.then(function (data) {
    console.log("成功2", data);
}, function (data) {
    console.log("失败2", data);
});

// 3.
let promise = new MyPromise(function (resolve, reject) {
    // resolve();
    reject(); // 失败
});
let p2 = promise.then(function () {
    console.log("成功");
});
p2.catch(function () {
    console.log("失败");
});
// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise{
    constructor(handle){
        // 0.初始化默认的状态
        this.status = PENDING;
        // 定义变量保存传入的参数
        this.value = undefined;
        this.reason = undefined;
        // 定义变量保存监听的函数
        // this.onResolvedCallback = null;
        // this.onRejectedCallback = null;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        // 1.判断是否传入了一个函数, 如果没有传入就抛出一个异常
        if(!this._isFunction(handle)){
            throw new Error("请传入一个函数");
        }
        // 2.给传入的函数传递形参(传递两个函数)
        handle(this._resolve.bind(this), this._reject.bind(this));

    }
    then(onResolved, onRejected){
        return new MyPromise((nextResolve, nextReject) => {
            // 1.判断有没有传入成功的回调
            if(this._isFunction(onResolved)){
                // 2.判断当前的状态是否是成功状态
                if(this.status === FULFILLED){
                    try {
                        // 拿到上一个promise成功回调执行的结果
                        let result = onResolved(this.value);
                        // console.log("result", result);
                        // 判断执行的结果是否是一个promise对象
                        if(result instanceof MyPromise){
                            result.then(nextResolve, nextReject);
                        }else{
                            // 将上一个promise成功回调执行的结果传递给下一个promise成功的回调
                            nextResolve(result);
                        }
                    }catch (e) {
                        nextReject(e);
                    }
                }
            }
            // 1.判断有没有传入失败的回调
            // if(this._isFunction(onRejected)){ // 实现了catch方法,这里可以不需要,异常会
            try {
                // 2.判断当前的状态是否是失败状态
                if(this.status === REJECTED){
                    console.log('then REJECTED', onRejected)
                    let result = onRejected(this.reason);
                    if(result instanceof MyPromise){
                        result.then(nextResolve, nextReject);
                    }else if(result !== undefined){
                        nextResolve(result);
                    }else{
                        nextReject();
                    }
                }
            }catch (e) {
                nextReject(e);
            }
            // }
            // 2.判断当前的状态是否是默认状态
            if(this.status === PENDING){
                if(this._isFunction(onResolved)){
                    // this.onResolvedCallback = onResolved;
                    this.onResolvedCallbacks.push(() => {
                        try {
                            let result = onResolved(this.value);
                            if(result instanceof MyPromise){
                                result.then(nextResolve, nextReject);
                            }else{
                                nextResolve(result);
                            }
                        }catch (e) {
                            nextReject(e);
                        }
                    });
                }
                // if(this._isFunction(onRejected)){
                // this.onRejectedCallback = onRejected;
                this.onRejectedCallbacks.push(() => {
                    try {
                        let result = onRejected(this.reason);
                        if(result instanceof MyPromise){
                            result.then(nextResolve, nextReject);
                        }else if(result !== undefined){
                            nextResolve(result);
                        }else{
                            nextReject();
                        }
                    }catch (e) {
                        nextReject(e);
                    }
                });
                // }
            }
        });
    }
    catch(onRejected){
        return this.then(undefined, onRejected);
    }
    _resolve(value){
        // 这里是为了防止重复修改
        if(this.status === PENDING){
            this.status = FULFILLED;
            this.value = value;
            // this.onResolvedCallback(this.value);
            this.onResolvedCallbacks.forEach(fn => fn(this.value));
        }
    }
    _reject(reason){
        if(this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            // this.onRejectedCallback(this.reason);
            this.onRejectedCallbacks.forEach(fn => fn(this.reason));
        }
    }
    _isFunction(fn){
        return typeof fn === "function";
    }
    static all(list){
        return new MyPromise(function (resolve, reject) {
            let arr = [];
            let count = 0;
            for(let i = 0; i < list.length; i++){
                let p = list[i];
                p.then(function (value) {
                    arr.push(value);
                    count++;
                    if(list.length === count){
                        resolve(arr);
                    }
                }, function (error) {console.log('失败回调函数', error)}) // 失败回调可以不加
                .catch(function (e) {
                    console.log('try 捕获异常')
                    reject(e);
                });
            }
        });
    }
    static race(list){
        return new MyPromise(function (resolve, reject) {
            for(let p of list){
                p.then(function (value) {
                    resolve(value);
                }).catch(function (e) {
                    reject(e);
                });
            }
        })
    }
}

《写一个Promise实现》有一个想法
  1. Wow, fantastic blog format! How long have you
    been running a blog for? you make running a blog glance
    easy. The whole look of your site is wonderful, as smartly as the content material!

    You can see similar here sklep internetowy

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注