promise深入理解和使用

发布于:2025-07-01 ⋅ 阅读:(19) ⋅ 点赞:(0)

概念

Promise是JS 中进行异步编程的新解决方案(旧的解决方案是回调函数),遵循es6规范。其最大特点就是解决了地狱回调问题。

从语法上来说: Promise是一个构造函数

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

异步编程包括
  • fs 文件操作

    require('fs').readFile('./index.html', (err,data)=>{})
    
  • 数据库操作

  • ajax

    $.get('/server', (data)=>{})
    
  • 定时器

    setTimeout(()=>{}, 2000);
    
优点

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

  • 旧的: 必须在启动异步任务前指定
  • promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函 数(甚至可以在异步任务结束后指定/多个)

支持链式调用,可以解决回调地狱问题

什么是回调地狱? 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
在这里插入图片描述

用法

基本写法
//promise构造函数的参数也是一个函数,接收两个参数,这两个参数也是函数
const p = new Promise((resolve, reject) => {
     //处理业务
        ...
     //处理业务状态的结果
     if(res.status){
       resolve(res.response) //如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
     }else{
       reject(res.status) //如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态
     }
});
p.then(
    res => { // 成功的回调函数 onResolved, 得到成功的 vlaue
       ...
    },
    reason => { //失败的回调函数 onRejected, 得到失败的 reason
       ...
    }
)
封装
function xxxxx(params) {
    //创建 promise 对象(pending 状态)
    return new Promise((resolve, reject) => {
        //处理业务
        ...
        //处理业务状态的结果
        if(res.status){
           resolve(res.response) //如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
        }else{
           reject(res.status) //如果失败了, 调用 reject(), 指定失败的 reason, 变为rejected 状态
        }
    });
}
//能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
xxxxx(params).then(
    res => { // 成功的回调函数 onResolved, 得到成功的 vlaue
       ...
    },
    reason => { //失败的回调函数 onRejected, 得到失败的 reason
       ...
    }
)

nodejs中有一个util.promisify方法可以自动帮我们封装promise业务。

promise状态

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

Promise 对象的值

实例对象中的另一个属性 『PromiseResult』

保存着异步任务『成功/失败』的结果

  • resolve
  • reject

执行流程

在这里插入图片描述

Promise的Api

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

//如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象,状态也是成功的
let p1 = Promise.resolve(521);
//如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
    // resolve('OK'); // 返回 resolved / fullfilled 状态
    reject('Error'); // 返回 reject 状态
}));
// console.log(p2);
p2.catch(reason => {
    console.log(reason);
})
Promise.reject 方法: (reason) => {}

(1) reason: 失败的原因

说明: 返回一个一直是失败的 promise 对象 (这个对象为reject传入的参数,参数是啥,结果就是啥,状态都是失败的)

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

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

说明: 返回一个新的 promise对象。只有传入的所有的 promise 都成功,状态才是成功,返回的是传入的所有成功的promise对象。只要有一个失败了返回的promise状态就是失败,结果为传入的失败的promise对象。

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

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

说明: 返回一个新的 promise对象, 第一个完成的 promise 的结果状态就是最终的结果状态。这里完成意思是传入n 个 promise 的数组, 哪一个优先成为promise对象,哪一个就决定了返回对象的结果和状态。

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
    }, 1000);
})
let p2 = Promise.resolve('Success'); 
let p3 = Promise.resolve('Oh Yeah');
//调用
const result = Promise.race([p1, p2, p3]);//因为p1 1秒后才执行,所以返回的结果为p2,状态也由p2决定
console.log(result);

关键的问题

如何改变 promise 的状态?
const p = new Promise((resolve, reject) => {
    //resolve(value);//如果当前是 pending 就会变为 resolved
    //reject(reason); //如果当前是 pending 就会变为 rejected 
    throw "sss"; //如果当前是 pending 就会变为 rejected, 值为"sss"
})
console.log(p1)
一个 promise 指定多个成功/失败回调函数, 都会调用吗?

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

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

两种都有可能。如何先改状态再指定回调?

  • 在执行器中(excutor)直接调用 resolve()/reject(),然后才调用回调
  • 延迟更长时间调用 then()。比如执行器中延时1秒执行,then中延时两秒。

什么时候then先执行?

  • 执行器调用resolve()/reject()由延时,或者比then延时更长。就会调用then方法。

如果then先执行什么时候才能得到数据?

  • 只有当执行器调用resolve()/reject()完毕之后,then方法的回调(作为then方法的那两个参数)才会执行
promise.then()返回的新 promise 的结果状态由什么决定?

调用then方法,then方法的逐回结果是 Promise对象,对象状态由回调函数的执行结果决定。

  1. 如果回调函数中返回的结果是非promise 类型的属性,状态为成功,返回值为对象的成功的值.
  2. 如果回调函数中返回的结果是promise 类型的属性,状态根据then方法内部Promise返回的状态决定。
  3. 如果直接抛出错误,返回值也是promise类型的,状态是reject,值为抛出错误的值。
//创建实例
const p = new Promise(function (resolve, reject) {
    //模拟主体业务代码
    setTimeout(() => {
        //let data = "成功获取数据库中的数据";
        //resolve(data);
        let data = "获取失败";
        reject(data);
    }, 1000);
});
//调用promise实例
const result = p.then(function (value) {
    //1.非promise类型的属性
    return 'iloveyou';
    //2.是 promise对象
    return new Promise((resolve, reject) => {
        // resolve('ok');
        reject('error ');
    });
    //3.抛出错误
    throw new Error("出错啦!");
}, function (reason) {
    console.warn(reason);
});
console.log(result);

由于promise返回的是promise类型,所以可以进行链式调用

const fs = require('fs');

const p = new Promise(function (resolve, reject) {
    fs.readFile("./source/为学.md", function (err, data) {
        if (err) reject(err);
        resolve(data);
    });
});

p.then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("./source/为学1.md", function (err, data) {
            resolve([value, data]);
        });
    });
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("./source/为学2.md", function (err, data) {
            value.push(data);
            return resolve(value);
        });
    });
}).then(value => {
    console.log(value.join('\r\n'));
});
promise 异常传透?

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

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

p.then(value => {
    throw '失败啦!';
    console.log(222);
}).then(value => {
    console.log(333);
}).catch(reason => {
    console.warn(reason);
});

中断 promise 链?

  • 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

自定义封装Promise

function Promise(executor){
  this.PromiseState = "pending"
  this.PromiseResult = null
  this.callback = []
  //保存Promise对象到this中
  const _this = this;

  function resolve(data){
    //只能修改一次
    if(_this.PromiseState !== "pending") return;
    //更改状态和值
    _this.PromiseState = "fulfilled"
    _this.PromiseResult = data
    //如果有保存then方法的参数回调,就执行
    if(_this.callback){
      _this.callback.forEach(item=>{
        item.onResovle(data)
      })
    }
  }

  function reject(data){
    //只能修改一次
    if(_this.PromiseState !== "pending") return;
    //更改状态和值
    _this.PromiseState = "reject"
    _this.PromiseResult = data
    //如果有保存then方法的参数回调,就执行
    if(_this.callback.onReject){
      _this.callback.onReject(data)
    }
    //如果有保存then方法的参数回调,就执行
    if(_this.callback){
      _this.callback.forEach(item=>{
        item.onReject(data)
      })
    }
  }

  try {
     //同步调用『执行器函数』
    executor(resolve, reject);
  } catch (error) {
    reject(error)
  }
 
}

Promise.prototype.then = function(onResovle, onReject){
  let _this = this
  //如果沒有传递onReject参数
  if(typeof onReject !== "function"){
    onReject = reason => {
      throw reason
    }
  }
  //如果沒有传递onResovle参数
  if(typeof onResovle !="function"){
    onResovle = value => value
  }

  //返回一个Promise对象
  return new Promise((resolve, reject)=>{
    function callback(type){
      try {
        const result = type(_this.PromiseResult)
        if(result instanceof Promise){
          result.then(v=>{
            resolve(v)
          }, r=>{
            reject(r)
          })
        }else{
          resolve(result)
        }
      } catch (error) {
        reject(error)
      }
    }
    
    if(this.PromiseState === "fulfilled"){
      callback(onResovle)
    }
    if(this.PromiseState === "reject"){
      callback(onReject)
    }
    if(this.PromiseState === "pending"){
      //状态为pending的时候保存回调方法
      this.callback.push({
        onResovle:function(){
          callback(onResovle)
        }, 
        onReject:function(){
          callback(onReject)
        }
      })
    }
  })
}

Promise.prototype.catch = function(onReject){
  return this.then(undefined, onReject)
}

Promise.resolve = function(value){
  return new Promise((resolve, reject)=>{
    if(value instanceof Promise){
      value.then(r=>{
        resolve(r)
      }, v=>{
        reject(v)
      })
    }else{
      resolve(value)
    }
  })
}

Promise.reject = function(value){
  return new Promise((undefined, reject)=>{
    reject(value)
  })
}

Promise.all = function(promise){
  return new Promise((resolve, reject)=>{
    let count = 0
    let arr = []

    for(let i=0; i<=promise.length; i++){
      promise[i].then(v=>{
        count ++;
        arr[i] = v;
        if(count === promise.length){
          resolve(arr)
        }
      }, r=>{
        reject(r);
      })
    }
  })
}

Promise.race = function(promise){
  return new Promise((resolve, reject)=>{
    for(let i=0; i<=promise.length; i++){
      promise[i].then(v=>{
        resolve(v)
      }, v=>{
        reject(v);
      })
    }
  })
}

async和await

文档

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

async函数
  • async关键字修饰的函数的返回值为promise对象。

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

函数体内部返回的结果如果是一个非Promise类型的对象,调用函数后返回的结果就是成功Promise对象,promise对象的值为返回的值。

async function fn() {
    return 'success';
}
let result = fn();
console.log(result);

如果函数体内抛出错误, 调用函数后返回的结果是一个失败的 Promise。

async function fn() {
    throw new Error('出错啦');
}
let result = fn();
console.log(result);

如果函数体内返回是一个Promise对象。

async function fn() {
    return new Promise(function (resolve, reject) {
    	//在Promise对象中如果执行resolve函数,async函数将返回成功的Promise对象,值为resolve传递的参数。
    	//在Promise对象中如果执行reject函数,函数将返回失败的Promise对象,值为resolve传递的参数
	});
}
let result = fn();
console.log(result);

await表达式

await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值。

  • await必须写在 async函数中
  • await右侧的表达式一般为promise对象
  • await返回的是promise 成功的值
  • awaitpromise 失败了,就会抛出异常,需要通过try...catch捕获处理。
//创建promise对象
const p = new Promise((resolve, reject) => {
    // resolve("用户数据");
    reject("失败啦! ");
})
// await要放在async函数中
async function main() {
    try {
        let result = await p;//await返回的是promise 成功的值
        console.log(result);
    } catch (e) { //如果调用reject函数,捕获异常
        console.log(e);
    }
}
//调用函数
main();

async和await结合实践

const fs = require('fs');

function readWeiXue1() {
    return new Promise((resolve, reject) => {
        fs.readFile("./source/为学.md", function (err, data) {
            if (err) reject(err);
            resolve(data);
        })
    });
}

function readWeiXue2() {
    return new Promise((resolve, reject) => {
        fs.readFile("./source/为学1.md", function (err, data) {
            if (err) reject(err);
            resolve(data);
        })
    });
}

function readWeiXue3() {
    return new Promise((resolve, reject) => {
        fs.readFile('./source/为学2.md', function (err, data) {
            if (err) reject(err);
            resolve(data);
        })
    });
}

async function main() {
    let wx1 = await readWeiXue1();
    let wx2 = await readWeiXue2();
    let wx3 = await readWeiXue3();
    console.log(wx1.toString());
    console.log(wx2.toString());
    console.log(wx3.toString());
}
main();

async和await结合ajax实践

function sendAjax(method, url) {
    return new Promise((resolve, reject) => {
        //创建对象
        let xhr = new XMLHttpRequest();
        //初始化
        xhr.open(method, url);
        //发送
        xhr.send();
        //事件绑定
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response)
                } else {
                    reject(xhr.status);
                }
            }
        }
    })
}

async function main() {
    let l1 = await sendAjax("GET", "https://www.tianqi.com/tianqi/mapdata_new.json");
    console.log(l1);
}
main();

网站公告

今日签到

点亮在社区的每一天
去签到