js Promise

这是我做的一个基于UmiJS的任务待办桌面应用,欢迎大家给我star

这是我做的一个博客管理系统,该系统在路由拦截这一块的做的非常好,欢迎大家star

异步编程

JS异步机制

  1. 回调函数
    使用多个回调函数嵌套会造成回调地狱,上下两层的代码耦合度高。
  2. Promise
    Promise是ES6引入的异步编程的解决方案,Promise可以封装异步操作,获取成功和失败的结果。Promise的优点是:支持链式调用,可以解决回调地狱问题。
  3. generator
  4. async
    当函数内部执行到一个await语句时,如果语句返回一个promise对象,那么函数会等待promise变为resolve状态在继续向下执行。

setTimeout、Promise、Async/Await 的区别

  1. setTimeout
console.log('script start')	//1. 打印 script start
setTimeout(function(){
    console.log('settimeout')	// 4. 打印 settimeout
})	// 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end')	//3. 打印 script start
// 输出顺序:script start->script end->settimeout
  1. Promise
    Promise本身是同步的立即执行函数,当在执行器中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行
console.log('script start')
let promise1 = new Promise(function (resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function () {
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout

当JS主线程执行到Promise对象时:

  • promise1.then() 的回调就是一个 task
  • promise1 是 resolved或rejected: 那这个 task 就会放入当前事件循环回合的 microtask queue
  • promise1 是 pending: 这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
  • setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况
  1. async/await
    async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体

对Promise的理解

Promise是一种异步编程的解决方案,可以解决回调地狱问题。Promise有三种状态:pending(进行中)、resolved(已完成)、rejected(已拒绝)。Promise只能由pending转化到resolved状态或pending转化到rejected状态。一旦从进行中状态转化为其他状态就不可再改变了

Promise使用流程

首先创建Promise实例,然后Promise对象会执行异步操作,若异步操作成功,则调用resolve()方法并将Promise对象的状态改为resolved,失败则调用reject()方法并将Promise对象的状态改为rejected。在后续调用then方法时,若Promise对象的的状态为resolved,则调用第一个回调函数,否则调用第二个回调函数。then()方法的返回对象也是一个Promise对象,因此可以进行链式调用。

Promise转换状态的三种方式

  1. resolve函数
  2. reject函数
  3. 抛出错误:使用throw抛出错误,promise的状态变为rejected

Promise的缺点:

  1. 无法取消,一旦新建就会立即执行。
  2. 如果不设置回调函数,Promise内部抛出错误,不会反应到外部。

Promise是改变状态先执行还是指定回调先执行

当执行器中的代码为同步时,会先改变状态后执行回调

let promise1 = new Promise((resolve, reject) => {
  resolve("ok1")
  console.log(111);
}).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err);
})

当执行器中的代码为异步时,会先执行回调再改变状态

let promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("ok2")
  }, 100)
}).then(res => {
  console.log(222);
  console.log(res);
}).catch(err => {
  console.log(err);
})

Promise.then()返回新的promise的结果状态由什么决定?

由then()返回的回调函数执行的结果决定。

  • 如果抛出异常,则新的promise的状态为rejected
  • 如果返回的是非promise的值,则新的promise状态为fulfilled
  • 如果返回的是promise,则promise的执行结果为新的promise的结果

如何中断promise链

返回一个状态为pendding的promise对象

Promise的基本用法

  1. 创建Promise对象。
    Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve、reject。
const promise1 = new Promise((resolve, reject) => { 
  ...
  resolve('promise1')
  ...

}).then(res => {   // then方法接受两个回调函数作为参数,第一个回调函数在请求成功时调用,第二个在失败时调用。
  ...
},()=>{

}).catch(err=>{
  console.log(err)
})
  1. Promise方法

all()
all()方法可以完成并行任务,它接收一个数组,数组的每一项都是一个promise对象,当数组中所有的promise的状态都达到了resolved的时候,all方法的状态就会变为resolved,如果有一个状态变为了rejected,那么all方法的状态就会变成rejected。all()方法成功后返回一个数组,该数组记录着每个promise的resolve执行的值。失败后返回最先被reject失败状态的值

race()
race()方法和all()方法一样,区别是race()会返回最先执行完的promise对象。
race()方法可以用来解决某一件事超过多久就不做了。例如:

Promise.race(promise1, timeOutPromise(5000)).then(res=>{})

finally()
finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作。

async

async的返回值为promise对象。这个promise的状态是由async的返回值决定的。

await

await必须写在async()函数内部,await表达式的运算结果取决于它等的是什么:

  • 如果它等到是普通表达式,那么表达式的运算结果就是await返回的结果
  • 如果等到的是promise对象,那么await会等promise对象的状态变为resolve后,得到resolve的值,作为await表达式的运算结果

async/await对比promise的优势

  1. 代码阅读起来更加像同步。promise虽然解决了回调地狱问题,但then的链式调用也会带来额外的阅读负担。
  2. 调试友好。调试器只能跟踪同步代码的每一步。
  3. 错误处理友好。
  4. promise传递中间值比较麻烦,而async/await几乎是同步写法,非常优雅。

promise、async&await和setTimeout运行顺序

  1. JS运行的机制
    JS有一个主线程和一个调用栈,所有的任务都会被放到调用栈中等待主线程执行

在JS中,任务被分为两种,一种宏任务,一种微任务。
宏任务主要为script全部代码、setTimeout、setInterval。

微任务执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务队列是否为空,如果为空时,就执行宏任务,否则就一次性执行完所有微任务。

  1. setTimeout属于宏任务;Promise本身属于同步的立即执行函数,Promise.then()属于微任务;async方法执行时,遇到await会立即执行await后面的代码,在await之后的代码放入微任务队列。

JS运行的流程为:

  1. 首先执行同步代码
  2. 若遇到宏任务调用则同步执行宏任务代码
  3. 宏任务代码执行完后,检测微任务队列,若微任务队列不为空,一次性执行完所有微任务
  4. 重复2.3步骤直到所有代码执行完毕

并行和并发的区别

并发并行
概念在某个时刻通过CPU切换对多个任务进行处理同一时刻发生多个事件
CPU资源需要对CPU资源进行抢占不会对CPU资源进行抢占
线程切换会进行线程切换线程之间不会进行切换

setTimeout、setInterval、requestAnimationFrame 各有什么特点?

  1. setTimeout
    由于JS是单线程执行的,如果前面的代码影响了性能,就会导致setTimeout不会按期执行。可以通过代码修正校准定时器。

  2. setInterval
    setInterval是每隔一定delay就执行一次回调函数。它和setTimeout一样,不能在预期的时间执行任务,而且存在累计执行的问题

setInterval的缺点:

  1. 无视代码错误:setInterval不关心自己调用的代码是否报错
  2. 无网络延迟:setInterval不会管网络延迟(流量剧增、临时断网、带宽限制等),指挥定时发送请求,导致客户端网络队列中都是请求。
  3. 不保证执行:如果你调用的函数需要花很长时间才能完成,那某些调用会被直接忽略。

setTimeout和setInterval的区别

  1. setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式;而setInterval()则可以在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval把它清除。

  2. setTimeout()只执行一次,setInterval()可以执行多次

  3. setTimeout用于延迟执行某方法或功能。setInterval则一般用于刷新表单,对于一些表单的假实时指定时间刷新同步。

  4. requestAnimationFrame
    requestAnimationFrame自带函数节流功能,延时效果精准

手撕promise

1. 初始结构搭建

function Promise(executor) {

}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {

}

2. resolve和reject结构搭建

function Promise(executor) {

  function resolve(data) {

  }

  function reject(data) {

  }

  // 执行器函数是同步调用的
  executor(resolve, reject)
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {

}

3. resolve和reject代码实现

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this


  function resolve(data) {
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data
  }

  function reject(err) {
    self.PromiseState = "rejected"
    self.PromiseResult = err
  }

  // 执行器函数是同步调用的
  executor(resolve, reject)
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {

}

这里需要注意的是,在resolve()函数中 要改变PromiseState和PromiseResult的值需要 更改this指向。因为在resolve()函数中this指向window,而Promise函数内this指向Promise对象,所以要在Promise函数中将this指向保存下来,再进行更改。

4. 抛出异常改变状态

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this


  function resolve(data) {
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data
  }

  function reject(err) {
    self.PromiseState = "rejected"
    self.PromiseResult = err
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {

}

5. Promise的状态只能修改一次

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return
    
    self.PromiseState = "rejected"
    self.PromiseResult = err
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {

}

6. then方法执行回调

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  // 这里的this指向Promise对象
  // console.log(this);

  // 调用回调函数
  if (this.PromiseState === "fulfilled") {
    onResolved(this.PromiseResult)
  }

  if (this.PromiseState === "rejected") {
    onRejected(this.PromiseResult)
  }
}

7. 异步任务回调的执行

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callback = {}


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    if (self.callback.onResolved) {
      self.callback.onResolved(data)
    }
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    if (self.callback.onRejected) {
      self.callback.onRejected(err)
    }
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  // 这里的this指向Promise对象
  // console.log(this);

  // 调用回调函数
  if (this.PromiseState === "fulfilled") {
    onResolved(this.PromiseResult)
  }

  if (this.PromiseState === "rejected") {
    onRejected(this.PromiseResult)
  }

  // 异步任务回调
  if (this.PromiseState === "pending") {
    // 保存回调函数
    this.callback = {
      onResolved,
      onRejected
    }
  }
}

如果Promise的构造器中有异步代码,这时要先执行回调函数,再改变Promise状态,所以要先将回调函数保存下来,等待异步任务执行完改变Promise状态再执行回调函数。首先创建一个callback对象用用于保存回调函数,在then方法中对回调函数进行保存,然后在resolve和reject函数中执行保存的回调函数

8. 指定多个回调的实现

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  // 这里的this指向Promise对象
  // console.log(this);

  // 调用回调函数
  if (this.PromiseState === "fulfilled") {
    onResolved(this.PromiseResult)
  }

  if (this.PromiseState === "rejected") {
    onRejected(this.PromiseResult)
  }

  // 异步任务回调
  if (this.PromiseState === "pending") {
    // 保存回调函数
    this.callbacks.push({
      onResolved,
      onRejected
    })
  }
}

将多个回调保存在一个数组中(防止覆盖),循环执行。

9. 同步修改状态then方法结果返回

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      try {
        // 获取回调函数的执行结果
        let result = onResolved(this.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    if (this.PromiseState === "rejected") {
      onRejected(this.PromiseResult)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved,
        onRejected
      })
    }
  })
}

10. 异步修改状态then方法结果返回

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

11. catch方法封装

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

12. resolve方法封装

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve方法
Promise.resolve = function (res) {
  return new Promise((resolve, reject) => {
    if (res instanceof Promise) {
      res.then(data => {
        resolve(data)
      }).catch(err => {
        reject(err);
      })
    } else {
      // 如果不是promise对象,将状态设置为成功
      resolve(res)
    }
  })
}

13. reject方法封装

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve方法
Promise.resolve = function (res) {
  return new Promise((resolve, reject) => {
    if (res instanceof Promise) {
      res.then(data => {
        resolve(data)
      }).catch(err => {
        reject(err);
      })
    } else {
      // 如果不是promise对象,将状态设置为成功
      resolve(res)
    }
  })
}

// 添加reject方法
Promise.reject = function (err) {
  return new Promise((resolve, reject) => {
    reject(err)
  })
}

14. all方法封装

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve方法
Promise.resolve = function (res) {
  return new Promise((resolve, reject) => {
    if (res instanceof Promise) {
      res.then(data => {
        resolve(data)
      }).catch(err => {
        reject(err);
      })
    } else {
      // 如果不是promise对象,将状态设置为成功
      resolve(res)
    }
  })
}

// 添加reject方法
Promise.reject = function (err) {
  return new Promise((resolve, reject) => {
    reject(err)
  })
}

// 添加all方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    // 声明一个计数变量
    let count = 0
    // 成功结果数组
    let arr = []
    // 遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        count += 1
        arr[i] = res
        if (count === promises.length) {
          resolve(arr)
        }
      }).catch(err => {
        reject(err)
      })
    }
  })
}

15. race方法封装

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    // 执行成功的回调
    self.callbacks.forEach(item => {
      item.onResolved(data)
    })
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    // 执行失败的回调
    self.callbacks.forEach(item => {
      item.onRejected(err)
    })
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      callback(onResolved)
    }

    if (this.PromiseState === "rejected") {
      callback(onRejected)
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve方法
Promise.resolve = function (res) {
  return new Promise((resolve, reject) => {
    if (res instanceof Promise) {
      res.then(data => {
        resolve(data)
      }).catch(err => {
        reject(err);
      })
    } else {
      // 如果不是promise对象,将状态设置为成功
      resolve(res)
    }
  })
}

// 添加reject方法
Promise.reject = function (err) {
  return new Promise((resolve, reject) => {
    reject(err)
  })
}

// 添加all方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    // 声明一个计数变量
    let count = 0
    // 成功结果数组
    let arr = []
    // 遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        count += 1
        arr[i] = res
        if (count === promises.length) {
          resolve(arr)
        }
      }).catch(err => {
        reject(err)
      })
    }
  })
}

// 添加race方法
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    // 遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        resolve(res)
      }).catch(err => {
        reject(err)
      })
    }
  })
}

16. then方法的回调异步执行

function Promise(executor) {
  this.PromiseState = "pending"
  this.PromiseResult = null
  // 这里的this指向Promise对象
  // console.log(this);
  // 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
  const self = this

  // 用于在异步任务回调中保存回调函数
  this.callbacks = []


  function resolve(data) {
    if (self.PromiseState !== "pending") return
    // 这里的this指向window
    // console.log(this);   // 指向window
    // console.log(self);   // 指向promise对象
    self.PromiseState = "fulfilled"
    self.PromiseResult = data

    setTimeout(() => {
      // 执行成功的回调
      self.callbacks.forEach(item => {
        item.onResolved(data)
      })
    }, 0);
  }

  function reject(err) {
    if (self.PromiseState !== "pending") return

    self.PromiseState = "rejected"
    self.PromiseResult = err

    setTimeout(() => {
      // 执行失败的回调
      self.callbacks.forEach(item => {
        item.onRejected(err)
      })
    }, 0);
  }

  // 捕获异常
  try {
    // 执行器函数是同步调用的
    executor(resolve, reject)
  } catch (error) {
    // 调用reject函数修改Promise对象的状态和值
    reject(error)
  }
}

// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
  const self = this

  // 判断回调函数的参数
  if (typeof onRejected !== "function") {
    onRejected = (err => {
      throw err
    })
  }

  if (typeof onResolved !== "function") {
    onResolved = (res => {
      return res
    })
  }

  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    // 这里的this指向Promise对象
    // console.log(this);

    // 封装回调函数执行结果
    function callback(type) {
      try {
        // 获取回调函数的执行结果
        let result = type(self.PromiseResult)
        // 判断执行结果类型
        if (result instanceof Promise) {
          // 结果为Promise对象
          result.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 结果状态为成功
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }

    // 调用回调函数
    if (this.PromiseState === "fulfilled") {
      setTimeout(() => {
        callback(onResolved)
      }, 0);
    }

    if (this.PromiseState === "rejected") {
      setTimeout(() => {
        callback(onRejected)
      }, 0);
    }

    // 异步任务回调
    if (this.PromiseState === "pending") {
      // 保存回调函数
      this.callbacks.push({
        onResolved: function () {
          callback(onResolved)
        },
        onRejected: function () {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve方法
Promise.resolve = function (res) {
  return new Promise((resolve, reject) => {
    if (res instanceof Promise) {
      res.then(data => {
        resolve(data)
      }).catch(err => {
        reject(err);
      })
    } else {
      // 如果不是promise对象,将状态设置为成功
      resolve(res)
    }
  })
}

// 添加reject方法
Promise.reject = function (err) {
  return new Promise((resolve, reject) => {
    reject(err)
  })
}

// 添加all方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    // 声明一个计数变量
    let count = 0
    // 成功结果数组
    let arr = []
    // 遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        count += 1
        arr[i] = res
        if (count === promises.length) {
          resolve(arr)
        }
      }).catch(err => {
        reject(err)
      })
    }
  })
}

// 添加race方法
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    // 遍历
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        resolve(res)
      }).catch(err => {
        reject(err)
      })
    }
  })
}

AJAX、Fetch、axios

AJAX
AJAX可以在不更新全局的情况下更新局部页面。通过在与服务器进行数据交换,可以是网页实现异步更新

创建AJAX

// 1. 创建 XMLHttpRequest 实例
let xhr = XMLHttpRequest()
// 2. 打开和服务器的连接
xhr.open('get', 'URL')
// 3.发送
xhr.send()
// 4. 接收变化。
xhr.onreadystatechange = () => {
    if(xhr.readyState == 4 && xhr.status == 200){   // readyState: ajax 状态,status:http 请求状态
        console.log(xhr.responseText);   //响应主体
    }
}
  1. 创建AJAX实例:let xhr = new XMLHttpRequest()
  2. 打开请求,配置请求前的配置项:xhr.open([http method], [url], [async], [userName], [userPass])
    • http methods 请求方式:postgetdeleteputheadoptionstraceconnect
    • url:想服务器请求的路径
    • async:是否为异步请求
    • userNameuserPass:用户名与密码
  3. 发送请求:XMLHttpRequest.send() 方法中如果 Ajax 请求是异步的则这个方法发送请求后就会返回,如果Ajax请求是同步的,那么请求必须知道响应后才会返回。
  4. 接收数据

AJAX的缺点:

  • 本是针对MVC变成,不符合前端MVVM的浪潮
  • 基于原生的XHR开发
  • 配置和调用方式混乱

axios原理
axios是使用promise封装的ajax,它内部有两个拦截器,分别是request拦截器和response拦截器

  • 请求拦截器的作用是在请求发送之前进行一些操作,例如在每个请求体上加入token
  • 响应拦截器的作用是接收到响应后做的一些操作,例如登录失败后需要重新登录跳转到登录页

axios的特点

  • 由浏览器端发起请求
  • 支持promise API
  • 监听请求和返回
  • 更好的格式化,自动将数据转换为json数据
  • 安全性更高,可抵御XSRF攻击

axios常用的方法
axios常用的方法有getpostputpatchdelete等。其中getpost返回的都是promise对象,可以使用promise方法

  1. axios.get(url[, config]):get请求用于列表和信息查询
axios.get('apiURL', {
    param: {
        id: 1
    }
    // param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res => {
    console.log(res);
})
.catch( error => {
    console.log(error)
}
  1. axios.delete(url[, config]):删除
axios.delete('apiURL', {
    params: {
        id: 1
    },
    timeout: 1000
})
  1. axios.post(url[, data[, config]]):post请求用于信息的添加
axios.post('apiURL',{
        user: '小新',
        age: 18
}).then( res => {
    console.log(res);
})
.catch( error => {
    console.log(error)
}
  1. axios.put(url[, data[, config]]):更新操作
axios.put('apiURL', {
    name: '小新',
})
  1. axios.patch(url[, data[, config]]):更新操作
axios.patch('apiURL', {
    id: 13,
},{
   timeout: 1000,
})

put和patch的区别
patch方法用来更新局部资源,假设我们有一个UserInfo,里面有userId,userName,userGender等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName,这个时候就可以使用patch

put也适用于更新数据,但必须提供完整的资源对象。

axios相关配置

  • url:用于请求服务器的url
  • method:请求方法,默认为get
  • baseURL:会自动加到url前面
  • proxy:用于配置代理
  • transformRequest:允许在服务器发送请求之前修改请求数据

fetch
fetch是http请求数据的方式,它使用Promise,但不使用回调函数。fetch采用模块化设计,通过数据流处理数据,对于请求大文件或网速慢的情况相当有用。默认情况下fetch不会接收或发送cookies。

Fetch、ajax与axios的区别

  • 传统的ajax利用的是HMLHttpRequest这个对象,和后端进行交互。而JQury ajax是对原生XHR的封装,多请求间有嵌套的话就会出现回调地狱的问题。
  • axios使用promise封装XHR,解决了回调地狱的问题。
  • Fetch没有使用XHR,使用的是promise

Fetch和Ajax比有什么优点

Fetch使用的是promise,方便使用异步,没有回调地狱的问题。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值