Web开发编程网
分享Web开发相关技术

es6-Promise 72行,还有比我少的吗?

  如果世界上所有的表白都能成功的话,那这个世界就不会存在像我这样的人了。

      晚上我回到宿舍将我要表白她的事告诉了室友,室友纷纷当起了劝退师,觉得我压根配不上她,她有太多优质的选择。陷入爱河的我已经听不进任何人的劝阻了,只要有百分之零点一的机会我就想尝试下。于是接下来的几天我一直在计划我的表白了……
      终于等到那天,今天的天气额外的宁静清爽,我以各种借口约她晚上去操场走走,起初她并不愿意,在我的死打烂缠下终于答应了。我提前买好了她喜欢的抹茶味奶茶,少糖。现在仍然记得等待时的心情,激动,紧张,充满期待,没一会,她也下来了,我俩并肩像操场走去,我曾在无数个日夜幻想这个场景。
      起先我只是和她聊了下最近的生活,我太紧张了,这是我人生中第一次约女孩出来,也是我即将的第一次表白,我一直不能从话题中找一个契合的时机去表白,走着走着已经围绕操场走了2圈了,她也有点想回去的意思,我突然话锋一转,说最近好多人和你表白呀,里面有你喜欢的吗?她说目前还没有让她心动的,她突然也警觉起来,说了句:该不会你要向我表白吧,我从没考虑过和班上人谈恋爱。我赶紧红着脸回答道:不是的,我也才认识你不久,只是觉得你挺优秀的,想和你交个朋友而已….当时我裂了,铁铁们….
      回到宿舍我强装着啥事没发生和他们说道表白延后了,我要充分准备下。半夜我哭了,没有声音,只是觉得心里很难受,甚至自己有点莫名其妙。
      第一次表白就这样烂在了我心里,还有那封未送出的信。

                              ……..
      我如果爱你 绝不学攀援的凌霄花 借你的高枝炫耀自己
      我如果爱你 绝不学痴情的鸟儿 为绿荫重复单调的歌曲
                              ……..

Promise用法及手写一个Promise

Promise 简介和基本用法

promise 是一个拥有 then 方法的对象或函数,其行为符合本规范;
promise A+规范我不会详细介绍,感兴趣的可以去promise官网了解。

then 方法接受两个参数 onFulfilled, onRejected 。前者是成功的回调,后者是失败的回调。如果Promise里面执行的是resolve进入onFulfilled,执行reject进入onRejected

人狠话不多,直接上干货了。

       new Promise((reslove, reject) => {
            console.log(1111);
            setTimeout(() => {
                console.log('setTimeut', 2222);
                reslove(1);
            }, 1000);
        }).then(
            (res) => {
                console.log(3333);
            },
            (err) => console.log(err),
        );
复制代码

上图代码的执行结果如下:

image.png
Promise.all

使用场景:一次请求多个接口,需要同时拿到里面的信息。

接下来用promise结合setTimeout模拟axios

        var promise1 = Promise.resolve('我');
        var promise2 = new Promise(function(resolve, reject) {
            setTimeout(resolve, 1000, '不是');
          });
        var promise3 = new Promise(function(resolve, reject) {
          setTimeout(resolve, 2000, '舔狗');
        });
        Promise.all([promise1, promise2, promise3]).then(function(values) {
          console.log(values);
        }); 
复制代码

下图是values的打印结果

image.png
Promise.all 弊端

但Promise.all是有弊端的,假如你一次请求5个接口,只要有一个接口请求失败,他将会走到catch

        var promise1 = Promise.resolve('我');
        var promise2 = new Promise(function (resolve, reject) {
            setTimeout(reject, 1000, '不是');
        });
        var promise3 = new Promise(function (resolve, reject) {
            setTimeout(resolve, 2000, '舔狗');
        });
        Promise.all([promise1, promise2, promise3])
            .then(function (values) {
                console.log(values);
            })
            .catch((err) => console.log(err));
复制代码

上面我把promise2 里面换成了reject,它走到catch,下图是打印的err

image.png
es11 的 Promise.allSettled 解决了Promise.all弊端
        var promise1 = Promise.resolve('我');
        var promise2 = new Promise(function (resolve, reject) {
            setTimeout(reject, 1000, '不是');
        });
        var promise3 = new Promise(function (resolve, reject) {
            setTimeout(resolve, 2000, '舔狗');
        });
        Promise.allSettled([promise1, promise2, promise3])
            .then(function (values) {
                console.log(values);
            })
            .catch((err) => console.log(err));
复制代码

无论是有失败的请求,他都会走到then里面,并用对象将结果包起来,下图是打印的values

image.png
Promise.race

多个请求中,那个先执行就返回该请求的结果,慢的就忽视了

        var promise2 = new Promise(function (resolve, reject) {
            setTimeout(resolve, 1000, '班花');
        });
        var promise3 = new Promise(function (resolve, reject) {
            setTimeout(resolve, 2000, '舔狗');
        });
        Promise.all([ promise2, promise3])
            .then(function (values) {
                console.log(values);
            })
复制代码

values的打印结果如下

image.png
Promise 值穿透 及如何中断Promise 链式请求

穿透

     Promise.resolve(1)
            .then(2) // 注意这里
            .then(Promise.resolve(3))
            .then(console.log);   // 输出1   这一步等同 .then((res)=>{console.log(res)})
复制代码

return 一个值修改下一个then里面的value

    Promise.resolve(1)
          .then(function(){return 2})
          .then(Promise.resolve(3))
          .then(console.log)  // 输出2
复制代码
    Promise.resolve(1)
          .then(function(){return 2})
          .then(function(){return Promise.resolve(3)})
          .then(console.log)  // 输出3
复制代码

如何中断Promise
中断Promise只有一种方法,那就是让他的状态变为pending
Promise是有三种状态 pendingfulfilled,or rejected

const promise = new Promise((resolve, reject) => {
        resolve(111);
    }).then((res)=>{
        console.log(res)  //打印111
        return  2222
    }).then(res=>{
        console.log(res)  //打印222
        return new Promise(()=>{})
    }).then(res=>{
        console.log(3333)  //不会打印,被中断了
    })
复制代码
手写Promise

下图是我们常见的业务场景,由浅入深,我们先单纯的实现下面这个例子

    new Promise((resolve,reject)=>{
            setTimeout(()=>{
                console.log(1)
                resolve(2)
            },1000)
        }).then(res=>{
            console.log(res)
        })
复制代码

是不是很简单,x instanceof myPromise ? x.then(resolve, reject) : resolve(x);就这行需要细品一下,如果卡在了setTimeout,可以看看事件循环机制,如果不懂class的可以看看我的第一文章

// 
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

 class myPromise {
            constructor(executor) {
                let self = this;
                self.status = PENDING;
                self.value = undefined;
                self.reason = undefined;
                self.onResolvedCallbacks = [];
                self.onRejectedCallbacks = [];

                let resolve = (value) => {
                    if (self.status === PENDING) {
                        self.status = FULFILLED;
                        self.value = value;
                        self.onResolvedCallbacks.forEach((fn) => fn());
                    }
                };
                
                executor(resolve);
            }
        
            then(onFulfilled, onRejected) {
                let self=this
                 return new myPromise((resolve, reject) => {
                     if (self.status === 'pending') {
                        self.onResolvedCallbacks.push(() => {
                                let x = onFulfilled(self.value);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                        });
                        self.onRejectedCallbacks.push(() => {
                                let x = onRejected(self.reason);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                        });
                      }
                  });
            }
        }
复制代码

下图我加入了reject,也完善了then方法里面当状态位fulfilled和rejected。代码量其实并不多….

    const PENDING = 'pending';
    const FULFILLED = 'fulfilled';
    const REJECTED = 'rejected';
     class myPromise {
            constructor(executor) {
                let self = this;
                self.status = PENDING;
                self.value = undefined;
                self.reason = undefined;
                self.onResolvedCallbacks = [];
                self.onRejectedCallbacks = [];

                let resolve = (value) => {
                    if (self.status === PENDING) {
                        self.status = FULFILLED;
                        self.value = value;
                        self.onResolvedCallbacks.forEach((fn) => fn());
                    }
                };

                let reject = (reason) => {
                    if (self.status === PENDING) {
                        self.status = REJECTED;
                        self.reason = reason;
                        self.onRejectedCallbacks.forEach((fn) => fn());
                    }
                };
                try {
                    executor(resolve, reject);
                } catch {
                    reject(err);
                }
            }

            then(onFulfilled, onRejected) {
                //处理then里面不是回调函数情况
                //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;
                onRejected =
                    typeof onRejected === 'function'
                        ? onRejected
                        : (err) => {
                              throw err;
                          };
                let self = this;
                return new myPromise((resolve, reject) => {
                    if (self.status === 'fulfilled') {
                        setTimeout(() => {
                            try {
                                let x = onFulfilled(self.value);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                            } catch (err) {
                                reject(err);
                            }
                        }, 0);
                    }
                    if (self.status === 'rejected') {
                        setTimeout(() => {
                            try {
                                let x = onRejected(self.reason);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                            } catch (err) {
                                reject(err);
                            }
                        }, 0);
                    }
                    if (self.status === 'pending') {
                        self.onResolvedCallbacks.push(() => {
                            setTimeout(() => {
                                let x = onFulfilled(self.value);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                            }, 0);
                        });
                        self.onRejectedCallbacks.push(() => {
                            setTimeout(() => {
                                let x = onRejected(self.reason);
                                x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
                            }, 0);
                        });
                    }
                });
            }
        }
复制代码

仔细分析下onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;let x = onFulfilled(self.value);,你就知道下图为啥是这个结果了

image.png
Promise.resolve

太简单了吧

    static resolve(data){ 
        return new Promise((resolve,reject)=>{ resolve(data); }) 
    }
复制代码
Promise.all

promise.race我就不写了,大家可以参考all想想如何实现

    static all(values) {
            if (!Array.isArray(values)) {
              return new TypeError("请输入一个数组")
            }
            return new Promise((resolve, reject) => {
              let resultArr = [];
              let len = 0;
              const dealFn = (value, index) => {
                resultArr[index] = value;
                if (++len === values.length) {
                    resolve(resultArr)
                }
              }
              for (let i = 0; i < values.length; i++) {
                let value = values[i];
                //判断value是否还是个promise
                if (value && typeof value.then === 'function') {
                  value.then((value) => {
                    dealFn(value, i);
                  }, reject);
                } else {
                    dealFn(value, i);
                }
              }
            });
          }
复制代码
总结

我用setTimeout模拟去实现它的延迟执行,没有过多的处理promise整体的容错性,真实的源码用了大量的回调去处理异步执行问题,我只是实现了Promise的回调思想。如果想深入学习Promise的可以去看看官网,我已经晕倒在里面了。只要你认真读懂以上内容,至少不会担心面试官问你promise了

如果喜欢我故事的朋友,第一次看的,可以看看我前面的文章 juejin.cn/post/702429…

最后,麻烦铁子们看完点赞支持下!
作者:舔狗的泪
链接:https://juejin.cn/post/7026896760152784910
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

未经允许不得转载:WEB开发编程网 » es6-Promise 72行,还有比我少的吗?

WEB开发编程网

谢谢支持,我们一直在努力

安全提示:您正在对WEB开发编程网进行赞赏操作,一但支付,不可返还。