Promise基础笔记

Promise

参考视频:尚硅谷Web前端Promise教程从入门到精通

https://www.bilibili.com/video/BV1GA411x7z1

回调地狱问题

1、什么是回调地狱?

​ 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件

回调地狱

2、回调地狱的缺点?

​ 不便于阅读,不便于异常处理

3、解决方案?

​ promise 链式调用

4、终极解决方案?

​ async/await

Promise是什么

​ Promise 是 JS 中进行异步编程的新解决方案

本质:Promise 是一个构造函数

作用:promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值

为什么要用 Promise?

​ 指定回调函数的方式更加灵活

​ 1.旧的: 必须在启动异步任务前指定

​ 2.promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)

Promise 的状态改变

​ 三种状态 pending(初始状态) resolved rejected

​ 一个 promise 对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据成功的结果数据一般称为 value, 失败的结果数据一般称为 reason

Promise的基本流程

Promise基本使用

//创建 promise 对象(pending 状态), 指定执行器函数
const p = new Promise((resolve, reject) => {
//在执行器函数中启动异步任务
  setTimeout(() => {
    const time = Date.now()
    // 根据结果做不同处理
    // 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状 态
    if (time%2===1) {
      resolve('成功的值 '+ time) 
    } else { 
      //如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态
      reject('失败的值' + time) 
    }
  }, 2000)
})
//能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
p.then(value => { 
  // 成功的回调函数 onResolved, 得到成功的 vlaue
  console.log('成功的 value: ', value)
},reason => { 
  // 失败的回调函数 onRejected, 得到失败的 reason
	console.log('失败的 reason: ', reason)
})

Promise API

1、Promise 构造函数: Promise (excutor) {}

​ (1) executor 函数: 执行器 (resolve, reject) => {}

​ (2) resolve 函数: 内部定义成功时我们调用的函数 value => {}

​ (3) reject 函数: 内部定义失败时我们调用的函数 reason => {}

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

2、Promise.prototype.then 方法: (onResolved, onRejected) => {}

​ (1) onResolved 函数: 成功的回调函数 (value) => {}

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

​ 说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调返回一个新的 promise 对象

3、Promise.prototype.catch 方法: (onRejected) => {}

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

​ 说明: then()的语法糖, 相当于: then(undefined, onRejected)

4、Promise.resolve 方法: (value) => {}

​ (1) value: 成功的数据或 promise 对象

​ 说明: 返回一个成功/失败的 promise 对象

5、Promise.reject 方法: (reason) => {}

​ (1) reason: 失败的原因

​ 说明: 返回一个失败的 promise 对象

6、Promise.all 方法: (promises) => {}

​ (1) promises: 包含 n 个 promise 的数组

​ 说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败

7、Promise.race 方法: (promises) => {}

​ (1) promises: 包含 n 个 promise 的数组

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

关键问题

一、如何改变 promise 的状态?

​ (1) resolve(value): 如果当前是 pending 就会变为 resolved

​ (2) reject(reason): 如果当前是 pending 就会变为 rejected

​ (3) 抛出异常: 如果当前是 pending 就会变为 rejected

let p = new Promise((resolve, reject) => {
  //1. resolve 函数
  // resolve('ok'); // pending   => fulfilled (resolved)
  //2. reject 函数
  // reject("error");// pending  =>  rejected 
  //3. 抛出错误
  // throw '出问题了';
});
二、一个 promise 指定多个成功/失败回调函数, 都会调用吗?

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

let p = new Promise((resolve, reject) => {
    // resolve('OK');
});
///指定回调 - 1
p.then(value => {
    console.log(value);
});
//指定回调 - 2
p.then(value => {
    alert(value);
});
三、⭐️⭐️改变 Promise 状态和指定回调函数谁先谁后?⭐️⭐️(对应P20)

​ (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调

​ (2) 如何先改状态再指定回调?

​ ① 在执行器中直接调用 resolve()/reject()

​ ② 延迟更长时间才调用 then()

​ (3) 什么时候才能得到数据?

​ ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据

​ ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

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

​ (1) 简单表达: 由 then()指定的回调函数执行的结果决定

​ (2) 详细表达:

​ ① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常

​ ② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值

​ ③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果

let p = new Promise((resolve, reject) => {
  resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
  console.log(value);
  //1. 抛出错误
  // throw '出了问题';
  //2. 返回结果是非 Promise 类型的对象
  // return 521;
  //3. 返回结果是 Promise 对象
  // return new Promise((resolve, reject) => {
  //     // resolve('success');
  //     reject('error');
  // });
}, reason => {
  console.warn(reason);
});
console.log(result);
五、⭐️⭐️Promise关键问题 - 如何串联多个任务⭐️⭐️

​ (1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用

​ (2) 通过 then 的链式调用串连多个同步/异步任务

let p = new Promise((resolve, reject) => {
  console.log(1)
  setTimeout(() => {
    resolve('OK');
  }, 2000);
});
p.then(value => {
  return new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => {
      console.log(value);
      resolve("successA");
    },2000)
  });
}).then(value => {
  return new Promise((resolve, reject) => {
    console.log(3)
    setTimeout(() => {
      console.log(value);
      resolve("successB");
    },2000)
  });
}).then(value => {
  console.log(value);
})
let status = ""
setTimeout(()=>{
  console.log(1)
  status = "OK"
  setTimeout(()=>{
    console.log(2)
    console.log(status)
    status = "successA"
    setTimeout(()=>{
      console.log(3)
      console.log(status)
      status = "successB"
      setTimeout(()=>{
        console.log(status)
      },0)
    },2000)
  },2000)
},2000)

说明:两段代码实现功能一样,可以看到使用promise后产生的明显的区别

六、 Promise 异常传透?

​ (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,

​ (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK');
    // reject('Err');
  }, 1000);
});

p.then(value => {
  // console.log(111);
  throw '失败啦!';
}).then(value => {
  console.log(222);
}).then(value => {
  console.log(333);
}).catch(reason => {
  console.warn(reason);
});
七、中断 Promise 链?

​ (1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数

​ (2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK');
  }, 1000);
});

p.then(value => {
  console.log(111);
  //有且只有一个方式
  return new Promise(() => {});
}).then(value => {
  console.log(222);
}).then(value => {
  console.log(333);
}).catch(reason => {
  console.warn(reason);
});

自定义(手写)Promise

函数版本

//声明构造函数
function Promise(executor){
  //添加属性
  this.PromiseState = 'pending';
  this.PromiseResult = null;
  //声明属性
  this.callbacks = [];
  //保存实例对象的 this 的值
  const self = this;// self _this that
  //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;
    //1. 修改对象的状态 (promiseState)
    self.PromiseState = 'rejected';// 
    //2. 设置对象结果值 (promiseResult)
    self.PromiseResult = data;
    //执行失败的回调
    setTimeout(() => {
      self.callbacks.forEach(item => {
        item.onRejected(data);
      });
    });
  }
  try{
    //同步调用『执行器函数』
    executor(resolve, reject);
  }catch(e){
    //修改 promise 对象状态为『失败』
    reject(e);
  }
}

//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
  const self = this;
  //判断回调函数参数
  if(typeof onRejected !== 'function'){
    onRejected = reason => {
      throw reason;
    }
  }
  if(typeof onResolved !== 'function'){
    onResolved = value => value;
    //value => { return value};
  }
  return new Promise((resolve, reject) => {
    //封装函数
    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'){
      setTimeout(() => {
        callback(onResolved);
      });
    }
    if(this.PromiseState === 'rejected'){
      setTimeout(() => {
        callback(onRejected);
      });
    }
    //判断 pending 状态
    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(value){
  //返回promise对象
  return new Promise((resolve, reject) => {
    if(value instanceof Promise){
      value.then(v=>{
        resolve(v);
      }, r=>{
        reject(r);
      })
    }else{
      //状态设置为成功
      resolve(value);
    }
  });
}

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

//添加 all 方法
Promise.all = function(promises){
  //返回结果为promise对象
  return new Promise((resolve, reject) => {
    //声明变量
    let count = 0;
    let arr = [];
    //遍历
    for(let i=0;i<promises.length;i++){
      //
      promises[i].then(v => {
        //得知对象的状态是成功
        //每个promise对象 都成功
        count++;
        //将当前promise对象成功的结果 存入到数组中
        arr[i] = v;
        //判断
        if(count === promises.length){
          //修改状态
          resolve(arr);
        }
      }, r => {
        reject(r);
      });
    }
  });
}

//添加 race 方法
Promise.race = function(promises){
  return new Promise((resolve, reject) => {
    for(let i=0;i<promises.length;i++){
      promises[i].then(v => {
        //修改返回对象的状态为 『成功』
        resolve(v);
      },r=>{
        //修改返回对象的状态为 『失败』
        reject(r);
      })
    }
  });
}

CLASS版本

class Promise{
  //构造方法
  constructor(executor){
    //添加属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //声明属性
    this.callbacks = [];
    //保存实例对象的 this 的值
    const self = this;// self _this that
    //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;
      //1. 修改对象的状态 (promiseState)
      self.PromiseState = 'rejected';// 
      //2. 设置对象结果值 (promiseResult)
      self.PromiseResult = data;
      //执行失败的回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onRejected(data);
        });
      });
    }
    try{
      //同步调用『执行器函数』
      executor(resolve, reject);
    }catch(e){
      //修改 promise 对象状态为『失败』
      reject(e);
    }
  }

  //then 方法封装
  then(onResolved,onRejected){
    const self = this;
    //判断回调函数参数
    if(typeof onRejected !== 'function'){
      onRejected = reason => {
        throw reason;
      }
    }
    if(typeof onResolved !== 'function'){
      onResolved = value => value;
      //value => { return value};
    }
    return new Promise((resolve, reject) => {
      //封装函数
      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'){
        setTimeout(() => {
          callback(onResolved);
        });
      }
      if(this.PromiseState === 'rejected'){
        setTimeout(() => {
          callback(onRejected);
        });
      }
      //判断 pending 状态
      if(this.PromiseState === 'pending'){
        //保存回调函数
        this.callbacks.push({
          onResolved: function(){
            callback(onResolved);
          },
          onRejected: function(){
            callback(onRejected);
          }
        });
      }
    })
  }

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

  //添加 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(promises){
    //返回结果为promise对象
    return new Promise((resolve, reject) => {
      //声明变量
      let count = 0;
      let arr = [];
      //遍历
      for(let i=0;i<promises.length;i++){
        //
        promises[i].then(v => {
          //得知对象的状态是成功
          //每个promise对象 都成功
          count++;
          //将当前promise对象成功的结果 存入到数组中
          arr[i] = v;
          //判断
          if(count === promises.length){
            //修改状态
            resolve(arr);
          }
        }, r => {
          reject(r);
        });
      }
    });
  }

  //添加 race 方法
  static race (promises){
    return new Promise((resolve, reject) => {
      for(let i=0;i<promises.length;i++){
        promises[i].then(v => {
          //修改返回对象的状态为 『成功』
          resolve(v);
        },r=>{
          //修改返回对象的状态为 『失败』
          reject(r);
        })
      }
    });
  }
}   

async 与 await

async 函数

1、函数的返回值为 promise 对象

2、promise 对象的结果由 async 函数执行的返回值决定

async function main(){
  //1. 如果返回值是一个非Promise类型的数据
  // return 521;
  //2. 如果返回的是一个Promise对象
  // return new Promise((resolve, reject) => {
  //     // resolve('OK');
  //     reject('Error');
  // });
  //3. 抛出异常
  throw "Oh NO";
}

await 表达式

1、await 右侧的表达式一般为 promise 对象, 但也可以是其它的值

2、如果表达式是 promise 对象, await 返回的是 promise 成功的值

3、如果表达式是其它值, 直接将此值作为 await 的返回值

async function main(){
  let p = new Promise((resolve, reject) => {
    // resolve('OK');
    reject('Error');
  })
  //1. 右侧为promise的情况
  // let res = await p;
  //2. 右侧为其他类型的数据
  // let res2 = await 20;
  //3. 如果promise是失败的状态
  try{
    let res3 = await p;
  }catch(e){
    console.log(e);
  }
}
main();

注意

1、await 必须写在 async 函数中, 但 async 函数中可以没有 await

2、如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理

async与await结合

/**
 * resource  1.html  2.html 3.html 文件内容
 */

const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisify(fs.readFile);

//回调函数的方式
// fs.readFile('./resource/1.html', (err, data1) => {
//     if(err) throw err;
//     fs.readFile('./resource/2.html', (err, data2) => {
//         if(err) throw err;
//         fs.readFile('./resource/3.html', (err, data3) => {
//             if(err) throw err;
//             console.log(data1 + data2 + data3);
//         });
//     });
// });

//async 与 await
async function main(){
  try{
    //读取第一个文件的内容
    let data1 = await mineReadFile('./resource/1x.html');
    let data2 = await mineReadFile('./resource/2.html');
    let data3 = await mineReadFile('./resource/3.html');
    console.log(data1 + data2 + data3);
  }catch(e){
    console.log(e.code);
  }
}

main();

说明:当你想实现读取项目目录下三个html文件并将文件的内容拼接(三个文件的内容按顺序拼接)由于fs.readFile是一个异步的方法,必须通过回调函数的形式进行执行才能得到想要的文件,产生了回调地狱.此时场景使用async,await会更加方便简单明了,解决回调地狱问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值