✿✿✿带你走进不一样的 Promise 世界✿✿✿

又是一个...标题党?

不不不,我是来给你的肚子填食儿的,相信我 🤩🤩🤩


Promise 基础语法

Promise

  • ES6中新增一个内置的类:Promise 承诺/约定模式, 基于这种模式可以有效的处理异步编程
  • 异步:上面的事情没有完成也不会等,下面的事情继续处理
  • 同步:上面事情没处理完之前,下面事情是无法去处理的

回调地狱

需求:首先从服务器端基于/api/1这个接口获取数据;紧接着把获取的某些数据作为参数,在基于api/2获取其他的数据;最后在第二次数据获取成功后,在基于api/3获取新的数据…也就是第一个请求成功才可以获取第二个,第二个成功才可以获取第三个…(AJAX的串行)

let data = null;
// 基于 AJAX 异步从服务器获取数据(真实项目中从服务器获取数据也都是异步的)
$.ajax({
    url: '/api/1.json',
    method: 'GET',
    success: function(result) {
    // result 就是基于 JQ 的 ajax 方法从服务器获取的结果
    console.log(result);// 后输出 第二次输出[1]
    data = result;
    }
});

console.log(data);// 先输出 第一次输出 null 

回调地狱:传统在实现异步操作,并且是串行的模式下,基本上都是回调函数嵌套回调函数,实现回调地狱的问题

$.ajax({
    url: '/api/1.json',
    method: 'GET',
    success: function(result) {
        // result 就是基于 JQ 的 ajax 方法从服务器获取的结果
        console.log(result);// 后输出 第二次输出[1]
        data = result;
        // ajax 串行:第一个请求成功才可以发送下一个请求
        $.ajax({
            url: '/api/1.json',
            method: 'GET',
            success: function(result) {
            console.log(‘第二次请求’+result);
            }
        });
    }
});

此时我们需要一种优秀的代码管理模式,能够有效的管理异步编程中的代码,通过这种代码管理的思想,让代码开发起来更便捷,维护起来也很方便,可读性更强。所以 JS 的设计模式诞生:Promise 设计模式就是管理异步编程的

  • 设计模式的优点:按照一定的思想有效管理代码,代码看起来可读性更高,后期可维护性更强。

解决回调地狱问题

  • 基于 Promise 解决
const = api1 = ()=>{
    return new Promise(resolve=>{
        $.ajax({
            url: '/api/1.json',
            method: 'GET',
            dataType: 'json',
            success: function(result) {
               resolve(result);
            }
        })
    })
};

const = api2 = ()=>{
    return new Promise(resolve=>{
        $.ajax({
            url: '/api/2.json',
            method: 'GET',
            dataType: 'json',
            success: function(result) {
               resolve(result);
            }
        })
    })
};

const = api3 = ()=>{
    return new Promise(resolve=>{
        $.ajax({
            url: '/api/3.json',
            method: 'GET',
            dataType: 'json',
            success: function(result) {
               resolve(result);
            }
        })
    })
};
// 执行第一个 ajax 请求,执行.then()「.then 方法是控制第一个请求成功」,拿到请求成后的结果传到 resolve(result) 中;
api1().then(result=> {
    console.log(‘第一次请求=’, result);
    // 发送第二个请求
    return api2();
}).then(result=> {
    console.log(‘第二次请求=’, result);
    // 发送第三个请求
    return api3();
}).then(result=> {
    console.log(‘第三次请求=’, result);
});
  • 终极解决:基于 Promise 管理的 async/await
(async function(){
    let result = await api1();
    console.log(‘第一次请求=’, result);
    let result = await api2();
    console.log(‘第二次请求=’, result);
    let result = await api3();
    console.log(‘第三次请求=’, result);
})()

异步编程: 在 JS 中,除了 ajax 请求时异步编程的,还有一些操作也是异步编程

  • 事件绑定
  • 定时器
  • Promise/async/await
  • requestAnimationFrame
    eg:
// 异步操作
setTimeout(()=>{
    console.log(1);// 第二步
}, 1000)
console.log(2);// 第一步

Promise 语法

  • 每次new Promise 的时候,内部要做的事情

    • new Promise 的时候会立即执行传递的 executor 函数
      • executor 函数中一般用来管控一个异步的操作(不写异步的也可以)
      • 而且传递给 executor 函数两个参数:resolve/reject,并且两个参数都是函数
    • 创造 Promise 类的一个实例 p1,每一个 Promise 的实例都存在两个属性
      • [[PromiseState]]: promise 状态
        • pending: 准备状态
        • fulfilled(旧版本浏览器)/resolved(新版本浏览器): 成功状态(已兑现)
        • rejected: 失败状态(已拒绝)
        • 但是一旦状态从 pending 改变为 fulfilled 或者是 rejected, 都无法再次改变其状态
        • 如果 executor 函数中的代码执行报错,则实例的状态也会变为失败,并且[[PromiseResult]]就是报错的原因
      • [[PromiseResult]]: promise 值:默认是 undefined,一般存储成功的结果或者失败的原因
      • 每个 Promise 实例指向 Promise 类的原型 p1.__proto__ = Promise.prototype
      • Promise 的原型上的方法:then/catch/finally
  • new 的时候必须要传入一个函数才可以,否则报错

let p1 = new Promise();
console.log(p1);// 报错 Promise resolver undefined is not a function at new Promise
let p1 = new Promise(function () { 
    // 一般写异步操作, 同步也可以
    // 同步操作
    console.log(1);  
    // 异步操作
    setTimeout(function () {}, 1000)

     // 只要让 resolve() 函数执行 Promise 状态就为成功, 值为 undefined
    resolve();
    // 传值,则 PromiseResult 值为 100
    resolve(100);
  
    /*
    执行 resolve 控制实例的状态变为成功,传递的值 100,是成功的结果
    [[PromiseState]]: 'fufilled'
    [[PromiseResult]]: 100
    */ 
    resolve(100);
    /*
    执行 resolve 控制实例的状态变为成功,传递的值 100,是成功的结果
    [[PromiseState]]: 'fufilled'
    [[PromiseResult]]: 100

    */ 
    reject(0);
});
console.log(2); 
p1.then();

Promsie 是如何管控异步编程的

  • new Promise 的时候创建一个 promise 实例,此时在 executor 函数中管理一套异步的代码
  • 后期等异步操作成功或者失败的时候,执行 resolve/reject,以此来控制 promise 实例的状态和结果
  • 根据状态和结果,就可以控制基于.then 注入的两个方法中的哪一个去执行了

下述代码执行的顺序(下述代码 executor 函数管控的是异步编程)

  • new Promise 构造函数执行
  • 执行 executor 函数:设置一个异步定时器
  • 执行实例.then(result, reason)注入两个方法,注入的方法会保存起来(此时这两个方法还没有执行)
  • 等待 1000ms
  • 执行定时器的回调函数:通过执行 resolve 改变 promise 状态和值
  • 通知之前基于.then()注入的两个方法中的某一个执行
let p1 = new Promise(function (resolve, reject) { 
  // new Promsie 的时候立即执行 executor 函数,在 executor 函数中管理了一个异步编程代码(此时状态是 pending);当异步操作到达指定时间,开始执行的时候(可以理解为异步操作成功),此时我们通过执行 resolve,把 promise 状态修改为 fulfilled;
  setTimeout(function(){
    resolve('OK');
  }, 1000)
});

p1.then(result=>{
  // 当p1 实例的状态修改为 fulfilled 的时候,通知传递的第一个函数执行,result 就是[[PromiseResult]] 的值
  console.log('成功', result)
}, reason=>{
  // 当p1 实例的状态修改为 rejected 的时候,通知传递的第二个函数执行,reason 就是[[PromiseResult]] 的值
  console.log('失败', reason)
});

下述代码管控的顺序(下述代码 executor 函数管控的是同步代码)

  • new Promise 构造函数执行
  • 执行 executor 函数:
    • 输出 1
    • 立即修改状态和值,并且通知基于 THEN 注入的方法执行,此时 .THEN 方法还没有执行,方法还没有被注入,不知道该通知谁来执行,所以此时需要把通知方法执行的操作先保存起来,放入到等待任务队列中,这个操作本身是异步的,需要等待方法注入完成后再通知其执行
    • 输出 2(到此 executor 函数已经执行完成)
  • 执行实例.then(result, reason)注入两个方法,注入的方法会保存起来(此时这两个方法还没有执行)
  • 输入 3
  • 通知之前基于.then()注入的两个方法中的第一个执行(result方法)
let p1 = new Promise((resolve, reject)=>{
    console.log('1');// 1
    resolve('OK');
    console.log('2');
});

p1.then(result=>{
    console.log('成功:'+result);
}, reason=>{
    console.log('失败:'+reason);
});
console.log('3');

.then方法是异步操作

let p1 = new Promise(resolve => {
    // 1000ms 后,开始执行定时器,此时p1.then()中的两个方法已经注入完成
    setTimeout(function(){
        // 执行 resolve ,立即修改 promise 状态和值
        resolve('OK);
        console.log(1);
    }, 1000)
});

p1.then(result=>{
    console.log(2);
});
// 最终结果为 1 2
  • 输出 1 2

    • 说明 then 方法为异步:执行 resolve 后,不会等待执行 then 方法中的 result,而是放在一个事件队列中,先把同步代码执行完成输出 1,在去事件队列中找异步代码去执行输出 2
  • 输出 2 1

    • 执行 resolve 后,立即去执行 then 方法中的 result 输出 2,然后在去执行同步代码 输出 1
  • 结论:不论是否基于 THEN 注入了方法,执行 resolve/reject 的时候「修改转态和值」是同步的会立即处理,但是「通知对应注入方法执行」的这个任务是异步操作的,不会立即处理,只是把它排在等待任务队列中,当其他事情处理完,再次返回去,通知对应注入的方法执行

总结

Promise 的三大概念

  • executor 函数
    • new Promise 的时候会立即执行 executor 函数,在 executor 函数中管理了一个异步编程代码(同步代码也是OK的),此时Promise 状态是 pending;在我们异步操作成功或者失败的时候,通过执行 resolve 或者 reject 函数,可以有效的把实例改成成功状态或者失败状态,也就是从 pending 变为 fulfilled(成功)/rejected(失败);如果代码报错的情况下,也是把状态改为失败;
  • 实例
    • 每一个 Promise 实例都具备[[PromiseState]][[PromiseResult]]方法,[[PromiseState]]promise 状态:pendingfulfilled/resolverejected三种状态;[[PromiseResult]]: promise 值:默认是 undefined,一般存储成功的结果或者失败的原因。
  • Promise 原型上的方法 .then(): 用来管控成功或者失败的操作
    • 实例可以调用 .then(),它会存放两个方法:resultreason (都是函数);
      • p1 实例的状态修改为 fulfilled 的时候,通知传递的第一个函数(result)执行,result 就是[[PromiseResult]]的值;
      • p1 实例的状态修改为 rejected 的时候,通知传递的第二个函数(reason)执行,reason 就是[[PromiseResult]]的值
    • 不论是否基于 THEN 注入了方法,执行 resolve/reject 的时候「修改转态和值」是同步的会立即处理,但是「通知对应注入方法执行」的这个任务是异步操作的,不会立即处理,只是把它排在等待任务队列中,当其他事情处理完,再次返回去,通知对应注入的方法执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值