JavaScript ES6 Promise( 一)

196 阅读11分钟

JavaScript ES6 Promise( 一)

异步处理的任务

  • 这个时候,我们就以一种贴近实际开发的一个例子为主题进行探究

    • 我们平时开发的时候,避免不了的就是向我们的后端发送网络请求
    • 但是实现网络请求的时候,我们需要做的就是关于我们的根据实际的网络请求是否成功来实现对象的效果
    • 如果我们的网络请求发送成功了,那就直接进行成功的网络请求的处理
    • 如果网络请求发送失败了,那就直接进行网络请求失败的回调处理
    • 这个时候就出现了我们的 Promise 来帮助我们的处理这种存在不同的返回结果的实现

首先我们先来一个早期的异步处理的代码

function exe_code(callback_success, callback_fail, counter) {
    // 首先我们先来实现模拟一下我们的网络请求的场景
    setTimeout(() => {
        // 失败的回调处理
        if (counter <= 0) {
            callback_fail(counter)
            return
        }
​
        // 成功的时候发生的回调
        console.log("hello world")
        console.log("There is 76333's blog website")
        let total = 0
        for (let i = 0; i < 100; i++) {
            total += 1
        }
        // 在我们完成了上面的任务后,我们就告诉调用者,任务已经完成了的操作
        // 这个时候,我们就可以实现我们的在某一个时刻就实现监听,调用我们的回调函数
        callback_success(total)
    }, 3000)
}
​
// 这个时候,我们就可以传入需要进行执行的回调函数
exe_code(value => {
    console.log("任务已经完成了...", value)
}, error => {
    console.error("本次的执行失败", error)
}, -100)
  • 代码解读

    • function exe_code(callback_success, callback_fail, counter) {
          // 首先我们先来实现模拟一下我们的网络请求的场景
          setTimeout(() => {
              // 失败的回调处理
              if (counter <= 0) {
                  callback_fail(counter)
                  return
              }
      ​
              // 成功的时候发生的回调
              console.log("hello world")
              console.log("There is 76333's blog website")
              let total = 0
              for (let i = 0; i < counter; i++) {
                  total += 1
              }
              // 在我们完成了上面的任务后,我们就告诉调用者,任务已经完成了的操作
              // 这个时候,我们就可以实现我们的在某一个时刻就实现监听,调用我们的回调函数
              callback_success(total)
          }, 3000)
      }
      
      • 我们这里定义了一个用来模拟网络请求的函数 exe_code

      • 因为网络请求是需要时间的,所以说在函数的内部定义了一个定时器,来实现虚拟的模拟网络请求

      • 同时在我们的回调函数中传入三个参数,callback_success callback_fail counter

        • callback_success 就是用来模拟的是我们的成功的时候需要进行调用的回调函数
        • callback_fail 就是我们的用来模拟实现的是失败的时候的需要调用的回调函数
        • counter 用来判断我们的模拟的网络请求是否成功的一个判断器
    • exe_code(value => {
          console.log("任务已经完成了...", value)
      }, error => {
          console.error("本次的执行失败", error)
      }, -100)
      
      • 然后在后面我们实现执行代码的时候,就需要传递三个参数,一个就是成功的时候应该触发的回调函数的实现
      • 一个就是我们的失败的时候应该触发的回调函数的实现
      • 最后一个就是传入我们的用来判断的条件
  • 上面的代码格式就是我们的 ES5 之前的用来实现处理异步响应的实现的形式

    • 但是这样的模式是具有一定的痛苦的

    • 因为我们开发人员是需要进行设计这种代码的要求

    • 然后协同办公,不同人设计的代码不同,就导致后期的维护工作十分的难受

    • JavaScript 本身的缺陷,JavaScript 本身比较自由的,对传入的参数没有限制,导致后面的执行处理函数可能

      • 含有意想不到的结果
    • 所以说通过上面的劣势,就出现了现在的 PromiseTypeScript 的出现

      • Promise 来实现的是形成统一的一种处理异步的规范

      • TypeScript 对函数调用的传参起到了类型限制,同时内部的泛型编程的思想,大大的提高了代码的复用性

        • 这个思想和 C++ 的模板的泛型编程的设计十分的相似

Promise 浅入解决早期处理异步处理的代码

先来一段简单的代码,只在乎代码设计思想,不在乎是否可以实现

function exe_code(counter) {
    let is_success = {}
    setTimeout(() => {
        // 失败的回调处理
        if (counter <= 0) {
            is_success.failure("error")
            return
        }
​
        // 成功的时候发生的回调
        console.log("hello world")
        console.log("There is 76333's blog website")
        let total = 0
        for (let i = 0; i < counter; i++) {
            total += 1
        }
        is_success.success("success")
    }, 3000)
    return is_success
}
​
// 这个时候我们就可以实现的是
const res = exe_code(1000)
​
// 实现监听成功的情况
res.success(value => {
    console.log(value)
})
​
// 实现监听是被时候的回调
res.failure(error => {
    console.log(error)
})

代码解读

  • 首先定义了一个 exe_code 函数模拟发送网络请求

    • 然后内部通过定时器来模拟完成发送网络请求的形式
    • 同时在我们的模拟网络请求前先定义了一个标识来记录我们的响应是否成功
    • 然后我们的这种标识就是我们的凭证
    • 等待响应完了,就直接把响应结果实现返回
    • 外部的调用者接收到了响应结果后,通过这个响应的结果实现对成功和失败的处理分别建立监听,进行回调处理
  • 上面的代码的实现就是我们的 Promise 用来处理异步的一种设计思想了

    • 但是其中还有很多的小细节
  • 这里先说一嘴,上面的代码只是带领大家领略思想,是否可完成,这个不保证

    • 这里我给的答案就是上面的代码是不可以模拟出真实 Promise 的效果的
    • 因为这个和后面需要了解的微任务、微队列、宏任务、宏队列息息相关
    • 主要还是领略这种设计代码结构的思想

开始使用我们的 Promise 来实现这样的功能代码

function exe_code(counter) {
    const promise = new Promise((resolve, reject) => {
        console.log(counter)
        setTimeout(() => {
            // 失败的回调处理
            if (counter <= 0) {
                reject(new Error('Could not find any problem'))
                return
            }
​
            // 成功的时候的回调
            console.log("hello world")
            console.log("There is 76333's blog website")
            let total = 0
            for (let i = 0; i < counter; i++) {
                total += i
            }
            resolve(total)
        }, 3000)
    })
    return promise
}
​
​
// 这个时候我们就可以实现的是
const promise = exe_code(1000)
// 开始我们的成功时候的监听
promise.then(value => {
    console.log("成功响应...", value)
})
// 开始实现监听我们的失败的响应
promise.catch(error => {
    console.error("失败响应...", error)
})
​
​
// 如果你使用了我们的 promise 的话,实际上内部的方法是可以支持链式调用的呐
exe_code(2000).then(value => {
    console.log("成功响应...", value)
}).catch(error => {
    console.log("失败响应...", error)
})

代码解读

  • 首先我们还是实现定义了一个模拟网络请求的 exe_code 的函数
  • 该函数内部的参数列表,我们传入了关于了一些进行决定是否成功的形参
  • 然后我们的更新的就是把我们的标识变成了我们的 Promise

Promise 对象特点的浅谈

  • Promise 是JavaScript 为我们提供的一种用来实现处理异步操作的 API

  • 其本身是一个对象的,同时我们在构建我们的 Promise 对象的时候,我们是可以发现一点的是内部需要我们传入回调函数

  • 回调函数的话一般是具备我们的两个参数的

    • 第一个参数就是我们的后面的操作响应成功的时候设置的回调函数形参,但是为了规范,一般的命名是 resolve
    • 第二个参数就是我们的后面的操作失败的时候设置的回调函数形参,但是为了规范,一般的命名时 reject
  • 同时设置了 Promise 的时候,回调函数内部的代码实现的是自动运行

调用者对象该进行的处理

  • 我们的 Promise 异步操作的调用者的监听模式含有两种

    • 第一种就是实现分别对成功和失败进行监听

    • 第二种就是我们的实现对失败或者成功实现链式的监听模式

      • 这里的话,不知道大家使用过数组的一系列方法没有,数组的一些方法也是可以支持链式调用的

      • 为什么会有这种效果呐???

      • 这里我浅浅的说一下把:

        • 这样的效果的实现就是因为某个对象调用了某种方法后,实际上该方法内部实现的是返回了一个一样的对象
        • 就是因为这种机制,就可以实现连续的链式调用
    • Promise 的 实例对象的then 方法,实现的是对我们的成功的响应实现的监听

    • Promise 的 实例对象的 catch 方法,实现的是对我们的失败的响应实现的监听

    • 关于 Promise 的更多的详细分析,后面再来解释吧!!!

实际上的话,我们当前的代码还是具有一定的不足的,因为现在的编译器会自动的给你提示,能够写在一行的代码就写在一行

image-20241122034052668.png

修正后的代码为:

function exe_code(counter) {
    return new Promise((resolve, reject) => {
        console.log(counter)
        setTimeout(() => {
            // 失败的回调处理
            if (counter <= 0) {
                reject(new Error('Could not find any problem'))
                return
            }
​
            // 成功的时候的回调
            console.log("hello world")
            console.log("There is 76333's blog website")
            let total = 0
            for (let i = 0; i < counter; i++) {
                total += i
            }
            resolve(total)
        }, 3000)
    })
}

Promise 更多的细节

Promise 三大状态

new Promise((resolve, reject) => {
    // 通过我们的调换这两个决定 Promise 状态的回调,从而来实现决定后面的回调的执行
    reject(false)
    
    resolve(true)
    
}).then(value => {
    
    console.log("异步响应结果是成功的...", value)
    
}).catch(error => {
    
    console.error("异步响应结果是失败的...", error)
})

代码解读

  • 从整体的代码来看,我们先实现创建了一个 Promise 对象,然后设置了其中的回调函数,同时实现了后面的链式调用

  • 回调函数的设置: resolvereject 参数(注意这里一定是看参数的位置,不是看参数的名称)

    • resolve 是用来决定我们的 Promise 后面的状态是成功的状态
    • reject 是用来决定我们的 Promise 后面的状态是失败的状态
  • .then() 方法的调用时机,就是实现的是我们的 Promise 的状态是成功的时候,会触发调用的回调函数

  • .catch() 方法的调用时机,就是实现的是我们的 Promise 的状态是失败的时候,会触发调用的回调函数

  • 这里还需要注意的一点是,我们的 Promise 的状态一旦确定,后面就不可以进行修改了,一次性用品😄😄😄

那么通过上面的讲述后,我们的 Promise 到底具备那些状态呐???

  • 待定(pending) :这个就是初始状态,就是说明我们的 Promise 的状态还没有被确定,还正在等待处理中
  • 已兑现(fulfilled) : 这个就是我们的成功的状态,就是执行 Promise 回调函数形参一后确定的状态
  • 已拒绝(rejected) : 这个就是失败的状态,就是执行了 Promise 回调函数形参二后确定的状态
  • 同时需要注意一点的是,我们的 Promise 的状态一旦被确定了,就不可修改了

image-20241122040840929.png

image-20241122041051692.png

image-20241122041235595.png

image-20241122042517513.png

Promise Executor

该函数是我们的创建 Promise 的实例化对象的时候需要传入的回调函数

当我们一旦创建了一个 Promise 对象后,我们的这个回调函数会被立即执行

image-20241122042517513.png

Promise Executor 第一个参数的值(resolve)

我们在使用 Executor 的第一个参数的时候,我们是可以传入一个值的,基本上的话所有的 JavaScript 数据类型都可以传入

该值是为了实现我们的后面调用 then 方法时候,内部的回调函数参数接收的值

这个时候的话,我们在平时的练习中就可以直接实现天马行空了,想怎么实践就怎么实践 😄 😄 😄

Promise then 方法的细节

then 方法本身是可以接收两个参数的,

  • 一个就是 Promise 状态为 fulfilled 的时候执行的回调
  • 一个就是 Promise 状态为 rejected 的时候执行的回调
  • 如果我们这样进行书写,实际上后面链式调用的 .catch 的调用就没啥必要继续书写了
const promise = new Promise((resolve, reject) => {
    reject(false)
    resolve(true)
})
​
promise.then(res => {
    console.log(res)
}, err => {
    console.log(err)
})
​
// 上面的代码等价于
// 推荐下面的这种写法,结构更加清晰吧!!!
promise.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

.then.catch 实际上的话都是具备两个参数的

但是不同的是(了解即可!!!)

  • .then 首先捕获的是我们的成功的回调,然后才是失败
  • .catch 先捕获的是我们的失败,然后才是成功

总结

我们在该部分中,我们实现了解 Promise 的经常使用的一些方法,从 ES5 之前的前端处理异步的操作作为切入点开始,

后面再引入到我们的 Promise 对象实现处理异步操作的方式,最后补充了一些实现 Promise 的细节!!!