老生常谈:Promise对象(1)

504 阅读5分钟

Promise是啥玩意

Promise 是异步编程的一种解决方案,他的出现主要是解决异步事件回调地狱的问题。 何谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件,也就是一个异步操作,从语法上说,Promise是一个对象,他可以获取异步操作的结果。并且提供统一的 API 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

Promise优缺点

优点:我们通过上面的介绍已经了解到了,他可以将异步操作的流程以同步操作的的流程表达出来,把一层层嵌套的 callback 变成 .then().then()...,从而使代码编写和阅读更直观,解决了异步操作回调嵌套的问题。

缺点:首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

基本用法

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。 Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

一个 Promise 实例有这几个状态

  • pending:未确定状态。刚 new 出来的 Promise 处于这个状态;然后会马上执行 executor 中定义的语句
  • resolved:代码执行到 resolve() 语句后
  • rejected:代码执行到 reject() 语句后
  • settled:resolved 或者 rejected 状态都属于 settled

resolve函数的作用是,将Promise对象的状态从“等待中”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“等待中”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用thencatch方法分别指定resolved状态和rejected状态的回调函数。

简单实现

  1. promise是个构造函数
  2. promise内部定义三个属性值 state状态 (初始状态pending,一经改变,无法更改), 成功返回值value,错误返回值reason
  3. promise接受一个函数作为参数,函数含有俩个参数resolve、reject, 这两个方法用来改变promise状态
  4. 初始化实例时 会立即执行处理器exector
  5. 所有promise实例都有then方法,所以then一定是在promise原型上
  6. then方法接受俩参数,成功回调,失败回调,如果是方法则执行
  7. promise内部要处理异步需要定义俩个数组
  8. 在then的时候如果promise是pending状态把回调方法放到数组里,在resolve或者reject时候调用

promise接收同步请求的结果(1-6毛皮)

// 1. pomise是个构造函数 
function Promise(exector) {}
// 2. promise内部定义三个属性值  state状态 (初始状态pending,一经改变,无法更改), 成功返回值value,错误返回值reason
function Promise(exector) {
  this.state = 'pending';
  this.value = undefined;
  this.reason = undefined;
}
// 3. promise接受一个函数作为参数,函数含有俩个参数resolve、reject, 这两个方法用来改变promise状态
let p = new Promise((resolve, reject) => {
    resolve('前端小菜鸟');
})
p.then(data => console.log(data)) // 前端小菜鸟
// 4. 初始化实例时 会立即执行处理器exector
function Promise(exector) {
  this.state = 'pending';
  this.value = undefined;
  this.reason = undefined;
  
  exector(resolve,reject);
  // 执行器其实就是promise接受的函数 
  // 立即执行
  //  (resolve, reject) => {
  //        resolve('前端小菜鸟');
  //  }()
  
  function resolve(value) {
    if(that.state === 'pending') {
      that.value = value;
      that.state = 'resolved';
    }
  }

  function reject(reason) {
    if(that.state === 'pending') {
      that.reason = reason;
      that.state = 'rejected';
    }
  }
}

// 初始化实例 执行器立即执行
let p = new Promise((resolve, reject) => {
    resolve('前端小菜鸟');
})
p.then(data => console.log(data)) // 前端小菜鸟
// 5. 所有promise实例都有then方法,所以then一定是在promise原型上
// 6. then方法接受俩参数,成功回调,失败回调,如果是方法则执行

Promise.prototype.then = function (onFulfilled, onRejected) {
  // then 方法有俩个回调函数 成功、失败
    if(this.state === 'resolved'){ // resolved状态
      if(typeof(onFulfilled) === 'function'){
        onFulfilled(this.value);
      }
    }
    if(this.state === 'rejected'){ // rejected状态
      if(typeof(onRejected) === 'function'){
        onRejected(this.reason);
      }
    }
}

promise接收异步请求的结果(7-8精髓)

// 7. promise内部要处理异步需要定义俩个数组
// 8. 在then的时候如果promise是pending状态把回调方法放到数组里,在resolve或者reject时候调用
function Promise(exector) {
  this.state = 'pending';
  this.value = undefined;
  this.reason = undefined;
  
  this.onResolvedCallbacks = []; // 异步成功回调
  this.onRejectedCallbacks = []; // 异步失败回调
  
  let that = this;
  try{
   // promise初始化实例时 会立即执行处理器exector
    exector(resolve,reject); 
    // 执行器其实就是promise接受的函数
    //  (resolve, reject) => {
    //        resolve('前端小菜鸟');
    //  }()
  }catch(err) {
    console.log(err);
  }
  
  function resolve(value) {
    if(that.state === 'pending') {
      that.value = value;
      that.onResolvedCallbacks.forEach((cb) => cb(value)); // resolve时候执行回调
      that.state = 'resolved';
    }
  }

  function reject(reason) {
    if(that.state === 'pending') {
      that.reason = reason;
      that.onRejectedCallbacks.forEach((cb) => cb(reason)); // reject时候执行回调
      that.state = 'rejected';
    }
  }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
  // then 方法有俩个回调函数 成功、失败
  
    // pending状态的处理
    if(this.state === 'pending') {
      if(typeof(onFulfilled) === 'function'){
        this.onResolvedCallbacks.push(onFulfilled);
      }
      if(typeof(onRejected) === 'function'){
        this.onRejectedCallbacks.push(onRejected);
      }
    }
    // resolved状态
    if(this.state === 'resolved'){ 
      if(typeof(onFulfilled) === 'function'){
        onFulfilled(this.value);
      }
    }
    // rejected状态
    if(this.state === 'rejected'){ 
      if(typeof(onRejected) === 'function'){
        onRejected(this.reason);
      }
    }
}
// promise对象 接受一个函数作为参数,函数中包含俩参数resolve和reject标识成功和失败
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
       resolve('前端大大大菜鸟');
    },1000)
})
p.then(data => console.log(data)) // 前端大大大菜鸟

用class实现

class Promise1 {
  // 实例属性和方法
  constructor(executor) {
    let that = this;
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = []; // 异步成功回调
    this.onRejectedCallbacks = []; // 异步失败回调

    executor(resolve, reject)

    function resolve(val) {
      if(that.state === 'pending') {
        that.value = val;
        that.onResolvedCallbacks.forEach(cb => {
          cb(val);
        })
        that.state = 'resolved';
      }
    }
    function reject(err) {
      if(that.state === 'pending') {
        that.reason = err;
        that.onRejectedCallbacks.forEach(cb => {
          cb(err);
        })
        that.state = 'rejected';
      }
    }
  }
 // 原型方法
  then(onFulfilled, onRejected) {
    if(this.state === 'pending') {
      if(typeof(onFulfilled) === 'function'){
        this.onResolvedCallbacks.push(onFulfilled);
      }
      if(typeof(onRejected) === 'function'){
        this.onRejectedCallbacks.push(onRejected);
      }
    }
    if(this.state === 'resolved' && typeof(onFulfilled) === 'function') {
      onFulfilled(this.value);
    }
    if(this.state === 'rejected' && typeof(onRejected) === 'function') {
      onFulfilled(this.value);
    }
  }
}
let p = new Promise1((resolve, reject)=>{
  setTimeout(() => {
    resolve('前端大菜鸟');
  }, 10);
})
p.then(res=> {
  console.log(res); // 前端大菜鸟
},err=>{
  console.log(err);
})

结语

本篇文章只是介绍一下Promise、优缺点以及Promise的简单实现原理,promise的链式调用和其他方法会在后续更新。如有写的不对的地方请大佬指点我会第一时间改正。