Js拓展_promise

一、什么是Promise

Promise是es6为了方便异步编程的新的解决方案,从语法上来看它是一个构造函数,用于封装异步任务,并且对其结果进行处理

//异步编程
//fs文件操作
require('fs').readFile('./index.html',(err,data)=>{})
//数据库操作
//AJAX
$.get('/server',(data)=>{})
//定时器
setTimeout(()=>{},2000)

二、Promise优缺点

1.promise优点

  1. 指定回调函数的方式更加灵活
  2. 支持链式调用,可以解决回调地狱问题
  3. 更好的进行错误捕捉

2.promise缺点

  1. 无法取消promise,一代新建就会立即执行,无法中途取消
  2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部
  3. 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

三、Promise的创建

promise构造函数包含一个参数和一个带有resolve和reject两个参数的回调。在回调中执行一些操作,如果一切正常则调用resolve,否则调用reject。

setTimeout模拟异步操作:

var myFirstPromise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve("成功!"); //代码正常执行!
  }, 250);
});
myFirstPromise.then(function(successMessage) {
  document.write("Yay! " + successMessage);
});

在这里插入图片描述

四、Promise实践

1、promise读取文件

let promise= new Promise((resolve,reject)=>{
  const fs = require('fs')
  fs.readFile('./data.txt',(err,data)=>{
    if (err) reject(err);
    resolve(data)
  })
})
//调用then
promise.then(value => {
  console.log(value.toString())
},reason => {
  console.log(reason)
})

2、promise封装AJAX

<body>
<button>点击发送请求</button>
</body>
<script>
var promise = new Promise(function(resolve, reject) {
  const btn = document.querySelector('button')
  btn.addEventListener('click',function(){
    //1.创建对象
    const xhr = new XMLHttpRequest()
    //2.初始化
    xhr.open('GET','https://api.apiopen.top/getJoke')
    //3.发送
    xhr.send()
    //4.处理响应结果
    xhr.onreadystatechange = function(){
      if (xhr.readyState ===4 ){
        if (xhr.status>=200&&xhr.response){
          resolve(xhr.response)
        }else {}
        reject(xhr.status)
      }
    }
  })
});
promise.then(value => {
  console.log(value)
},reason => {
  console.log(reason)
});
</script>

3.Promise封装函数

function mineReadFile(Path){
  return new Promise((resolve,reject)=>{
    //读取文件
    require('fs').readFile(Path,(err,data)=>{
      if (err) reject(err);
      resolve(data)
    })
  })
}
mineReadFile('./data.txt').then(value => {
  console.log(value.toString())
},reason => {
  console.log(reason)
})

4.promisify方法

传入一个错误优先的回调风格的函数(以(err,value)=>…会带哦作为最后一个参数),并返回一个Promise版本

//引入util模块
const util = require('util');
//引入fs模块
const fs = require('fs')
let  mineReadFile = util.promisify(fs.readFile);
mineReadFile('./data.txt').then(value => {
  console.log(value.toString())
})

五、Promise状态

描述:实例对象中的一个属性[PromiseState]

三种状态:

  1. pending(进行中)
  2. resolved/fulfilled(已成功)
  3. rejected(已失败)

状态改变:

  1. pending变为resolved
  2. pending变为reje。cted

PS:只有这两种变化,且一个promise对象只能改变一次

六、Promise对象的值

描述:实例对象的另一个属性[PromiseResult]
保存着异步任务【成功/失败】的结果

只有resolve和reject可以对该值进行修改

七、Promise的API

1. Promise构造函数:

Promise(excutor){}

  1. executor 函数:执行器 (resolve,reject)=>{}
  2. resolve函数:内部定义成功时调用的函数 value=>{}
  3. reject函数:内部定义失败时调用的函数reason=>{}

PS:executor会在Promise内部立即同步调用,异步操作在执行器中执行

2.Promise.prototypr.then方法:

(onRsolved.onRejected)=>{}

  1. onResolved函数:成功的回调函数(value)=>{}
  2. onRejected函数:失败的回调函数(reason)={}

PS:指定用于得到成功value的成功回调和用于得到失败reason的失败会带哦返回一个新的promise对象

3.Promise.prototype.catch方法:

(onRejected)=>{}

  1. onRejected函数:失败的回调函数(reason)=>{}

PS:then()的语法糖,相当于:then(undefined,onRejected)

4.Promise.resolve方法:

(value)=>{}

  1. value:成功的数据或者promise对象

PS:返回一个成功/失败的promise对象

5.Promise.reject方法:

(reason)=>{}

  1. reason:失败的原因

PS:返回一个失败的promise对象

6. Promise.all方法:

(promise)=>{}

  1. promises:包含n个promise的数组

PS:返回一个新的promise,只有所有的promise都成功才算成功

let p1 = new Promise((resolce,reject)=>{
  resolce('OK')
})
// let p2 = Promise.resolve('Sucess')
let p2 = Promise.reject('Error')
let p3 = Promise.resolve('Oh Yeah')

const res= Promise.all([p1,p2,p3])
console.log(res)

在这里插入图片描述

7.Promise.race方法:

(promise)=>{}

  1. promises:包含n个promise的数组

PS:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

let p1 = new Promise((resolce,reject)=>{
  resolce('OK')
})
// let p2 = Promise.resolve('Sucess')
let p2 = Promise.reject('Error')
let p3 = Promise.resolve('Oh Yeah')

const res= Promise.race([p1,p2,p3])
console.log(res)

在这里插入图片描述

八、如何改变promise的几个关键问题

1.如何改变promise的状态

  1. resolve(value): 如果当前时pending就会变成resolved
  2. reject(reason): 如果当前时pending就会变成rejected
  3. 抛出异常:如果档期那时pending就会变成rejected
<script>
let p1 = new Promise((resolve,reject)=>{
  // 1.resolve函数
  // resolce('OK') // pending =>fulfilled(resolved)
  // 2.reject函数
  // reject('error') //pending => rejected
  // 3. 抛出错误
  throw 'erro';
})
console.log(p1)
</script>

2.一个promise指定多个成功/失败回调函数时,都会调用吗?

当promise改变未对应状态时都会调用

let p1 = new Promise((resolve,reject)=>{
  resolve('OK')
})
p1.then(value => {
  console.log(value)
})
p1.then(value => {
  alert(value)
})

3.改变promise状态和指定回调函数谁先谁后?

  1. 都有可能,正常情况下时限指定回调在改变状态,但也可以先改变状态再指定回调
  2. 如何先改变状态再指定回调?
  1. 再执行器中直接调用resolve()/reject()
  2. 延迟更长时间调用then()
  1. 什么时候才能得到数据?
  1. 如果先指定的回调,那么当状态发生改变时,回调函数就会调用,得到数据。
  2. 如果先改变的状态,那指定回调时,回调函数就会调用,得到数据。

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

  1. 简单表达:由then()指定的回调函数执行的结果决定。
  2. 详细表达:
  1. 如果抛出异常,新promise变为rejected,reason为抛出的异常。
  2. 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值。
  3. 如果返回的是一个新promise,此promise的结果就会成为新promise的结果。

5.promise如何串联多个操作任务?

  1. promise的then()返回一个新的promise,可以开发成then()的链式调用。
  2. 通过then()的链式调用串联多个同步/异步任务。
//后一个回调返回的时前一个回调函数的结果
let p1 = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },1000)
})
p1.then(value => {
  return new Promise((resolve,reject)=>{
    resolve('success')
  })
}).then(value => {
  console.log(value)// 打印success
}).then(value => {
  console.log(value)//undefined 上一个函数没有指定返回值
})

6.promise异常穿透?

  1. 当使用promise的then()链式调用时,可以再最后指定失败的回调。
  2. 前面任何操作除了异常,都会传到最后失败的回调中处理。
let p1 = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    // reject('err')
    resolve('ok')
  },1000)
})
p1.then(value => {
  // console.log(11)
  throw '失败了'
}).then(value => {
  console.log(22)
}).then(value => {
  console.log(33)
}).catch(reason => {
  console.log(reason)
})

7.中断promise链?

  1. 当使用promise的then()链式调用时,在中间中断,不在调用后面的回调函数。
  2. 方法:在回调函数中返回一个pendding状态的promise对象
let p1 = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('ok')
  },1000)
})
p1.then(value => {
  console.log(11)
  // 有且只有一个方式
  return new Promise(()=>{})
}).then(value => {
  console.log(22)
}).then(value => {
  console.log(33)
}).catch(reason => {
  console.log(reason)
})

九、手写Promise

class Promise {
  //构造方法
  constructor(executor) {
    //添加属性
    this.PromiseState = 'pending'
    this.PromiseResult = null
    // 声明属性
    this.callbacks = []
    // 保存实例对象this的值
    const self = this;

    // resolve
    function resolve(data) {
      //判断状态
      if (self.PromiseState !== 'pending') return
      // 1.修改状态 promiseState
      self.PromiseState = 'fulfilled' //resolved
      // 2.设置对象结果的值 promiseResult
      self.PromiseResult = data
      // 调用成功的回调函数
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onResolved(data)
        })
      })
    }

    // reject
    function reject(data) {
      if (self.PromiseState !== 'pending') return
      self.PromiseState = 'rejected' //resolved
      self.PromiseResult = data
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onRejected(data)
        })
      })
    }

    try {
      //同步调用执行器函数
      executor(resolve, reject);
    } catch (e) {
      //修改promise对象状态为【失败】
      reject(e)
    }
  }

  // then方法
  then(onResolved, onReject) {
    const self = this
    // 判断回调函数参数
    if (typeof onReject !== 'function') {
      onReject = reason => {
        throw reason
      }
    }
    if (typeof onResolved !== 'function') {
      onResolved = value => value;
    }
    return new Promise((resolve, reject) => {
      //封装函数callback
      function callback(type) {
        try {
          //获取回调函数的执行结果
          let result = type(self.PromiseResult)
          if (result instanceof Promise) {
            //如果时Promise类型的对象
            result.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            // 结果的对象状态为成功
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }

      //调用回调函数 PromiseState
      if (this.PromiseState === 'fulfilled') {
        //将then方法改为异步
        setTimeout(() => {
          callback(onResolved)
        })
      }
      if (this.PromiseState === 'rejected') {
        setTimeout(() => {
          callback(onReject)
        })
      }
      // 判断pending状态
      if (this.PromiseState === 'pending') {
        // 保存回调函数
        this.callbacks.push({
          onResolved: function() {
            callback(onResolved)
          },
          onRejected: function() {
            callback(onReject)
          },
        })
      }
    })
  }

  // catch方法
  catch(onReject) {
    return this.then(undefined, onReject)
  }

  // resolve方法
  static resolve(value) {
    //添加Promise对象
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        resolve(value)
      }
    })
  }

  // 添加reject方法
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  // 添加all方法
  static all(promise) {
    // 返回结果时Promise对象
    return new Promise((resolve, reject) => {
      //定义一个计数器
      let count = 0
      let array = []
      // 遍历
      for (let i = 0; i < promise.length; i++) {
        promise[i].then(v => {
          //当所有对象都是成功的
          count++
          //将成功的对象存入到数组中
          array[i] = v
          if (count === promise.length) {
            resolve(array);
          }
        }, r => {
          reject(r)
        })
      }
    })
  }

  // 添加race方法
  static race(promise) {
    return new promise((resolve, reject) => {
      for (let i = 0; i < promise.length; i++) {
        promise[i].then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      }
    })
  }
}

十、async和await

1.async函数

  1. 函数的返回值为Promise对象
  2. promise对象的结果由async函数执行的返回值决定
async function main(){
  //1.如果返回值是一个非Promise的数据
  // return 321
  //2.如果返回 值是一个promise对象
  // return new Promise((resolve,reject)=>{
  //   reject('ERROR')
  // })
  //3.抛出异常
  throw 'NO'
}
let result  = main()
console.log(result)

2. await表达式

  1. await右侧的表达式一般为Promise对象,但也可以是其他的值
  2. 如果表达式时promise对象,await返回的时prmise成功的值
  3. 如果表达式是其他值,直接将此值转会为await的返回值
async function main(){
  let p = new Promise((resolve,reject)=>{
    // resolve('ok')
    reject('error')
  })
  //1.右侧为promise
  // let res = await p; //ok
  //2.右侧为其他类型的数据
  // let res2 =await 20; //20
  //3.promise是失败的状态
  try{
    let res3 = await p //error
  }catch (e){
    console.log(e)
  }
}
main()

3.aync和await结合

案例1

可以看到和回调函数的方式比起来,这种方式非常

const fs = require('fs')
const util = require('util')
const mineReadFile = util.promisify(fs.readFile)
// 回调函数
// fs.readFile('../resource/data.txt',(err,data)=>{
//   if (err) throw err
//   fs.readFile('../resource/data1.txt',(err,data1)=>{
//     if (err) throw err
//     fs.readFile('../resource/data2.txt',(err,data2)=>{
//       if (err) throw err
//       console.log((data+data1+data2).toString())
//     })
//   })
// })

// async 与await
async function main() {
  try {
    //读取第一个文件的内容
    let data = await mineReadFile('../resource/data.txt')
    let data1 = await mineReadFile('../resource/data1.txt')
    let data2 = await mineReadFile('../resource/data2.txt')
    console.log((data + data1 + data2).toString())
  }catch (e){
    console.log(e)
  }
}
main()

案例2

封装AJAX请求

function sendAJAX(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.responseType = 'json'
    xhr.open('GET', url)
    xhr.send()
    //处理结果
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.response)
        } else {
          reject(xhr.status)
        }
      }
    }
  })
}

// sendAJAX('https://api.apiopen.top/getJoke')
//   .then(value => {
//     console.log(value)
//   }, reason => {
//     console.warn(reason)
//   })

let btn = document.querySelector('button')
btn.addEventListener('click', async function() {
  //获取段子
  let res = await sendAJAX('https://api.apiopen.top/getJoke')
  console.log(res)
})
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是发财不是旺财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值