最最最通俗易懂的promise手写系列(二)- 链式调用

前言

上一次咱们写完了Promise的基础功能,明白了promise为什么能在任务成功的时候,调成功的回调函数,为什么在任务失败的时候调失败的回调函数.今天就把最麻烦的promise链式调用给搞定吧.javascript

附上上篇文章的连接:最最最通俗易懂的promise手写系列(一)
java

再附上上次的代码吧,以避免翻来翻去麻烦.promise

function Promise(executor) {
    let self = this;
    self.value = undefined;
    self.reason = undefined;
    self.status = 'pending';

    self.onFulFilledCallbacks = [];
    self.onRejectedCallbacks = [];

    function resolve(value) {
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved'

            self.onFulFilledCallbacks.forEach(onFulFilled => {
                onFulFilled(self.value)
            });
        }
    }
    function reject(reason) {
        if (self.status === 'pending') {
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(onRejected => {
                onRejected(self.reason)
            });
        }
    }

    try {
        executor(resolve, reject);
    } catch (error) {
        reject(error)
    }
}

Promise.prototype.then = function (onFulFilled, onRejected) {
    if (this.status === 'pending') {
        this.onFulFilledCallbacks.push(() => {
            onFulFilled(this.value)
        }); 
        this.onRejectedCallbacks.push(() => {
            onRejected(this.reason)
        })
    } else if (this.status === 'resolved') {
        onFulFilled(this.value);
    } else if (this.status === 'rejected') {
        onRejected(this.reason);
    }
}
复制代码

咱们要完成的目标:异步

let p = new Promise(function (resove, reject) {
  setTimeout(() => {
    console.log('任务执行完了');
    resove()
  },1500)
});

p.then(function (value) {
      console.log('第一个成功回调')
    },function () {})
  .then(function () {
      console.log('第二个成功回调')
    }, function () {});
    
输出以下:
任务执行完了
第一个成功回调
第二个成功回调
复制代码
  • 咱们都熟悉Jquery,它的链式调用是用rerun this来作的,但是这里却不行,缘由文章末尾再解释。 咱们采起返回一个新的promise对象来实现链式调用.
  • 意思也就是p.then()返回一个新promise对象.
//给这个函数加个返回值,返回值就是一个新new的promise对象
Promise.prototype.then = function (onFulFilled, onRejected) {
    let p2 = new Promise((resolve, reject) => {});
    
    if (this.status === 'pending') {
        this.onFulFilledCallbacks.push(() => {
            onFulFilled(this.value)
        }); 
        this.onRejectedCallbacks.push(() => {
            onRejected(this.reason)
        })
    } else if (this.status === 'resolved') {
        onFulFilled(this.value);
    } else if (this.status === 'rejected') {
        onRejected(this.reason);
    }
    return p2;
}
复制代码
  • 加了两行代码,咱们测试一下输出结果:
    任务执行完了
    第一个成功回调
  • 根据上一次咱们所讲的能够总结出以下结论:真正触发onFulFilledCallbacks里所存储的回调函数只有两个地方:
  1. resolve被调用的时候.(resolve是用户调用的,由于用户固然知道哪一种逻辑算任务成功,哪一种逻辑算任务失败,例如咱们上一章的例子,随机数大于5我就认为是成功的.)
  2. then被调用的时候.(then也是用户调用的,promise里的任务执行完了后要作啥)

这里咱们理一下流程:在咱们new Promise的时候,executor就同步的执行了,根据executor里有无异步操做分一下两种状况:

1.有异步操做,如咱们的例子里,有setTimout,延时1.5s后打印。函数

  • executor函数执行完,p也就完成了new的过程。(此时还不会打印输出任务执行完了,由于setTimout是异步的)
  • 拿到p对象后,代码接着执行p.then,此时很明显状态是pending,咱们会把用户在then里传的回调函数存起来(onFulFilledCallbacks),在1.5s后,setTimeout里调用resovle的时候,会遍历onFulFilledCallbacks,执行以前then里传的函数
  • 这也就是咱们以前为何要给promise加三个状态的缘由(等待pending 成功resolve 失败rejected),惧怕里面有异步任务。 无论如何异步,用户老是知道代码走到哪儿算是成功了(在成功的地方调resolve),代码走到哪儿算是出异常了(在失败的地方调reject)这是规矩,使用Promise必须遵照的规矩。

2.没有异步操做,如咱们的例子里,有setTimout,延时1.5s后打印。post

  • 这个就简单了,跟着代码顺序看就好了,执行executor直接就会调resolve,then的会后,任务已经完成,立即执行用户传的回调函数就好了

回到咱们要解决的问题刚只是输出了第一个成功回调,由于【p2】的status是pending呀(咱们在内部本身new的Promise,内部没有任何要执行的东西,没有调resolve,那咱们就调一下呗).

//给这个函数加个返回值,返回值就是一个新new的promise对象
Promise.prototype.then = function (onFulFilled, onRejected) {
    let p2 = new Promise((resolve, reject) => { resove() });
    
    if (this.status === 'pending') {
        this.onFulFilledCallbacks.push(() => {
            onFulFilled(this.value)
        }); 
        this.onRejectedCallbacks.push(() => {
            onRejected(this.reason)
        })
    } else if (this.status === 'resolved') {
        onFulFilled(this.value);
    } else if (this.status === 'rejected') {
        onRejected(this.reason);
    }
    return p2;
}
复制代码
  • 咱们测试一下输出结果:
    第二个成功回调
    任务执行完了
    第一个成功回调
  • 这一会却是执行了,但是顺序乱了,缘由:p.then拿到p2,p2马上就resolve了,当代码走到p2.then天然就是直接走到this.status === 'resolved',执行传入的函数了.等1.5s后第一个promsie任务完成,打印任务执行完了调用第一个的resolve,第一个成功回调
  • 咱们想要的是本身控制顺序,看直白一点就是咱们得控制在第一个Promise也就是P任务执行完了,才能调P2.resove,那就直接在第一个Promise回调函数执行完了咱们再调P2.resove吧
//给这个函数加个返回值,返回值就是一个新new的promise对象
Promise.prototype.then = function (onFulFilled, onRejected) {
  //p2的resolve在里面,外面拿不到,只有这样很贱的给在外面记下来了
  let p2Resolve ;
  let p2Reject;
  let p2 = new Promise((resolve, reject) => {
    p2Resolve = resolve;
    p2Reject = reject;
  });

  if (this.status === 'pending') {
    this.onFulFilledCallbacks.push(() => {
      onFulFilled(this.value)
      p2Resolve()
    });
    this.onRejectedCallbacks.push(() => {
      onRejected(this.reason)
      p2Reject()
    })
  } else if (this.status === 'resolved') {
    onFulFilled(this.value);
    p2Resolve()
  } else if (this.status === 'rejected') {
    onRejected(this.reason);
    p2Reject()
  }

  return p2;
}
复制代码

输出以下:
任务执行完了
第一个成功回调
第二个成功回调测试

结语

咱们剩下onFulFilled返回值的功能没作,下次子再来.
感谢各位观众.ui

相关文章
相关标签/搜索