八、js手写函数第八批


36、ajax

<script>
  const getJSON = function (url) {
    return new Promise((resolve, reject) => {
      const xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
      // 这里的false指的是是否异步发送请求
      // 这里为false就是指请求不是异步的,而是等请求结束,服务器返回结果后再继续执行接下来的js代码
      // 就是和现在的async/await很像
      xhr.open('GET', url, false);
      xhr.setRequestHeader('Accept', 'application/json');
      xhr.onreadystatechange = function () {
        // 这里如果不等于4的话说明请求还没有发送结束,跳出去等待下一次readystatus的状态变更
        //当判断等于4的时候,说明请求结束了,可以继续执行了
        if (xhr.readyState !== 4) return;
        if (xhr.status === 200 || xhr.status === 304) {
          resolve(xhr.responseText);
        } else {
          reject(new Error(xhr.responseText));
        }
      }
      xhr.send();
    })
  }
</script>

37、再次手写Promise

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    img {
      width: 200px;
      height: 200px;
      display: block;
      margin-bottom: 20px;
    }
  </style>
</head>

<body>

  <script>

    const resolvePromise = (promise2, x, resolve, reject) => {
      if (promise2 === x) return reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
      if (x instanceof Promise) {
        // 如果是Promise的话我们就要等它执行完成,执行成功我们就调用成功的回调,执行失败就调用失败的回调
        x.then(res => {
          resolve(res)
        }, err => {
          reject(err)
        })

      } else {
        resolve(x);
      }
    }

    class MyPromise {
      constructor(executor) {
        this.state = 'pending';        // 初始状态为 pending
        this.value = undefined;        // 存储结果
        this.reason = undefined;       // 存储错误/拒绝的原因
        this.onFulfilledCallbacks = [];  // 成功的回调列表
        this.onRejectedCallbacks = [];   // 失败的回调列表

        const resolve = (value) => {
          if (this.state === 'pending') {  // 只有在 pending 状态时才可以转移到 fulfilled
            this.state = 'fulfilled';
            this.value = value;
            this.onFulfilledCallbacks.forEach(fn => fn());
          }
        };

        const reject = (reason) => {
          if (this.state === 'pending') {  // 只有在 pending 状态时才可以转移到 rejected
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn => fn());
          }
        };

        try {
          executor(resolve, reject);       // 执行执行器函数,并传入 resolve 和 reject
        } catch (error) {
          reject(error);                  // 如果执行器函数出错,直接调用 reject
        }
      }

      then(onFulfilled, onRejected) {
        let promise2 = new MyPromise((resolve, reject) => {
          if (this.state === 'fulfilled') {
            // 这里写成异步的作用是我们要在代码里访问promise2,但是promise2是new出来的,那个时候new的动作还没有完成,所以访问不到promise2
            // 所以要加个setTimeout作为异步
            setTimeout(() => {
              let x = onFulfilled(this.value);
              // 在这里我们看下用法2和用法3的区别,2返回的x是普通的值,3返回的x是一个Promise对象
              // 这个时候就要判断做不同的处理了,如果是普通值则直接resolve(x),如果是Promsie对象
              // 我们要判断Promsie是否成功,成功调用resolve(),失败调用reject()
              resolvePromise(promise2, x, resolve, reject);
            }, 0)
          } else if (this.state === 'rejected') {
            setTimeout(() => {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            }, 0)
          } else {
            this.onFulfilledCallbacks.push(() => {
              setTimeout(() => {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              }, 0)
            });
            this.onRejectedCallbacks.push(() => {
              setTimeout(() => {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              }, 0)
            });
          }
        });
        return promise2;
      }
    }

    // 1、第一个用法,这个用法帮助我们理解为什么then方法里要做状态的判断,如果是等待状态要先把回调存起来
    // 等resolve执行完改变状态之后再执行,就是为了处理这里的异步的
    const p1 = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        resolve(100)
      }, 1000)
    })
    p1.then((res) => {
      console.log(res);
    })

    // 2、第二个用法,这个用法帮助我们理解promise的链式调用
    const p2 = new MyPromise((resolve, reject) => {
      resolve(500)
    })
    p2.then(res => {
      console.log(res);
      return 200;
    }).then(res => {
      console.log(res)
    })

    // 3、第三个用法,这个用法帮助我们理解promise的链式调用中return Promise对象的情况
    // 现实中也就是应该这么用的
    const p3 = new MyPromise((resolve, reject) => {
      resolve(500)
    })
    p3.then(res => {
      console.log(res);
      return new Promise((resolve, reject) => {
        resolve(100)
      });
    }).then(res => {
      console.log(res)
    })
  </script>

</body>

</html>

文章作者: 吴俊杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 吴俊杰 !
  目录