实现Promise所有核心功能和方法

news2024/9/29 11:42:18

一直以来对Promise只是会用简单的方法,例如then,catch等,对于其余各种方法也只是简单了解,这次想要通过实现Promise来加深对Promise的使用

话不多说,直接开始,简单粗暴一步步来

一:了解Promise

1.1 什么是Promise

Promise是一种用于处理异步操作的JS对象,可以通过链式调用的方式来处理操作的结果

使Promise可以更加优雅地处理异步代码,避免回调地狱的产生

1.2 Promise的三种状态

  • Pending(进行中):初始状态,表示操作尚未完成
  • Fulfilled(已完成):表示操作成功完成
  • Rejected(已拒绝):表示操作失败

1.3 示例

通过示例来了解Promise的基本用法

    const p = new Promise((resolve, reject) =>
    {
        resolve(1)
    })

    const p2 = p.then(res =>
    {
      console.log(res)  // 1
      throw 'xxx'
    })

    p2.catch(error =>
    {
      console.log(error); //xxx
    })
  • 通过 new Promise创建一个Promise实例对象,在构造函数中传入一个执行器函数,该函数接收两个参数
    • resolve函数:如果操作成功,调用resolve函数并传递结果
    • reject函数:如果调用失败,或抛出错误,调用reject函数并传递错误信息
  • 通过Promise的实例对象上的 then方法,可以指定操作成功时所要执行的回调函数
  • 通过 catch方法,可以指定操作失败时候要执行的回调函数
    • 在上述代码中,调用resolve函数,更改为成功状态并传递结果1
    • 通过调用p实例上的then方法来接收传递的结果,res接收到的结果即是1,并自定义回调函数,在回调函数中抛出错误信息'xxx',并使用p2来接收p.then的返回值
    • p2实际也是一个Promise实例,因为promise支持链式调用,返回值也是一个promise对象,那么p.then中抛出的错误会被p2实例身上的catch方法捕获
    • 最终通过 catch方法打印对应的错误信息

状态变化

  • 执行器函数执行 resolve(1),会将p实例对象的状态由 Pending转为 Fulfilled状态,即由待定状态转为成功状态
  • 在p实例的then回调函数中,抛出错误信息xxx,由于异常未被捕获,p2对象状态被设置为 Rejected,p2实例的catch方法会根据此时p2实例的状态捕获错误信息xxx

then方法

  • 实际上,Promise对象的 then方法会根据实例的不同状态执行不同的处理方法
  • then方法接收两个可选参数, onFulfiedonRejected,分别表示成功时和失败时的回调函数
    • 当Promise对象的状态为Fulfilled(已完成)时, then方法会立即执行 onFulfilled回调函数,并将操作结果作为参数传递给该函数。
    • 当Promise对象的状态为Rejected(已拒绝)时, then方法会立即执行 onRejected回调函数,并将拒绝原因(错误信息)作为参数传递给该函数。
    const p = new Promise((resolve, reject) =>
    {
      resolve(1)
      // reject('xxx')
    })

    p.then(res =>
    {
      console.log(res)  // 1
    }, error =>
    {
      console.log(error);
    })
  • 该代码,如果执行resolve函数,状态会被改为Fulfilled(已完成),那么就会执行then方法中的第一个回调函数,并将1传递给res
  • 如果执行reject函数,状态会被改为Rejected(已拒绝),执行第二个回调函数,并将xxx传递给error
  • 在之前的代码中,catch方法的功能和执行 onRejected回调函数(第二个参数的回调函数)是一致的,都是用于当实例对象为 Rejected状态时候,执行对应的回调函数,并将错误信息作为参数传递给该函数
    • 在MDN中有说明,此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式

二:实现Promise核心功能

了解Promise的基本使用过后,那么就可以来一步步去实现一个Promise,先去实现Promise的核心功能*

  • 「构造函数」:通过class创建 MyPromise类,接收执行器函数(resolve/reject)并执行
  • 「更改状态和原因」:通过resolve和reject函数去更改实例对象的状态,并将原因(操作结果)作为参数传递
  • 「初步实现then方法」:添加实例then方法,并判断传入then方法的参数类型,设置成功和失败的回调函数
  • 「支持异步操作和多次调用」:设置数组存储回调函数来实现多次通过实例调用then方法(非链式调用),通过设置异步函数来处理异步调用resolve/reject
  • 「then的异步执行」
  • 「then的链式调用」:返回MyPromise实例,异常处理,获取then的返回值,对于不同的返回值做出不同处理

2.1 构造函数

    class MyPromise
    
{
      // 1. 添加构造函数
      constructor(func)
      {

        // 2. 定义resolve/reject
        const resolve = (result) =>
        {
          console.log(result) //success
        }
        const reject = (result) =>
        {
          console.log(result)
        }

        // 3. 执行回调函数
        func(resolve, reject)
      }
    }

    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
      // reject('error')
    })
  • 创建构造函数,并由 func接收传入的回调函数
  • 设置回调函数的两个参数,resolve,reject函数
  • 执行func回调函数

2.2 更改状态和设置原因

    //1. 设置三种状态
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'

    class MyPromise
    
{
      constructor(func)
      {
        //2. 设置result存储原因 /初始化状态
        this.state = PENDING
        this.result = undefined
        const resolve = (result) =>
        {
          //3. 通过resolve/reject修改状态
          //注意判断状态条件 使得状态不可逆
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
          }
        }
        const reject = (result) =>
        {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
          }
        }
        func(resolve, reject)
      }
    }

    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
      reject('error')
    })
  • 设置三种状态,pending,fufilled,rejected。
  • 初始化实例状态为pending
  • 设置result变量存储resolve、reject传递过来的结果
  • 执行resolve、reject函数时候,修改状态
  • 注意状态的不可逆,状态只能由pending -> fulfilled或者pending -> rejected,不可以从fulfilled -> rejected,条件判断一下, 即便resolve,reject都执行了,实例状态还是由第一个执行的函数改变
    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
      reject('error')
    })
image-20231010132809495
image-20231010132809495

2.3 初步实现then方法

  class MyPromise
    
{
      constructor(func)
      {
        //...
      }

      // 1. 添加实例方法
      then (onFulfilled, onRejected)
      {
        // 2. 参数判断
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }

        // 2.1 执行成功回调
        // 2.2 执行失败回调
        if (this.state === FULFILLED) {
          onFulfilled(this.result)
        } else if (this.state === REJECTED) {
          onRejected(this.result)
        }
      }
    }

    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
      // reject('error')
    })

    p.then(res =>
    {
      console.log('p1:', res) // p1: success
    })
  • 添加实例then方法,接收两个参数,一个执行 成功的回调函数onFulfilled,一个执行 失败的回调函数onRejected
  • 作为调用者,对then方法的参数可能设置有不同形式,可能是简单的变量或是正确的回调函数形式,因此在then方法内部需要对传递过来的参数进行一个判断
  • 使用 typeof关键字对参数类型进行判断,对于onFulfilled和onRejected,如果是回调函数都不做处理
    • onFulfilled如果不是回调函数,其内部转化为一个恒等函数((x) => x),只是简单的把值传递一下,也没有什么处理
    • mdn上这么说:如果 onFulfilled 不是一个函数,则内部会被替换为一个 恒等函数( (x) => x),它只是简单地将兑现值向前传递。
    • onRejected如果不是回调函数,对其抛出其拒绝的原因
    • mdn上这么说:如果 onRejected 不是一个函数,则内部会被替换为一个 抛出器函数( (x) => { throw x; }),它会抛出它收到的拒绝原因
  • 关键在于状态判断:根据实例的状态来执行不同的回调函数
    • FULFILLED状态:执行第一个回调函数onFulfilled回调,并把 原因(结果),传递给 then方法的 参数
    • REJECTED状态:执行第二个回调函数onRejected回调,并把 原因(结果),传递给 then方法的 参数
  • 通过以上处理,then方法就可以正确调用,并可以根据不同状态执行不同的回调函数,来接收对应的结果

2.4 支持异步操作和多次调用

此时then方法为同步

    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
    })

    p.then(res =>
    {
      console.log('p1:', res)  //p1: success
    })
  • 根据目前我们实现的代码,通过调用resolve函数改变实例状态,通过then方法根据状态处理不同的结果,成功打印success
  • Promise是支持异步操作resolve/reject函数,如果使用我们的代码直接设置异步操作,能否正确输出结果呢?
    const p = new MyPromise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('success')

      }, 2000);
    })

    p.then(res =>
    {
      console.log('p1:', res)
    })
image-20231010141014499
image-20231010141014499
  • 为什么无法正常输出呢?设置一个定时器异步操作resolve为什么就无法在then方法中正确处理结果呢?在控制台打印一下此时的实例状态
image-20231010141146295
image-20231010141146295
  • 很明显,p的状态根据设置定时器,初始为pending,定时器结束后,执行resolve设置为fulfilled状态,那么想到此时的 then方法是同步的,它不会等到定时器结束才执行
  • 一开始实例状态是pending,直接执行了then方法,但我们没有在then方法中对pending状态做出处理,也就没有正确执行回调,所以就什么都没有了
  • 那么怎么正确处理呢? 先保存此时的回调和结果,等状态改变了再执行

    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'

    class MyPromise
    
{
      constructor(func)
      {
   //...
        //保存成功的回调函数
        this.onResolveCallbacks = []
        //保存失败的回调函数
        this.onRejectCallbacks = []
        const resolve = (result) =>
        {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            //遍历执行保存的回调函数
            this.onResolveCallbacks.forEach(fn => fn())
          }
        }
        const reject = (result) =>
        {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            //遍历执行保存的回调函数
            this.onRejectCallbacks.forEach(fn => fn())
          }
        }
        func(resolve, reject)
      }

      then (onFulfilled, onRejected)
      {
       //...

        if (this.state === FULFILLED) {
          onFulfilled(this.result)
        } else if (this.state === REJECTED) {
          onRejected(this.result) 
        } else if (this.state === PENDING) {
          //PENDING状态处理
          this.onResolveCallbacks.push(() =>
          {
            onFulfilled(this.result)
          })
          this.onRejectCallbacks.push(() =>
          {
            onRejected(this.result)
          })
        }
      }
    }


    const p = new MyPromise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('success')

      }, 2000);
    })

    p.then(res =>
    {
      console.log('p1:', res) //p1: success
    })
  • 添加两个数组用于存储执行成功和失败的回调函数,在状态为pending的时候先添加到对应数组中
  • 等待调用resolve/reject改变状态后,再依次从数组中取出对应成功or失败的回调函数并执行
  • 对于多次调用 then方法,由于我们用数组存储回调函数,即可以多次调用then方法了(非链式调用)
    const p = new MyPromise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('success')

      }, 2000);
    })

    p.then(res =>
    {
      console.log('p1:', res)
    })
    p.then(res =>
    {
      console.log('p1:', res)
    })
    p.then(res =>
    {
      console.log('p1:', res)
    })
  • 这次就成功打印结果了
image-20231010142108496
image-20231010142108496

2.5 then的异步执行

在2.4中,我们实现了异步操作resolve/reject,能够成功处理对应结果,但当时的then方法还是同步的

在Promise中

then方法是异步的

    console.log(1);
    const p1 = new Promise((resolve, reject) =>
    {
      resolve('success')
    })

    p1.then(res =>
    {
      console.log(res);
    })

    console.log(2);

执行结果为: 1 2 success

在MyPromise中

我们未对then方法的调用处理异步,此时还是同步的

    console.log(1);
    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
    })

    p.then(res =>
    {
      console.log('p1:', res)
    })

    console.log(2);

执行结果为:1 p1: success 2

使用settimeout处理异步

then (onFulfilled, onRejected)
      {
        //...
        if (this.state === FULFILLED) {
          setTimeout(() =>
          {
            onFulfilled(this.result)

          }, 0);
        } else if (this.state === REJECTED) {
          setTimeout(() =>
          {
            onRejected(this.result)

          }, 0);
        } else if (this.state === PENDING) {
          //执行回调
          this.onResolveCallbacks.push(() =>
          {
            setTimeout(() =>
            {
              onFulfilled(this.result)
            }, 0);
          })
          this.onRejectCallbacks.push(() =>
          {
            setTimeout(() =>
            {
              onRejected(this.result)
            }, 0);
          })
        }
      }
    }
  • 通过 setTimeout 方法将 then 方法的执行放到宏任务中执行,在同步任务执行完毕后,then 方法才会被调用

2.6 then的链式调用

对于then的链式调用即需要实现很多关键点

  • 返回一个新的MyPromise实例可以继续调用then方法
  • 获取实例的返回值并处理异常
  • 对于不同返回值做出不同的处理
    • 普通返回值
    • 返回值是MyPromise实例
    • 返回值是对应的实例(重复引用)即该抛出错误
  • 对于三种状态统一进行处理

返回一个新实例

    then (onFulfilled, onRejected)
    {
  //...
        const p2 = new MyPromise((resolve, reject) =>
        {
          //...
        })
        return p2
    }
    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
    })

    p.then(res =>
    {
      console.log('p1:', res)
      return 1
    }).then(res =>
    {
      console.log('p2:', res)
    })
image-20231010144315841
image-20231010144315841
  • 可以链式调用then方法不会报错,但是第二个then方法明显无法第一个then方法的返回值,说明未对第一个实例的返回值进行处理

  • 在Promise中,第一个then方法的返回值会传递给第二个链式调用的then方法的第一个回调函数的参数,即第二个then应该打印p2: 1

获取实例的返回值并对异常做出处理

   then (onFulfilled, onRejected)
      {
        //...
        const p2 = new MyPromise((resolve, reject) =>
        {
          if (this.state === FULFILLED) {
            setTimeout(() =>
            {
              try {
                const res = onFulfilled(this.result)
                //将实例返回值传递给下一个then方法的onFulfilled回调函数
                resolve(res)
              } catch (error) {
                //处理异常 将错误信息传递给下一个then方法的onRjected回调函数
                reject(error)
              }
            }, 0);
          } 
        //...
        return p2

      }
    }
    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
    })

    p.then(res =>
    {
      console.log('p1:', res)
      return 1
    }).then(res =>
    {
      console.log('p2:', res)
    })
  • 获取onFulfilled回调函数的返回值,即是then方法中第一个函数的返回值
  • 异常处理,在then方法中,可能会抛出各种异常错误,因此需要利用try catch对异常做出处理
    • 没有异常,就调用resolve函数,将返回值传递给下一个then方法的onFulfilled回调函数
    • 有异常,就调用reject函数,将error捕获的错误传递给下一个then方法的onRejected回调函数
image-20231010145538010
image-20231010145538010
  • then方法中抛出错误
    p.then(res =>
    {
      console.log('p1:', res)
      throw 'xxxx'
      return 1
    }).then(res =>
    {
      console.log('p2:', res)
    }, error =>
    {
      console.log('p2:', error)
    })
image-20231010145657224
image-20231010145657224

当返回值为MyPromise实例

 then (onFulfilled, onRejected)
      {
        //...

        const p2 = new MyPromise((resolve, reject) =>
        {
          if (this.state === FULFILLED) {
            setTimeout(() =>
            {
              try {
                const res = onFulfilled(this.result)
                //1. 处理返回MyPromise实例
                if (res instanceof MyPromise) {
                  res.then(res => resolve(res), error => reject(error))
                } else {
                  //将实例返回值传递给下一个then方法的onFulfilled回调函数
                  resolve(res)
                }
              } catch (error) {
                //处理异常 将错误信息传递给下一个then方法的onRjected回调函数
                reject(error)
              }
            }, 0);
           //...
          } 
        })
        return p2

      }
    }
 
    const p = new MyPromise((resolve, reject) =>
    {
      resolve('success')
    })

    p.then(res =>
    {
      console.log('p1:', res)
      return new MyPromise((resolve, reject) =>
      {
        resolve(2)
        // reject('error')
      })
    }).then(res =>
    {
      console.log('p2:', res)  //2
    }, error =>
    {
      console.log('p2:', error)
    })
  • 当第一个then方法返回值如果是MyPromise实例的时候
  • 我们利用 instanceof关键判断,res获取的返回值是否是MyPromise实例,如果是该实例
  • 通过then方法先获取对应的结果,再通过resolve/reject将结果传递给下一个then方法的回调函数

当返回值和接受返回值的实例一致(重复引用)

const p2 = new MyPromise((resolve, reject) =>
        {
          if (this.state === FULFILLED) {
            setTimeout(() =>
            {
              try {
                const res = onFulfilled(this.result)

                // 处理重复引用
                if (res === p2) {
                  throw new TypeError('Chaining cycle detected for promise #<Promise>')
                }
                //处理返回MyPromise实例
                if (res instanceof MyPromise) {
                  res.then(res => resolve(res), error => reject(error))
                } else {
                  //将实例返回值传递给下一个then方法的onFulfilled回调函数
                  resolve(res)
                }
              } catch (error) {
                //处理异常 将错误信息传递给下一个then方法的onRjected回调函数
                reject(error)
              }
            }, 0);
          } 
     //...
        })
        return p2
 const p2 = p.then(res =>
    {
      console.log('p1:', res)
      return p2
    })
    p2.then(res =>
    {
      console.log('p2:', res)
    }, error =>
    {
      console.log('p2:', error)
    })
  • 当p2 接收then方法的返回值时,返回值也是p2,在Promise中会直接抛出错误
  • 因此我们也需要判断res 和 p2是否一致,如果一致就是重复引用,直接抛出错误,有catch捕获错误,并利用reject传递给下一个then方法中的onRejected回调函数中
image-20231010151110175
image-20231010151110175

抽离函数

  • 我们不仅需要在实例状态为onFulfilled时候,对返回值进行处理,对于其余两个状态也是需要相同的处理,为了实现代码复用,将上述处理过程抽离成一个函数
  • 在三种状态中依次调用该方法
 //封装函数 处理then方法
    function resolvePromise (p2, res, resolve, reject)
    
{
      //1. 重复引用 直接抛出错误
      if (res === p2) {
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      //2. 返回值是MyPromise实例 利用then获取对应的resolve/reject的值
      if (res instanceof MyPromise) {
        res.then(res => resolve(res), error => reject(error))
      } else {
        //3.处理普通返回值
        resolve(res)
      }
    }
 //then方法 两个参数 onFulfilled, onRejected
      then (onFulfilled, onRejected)
      {
  //...
        const p2 = new MyPromise((resolve, reject) =>
        {
          if (this.state === FULFILLED) {
            setTimeout(() =>
            {
              try {
                //...
                resolvePromise(p2, res, resolve, reject)
              } 
            }, 0);
          } else if (this.state === REJECTED) {
            setTimeout(() =>
            {  
              try {        
                //...
                resolvePromise(p2, res, resolve, reject)
              }
            }, 0);
          } else if (this.state === PENDING) {
            this.onResolveCallbacks.push(() =>
            {
              setTimeout(() =>
              {
                try {
                  //...
                  resolvePromise(p2, res, resolve, reject)
                }
              }, 0);
            })
   
            this.onRejectCallbacks.push(() =>
            {
              setTimeout(() =>
              {
                try {
                  //...
                  resolvePromise(p2, res, resolve, reject)
                } 
              }, 0);
            })
          }
        })
        return p2
      }

三:实现Promise实例方法

核心功能实现之后,开始去实现,Promise实例上的方法

3.1 catch方法

在之前的示例中有出现过catch方法的示例,也大体讲解了下catch方法与then方法之间的联系与关系

引用MDN中对catch方法的论述:

  • Promise 实例的 catch() 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你 链式调用其他 promise 的方法
  • 此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式

总结一下

catch方法等同于then(undefined, onRejected)

  • catch() 方法用于捕获并处理 Promise 实例的拒绝状态。当 Promise 实例被拒绝时, catch() 方法会被调用,并传递拒绝的原因作为参数。
  • 返回一个 Promise实例

实现

参数(onRejected):一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值

返回值:返回一个新Promise,新Promise在返回时总处于待定状态

      catch (onRejected)
      {
        return this.then(undefined, onRejected)
      }
    const p = new MyPromise((resolve, reject) =>
    {
      reject('error')
    })

    p.then(res =>
    {
      console.log(res)
    }).catch(error =>
    {
      console.log('p:', error); //p: error
    })

3.2 finally方法

Promise 实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法。

如果你想在 promise 敲定时进行一些处理或者清理,无论其结果如何,那么 finally() 方法会很有用。

总结一下

  • 无论该Promise实例最终是被成功兑现(resolve),还是被拒绝(reject),finally方法都会被调用
  • 返回一个Promise实例

实现

参数(onFinally):回调函数

返回值:返回一个Promise实例

      //finally方法
      finally (onFinally)
      {
        return this.then(onFinally, onFinally)
      }
    const p = new MyPromise((resolve, reject) =>
    {
      // reject('error')
      resolve('success')
    })

    p.then(res =>
    {
      console.log(res)
    }).catch(error =>
    {
      console.log('p:', error);
    }).finally(() =>
    {
      console.log(1); // success 1
    })
  • 无论是成功的兑现resolve('success'),还是拒绝reject('error'),最终都会调用finally函数并执行其中的回调函数

四:实现Promise静态方法

Promise还提供了一些静态方法,是在构造函数上调用的,而不是在实例上调用的

4.1 resolve方法

Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数

Promise中的resolve方法

    const p = Promise.resolve(1)
    console.log(p);
    p1 = Promise.resolve(p)
    console.log(p1);
image-20231010203520862
image-20231010203520862
  • Promise.resolve,将给定的1转化为了一个Promise对象
  • 如果再把一个Promise对象传递给Promise.resolve中,它不会继续封装该Promise,而是将这个Promise对象返回

思路

  • 当接收的值是一个Promise对象时候,直接返回该对象
  • 否则,返回一个新Promise对象,并调用resolve,兑现对应的值

实现

参数(value):resolve方法接收的值,可能为MyPromise

返回值:MyPromise

      static resolve (value)
      {
        //是一个MyPromise直接返回
        if (value instanceof MyPromise) {
          return value
        }

        //其余转化为MyPromise并返回
        return new MyPromise(resolve =>
        {
          resolve(value)
        })
      }
  • 利用instanceof关键字判断value是否为一个MyPromises实例,如果是,直接返回该MyPromise
  • 返回一个Promise实例,并调用resolve兑现该值, 即该实例状态直接被转为fulfilled
    const p = MyPromise.resolve(1)
    console.log(p);
    const p1 = MyPromise.resolve(p)
    console.log(p1);
image-20231010204409551
image-20231010204409551

4.2 reject方法

Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。

这个说的就很清楚

  • 返回一个Promise对象
  • 调用reject更改状态为rejected拒绝,并把原因传递过去

实现

参数(value):该 Promise 对象被拒绝的原因。

返回值:Promise对象

      static reject (value)
      {
        //直接返回一个Promise
        return new MyPromise((undefined, reject) =>
        {
          reject(value)
        })
      }

    const p = MyPromise.reject('error')
    p.catch(error =>
    {
      console.log(error);
    })
image-20231010204846632
image-20231010204846632

4.3 race方法

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

总结一下

  • 接收一个promise可迭代对象,例如为数组,元素都为promise
  • 数组中的所有promise实例进行竞争,谁敲定的最快(状态改变的最快),就返回谁的Promise实例

在promise中

    const p1 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('p1')
      }, 1000);
    })

    const p2 = 'p2'
    const p3 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        reject('p3')
      }, 3000);
    })
    const p = Promise.race([p1, p2, p3])
    p.then(res =>
    {
      console.log(res);
    }).catch(error =>
    {
      console.log(error);
    })
image-20231010205639328
image-20231010205639328
  • 设定两个Promise实例和一个基本类型值,p1实例设置定时器1秒后兑现结果,p2为基本类型值'p2',p3设置一个定时器3秒后拒绝
  • 调用Promise.race()方法,并把p1,p2,p3作为数组传递race方法
  • race方法内部,会先将不是promise对象转化为promise对象,然后所有Promise实例进行竞争,显然没有设置定时器的p2实例最快,返回p2实例
  • 最终通过then方法兑现对应的结果
image-20231010210252921
image-20231010210252921

思路

  • 接收一个数组,元素都为Promise实例,那么如果接受的不是数组呢?抛出错误
  • 返回值为一个Promise实例
  • 遍历数组,把不是Promise实例的转化为Promise实例
  • 等待第一个Promise的敲定(状态改变)

实现

参数(iterable):可迭代对象,例如数组

返回值:Promise

 static race (promises)
      {
        //返回一个promsie
        return new MyPromise((resolve, reject) =>
        {
          //如果参数不是一个数组直接抛出错误
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }

          //遍历数组等待第一个敲定
          promises.forEach(p =>
          {
            //由于p不一定是一个promise 先转化为promise 
            MyPromise.resolve(p).then(res =>
            {
              resolve(res)
            }, error =>
            {
              reject(error)
            })
          })
        })
      }
  • 首先返回一个MyPromise实例,在其中写对应逻辑
  • 利用Array.isArray方法判断是否为一个数组,不是数组抛出错误
  • 遍历数组,通过resolve方法将不是Promise实例转化为Promise实例
  • 调用then方法,接收Promise实例敲定后传递的结果或拒绝的原因
  • 谁最先敲定(改变状态),谁直接调用resolve/reject把结果或原因返回

4.4 all方法

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

总结一下

  • 跟race方法接收参数形式一样,都是一个数组,元素为Promise实例
  • 返回值为一个Promise实例
  • 等所有的Promise实例全部都被兑现了,并将兑现的值按照Promise传入数组的位置,依次存放到一个数组中
  • 最后将返回值的Promise实例兑现,并把这个结果数组传递
  • 只要其中有Promise拒绝了,那么返回的Promise就被拒绝,并把原因传递

在Promise中

    const p1 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('p1')
      }, 1000);
    })

    const p2 = 'p2'
    const p3 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('p3')
      }, 3000);
    })
    const p = Promise.all([p1, p2, p3])
    p.then(res =>
    {
      console.log(res);
    }).catch(error =>
    {
      console.log(error);
    })
image-20231010212126512
image-20231010212126512
  • 当数组中的所有Promise实例全部被兑现,兑现的值也会按照对应位置存放在一个数组中
  • 等所有Promise实例都被兑现了,最终兑现返回的promise实例,并把这个结果数组传递
const p1 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('p1')
      }, 1000);
    })

    const p2 = 'p2'
    const p3 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        reject('p3')
      }, 3000);
    })
    const p = Promise.all([p1, p2, p3])
    p.then(res =>
    {
      console.log(res);
    }).catch(error =>
    {
      console.log(error);
    })
  • 但如果只要有一个promise实例被拒绝了,返回的promise直接拒绝
image-20231010213455910
image-20231010213455910

思路

  • 判断参数,是否是一个数组,不是数组就抛出错误
  • 返回一个Promise实例
  • 如果是空数组,直接兑现
  • 遍历数组,把数组中不是Promise实例的转化为Promise实例
    • 维护一个数组和一个计数器
    • 遍历数组,等待所有Primose兑现
    • 通过索引记录兑现值在数组中的位置,保证跟参数中顺序一致
    • 利用计数器计数,等待所有promise实例兑现

实现

static all (promises)
      {
        //返回一个promise
        return new MyPromise((resolve, reject) =>
        {
          //不是数组抛出错误
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }

          //空数组直接兑现
          promises.length === 0 && resolve(promises)

          const result = []
          let count = 0
          //foreach取出全部的promise
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              //记录结果
              result[index] = res
              //判断全部兑现 传递result
              count++
              count === promises.length && resolve(result)
            }, error =>
            {
              //处理拒绝
              reject(error)
            })
          })

        })
      }
  • 还是利用Array.isArray方法判断参数是否为一个数组
  • 判断参数数组是否为空数组,空数组直接兑现,并把空数组传递
  • 遍历数组中,利用resolve方法把不是promise实例的元素转化为priomise实例
  • 通过result[index]索引记录对应的promise实例的兑现值
  • count计数器等所有的promise实例兑现,最后传递result数组

4.5 allSettled方法

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组

总结一下

  • 接受参数和返回值与all方法类似
  • 等全部promise实例敲定时(all方法是兑现时),也就意味着allSettled方法允许出现被拒绝时的状态,不会像all方法一样被拒绝时,返回值也直接被拒绝

在promise中

 const p1 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        resolve('p1')
      }, 1000);
    })

    const p2 = 'p2'
    const p3 = new Promise((resolve, reject) =>
    {
      setTimeout(() =>
      {
        reject('p3')
      }, 3000);
    })
    const p = Promise.allSettled([p1, p2, p3])
    p.then(res =>
    {
      console.log(res);
    }).catch(error =>
    {
      console.log(error);
    })
image-20231010213350301
image-20231010213350301
  • 与all方法不同的是,当数组中的promise实例有被拒绝的状态的时候,返回的promise也不会直接被拒绝,而是会把这个状态记录,原因传递,其余promise继续兑现
  • 同时,与all方法不同的是,最终传递的结果数组中是以对象形式
    • status为fulfilled状态时候,另个属性就是value,兑现值
    • statue为rejected状态时候,另个属性就是reason,拒绝原因
  • 但大体内层逻辑与all方法大体相同

实现

      //settled方法
      static allSettled (promises)
      {
        //返回promise
        return new MyPromise((resolve, reject) =>
        {
          //判断数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }
          // 为空
          promises.length === 0 && resolve(promises)

          const result = []
          let count = 0
          //遍历数组
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              //记录
              result[index] = { status: FULFILLED, value: res }
              count++
              count === promises.length && resolve(result)
            }, error =>
            {
              result[index] = { status: REJECTED, reason: error }
              count++
              count === promises.length && resolve(result)
            })
          })
        })
      }
  • 与all方法不同的是
  • 在兑现或拒绝每个promise实例的时候,对于索引记录下是以对象形式存入数组中
  • 无论兑现还是拒绝,利用计数器等到全部promise敲定之后再将返回值敲定,并把结果数组传递

4.6 any方法

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

总结一下

  • 接收参数和返回值与all方法类似
  • 但有种像all方法反过来的感觉
  • 只要有一个promise兑现,返回值promise立即兑现
    • all方法是只要有一个promise被拒绝,返回值promise直接被拒绝
  • 只有当全部promise实例都被拒绝时候,返回值promise才会被拒绝,并传递一个拒绝原因的数组

实现

static any (promises)
      {
        // 1. 返回Promise,数组判断
        return new MyPromise((resolve, reject) =>
        {
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }
          // 2. 空数组直接拒绝
          promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))

          // 3. 等待结果
          const errors = []
          let count = 0
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              // 3.1 第一个兑现
              resolve(res)
            }, err =>
            {
              // 3.2 全部拒绝
              errors[index] = err
              count++
              count === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))
            })
          })
        })
      }
    }
  • 逻辑上是all方法的反过来

五:完整代码

   function resolvePromise (p2, res, resolve, reject)
    
{
      //1. 重复引用 直接抛出错误
      if (res === p2) {
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      //2. 返回值是MyPromise实例 利用then获取对应的resolve/reject的值
      if (res instanceof MyPromise) {
        res.then(res => resolve(res), error => reject(error))
      } else {
        //3.处理普通返回值
        resolve(res)
      }
    }

    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'

    class MyPromise
    
{
      constructor(func)
      {
        //初始状态pending 
        this.state = PENDING
        //初始原因undefined
        this.result = undefined
        //保存成功的回调函数
        this.onResolveCallbacks = []
        //保存失败的回调函数
        this.onRejectCallbacks = []
        //更改状态
        const resolve = (result) =>
        {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            //遍历执行保存的回调函数
            this.onResolveCallbacks.forEach(fn => fn())
          }
        };
        const reject = (result) =>
        {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            //遍历执行保存的回调函数
            this.onRejectCallbacks.forEach(fn => fn())
          }
        };
        //捕获错误
        try {
          //执行函数
          func(resolve, reject)
        } catch (error) {
          reject(error)
        }

      }
      //then方法 两个参数 onFulfilled, onRejected
      then (onFulfilled, onRejected)
      {
        //参数判断
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error }

        //链式调用 返回新的promise实例
        const p2 = new MyPromise((resolve, reject) =>
        {
          //根据状态执行成功失败的回调
          if (this.state === FULFILLED) {
            //并把失败的原因传递过去
            setTimeout(() =>
            {
              //处理异常  调用reject并把异常传过去
              try {
                //res为p1的返回值 判断是否为promise
                const res = onFulfilled(this.result)
                resolvePromise(p2, res, resolve, reject)
              } catch (error) {
                reject(error)
              }

            }, 0);
          } else if (this.state === REJECTED) {
            setTimeout(() =>
            {
              //使用try catch捕获错误
              try {
                //获取p1返回值 
                const res = onRejected(this.result)
                resolvePromise(p2, res, resolve, reject)

              } catch (error) {
                reject(error)
              }
            }, 0);
          } else if (this.state === PENDING) {
            //保存成功的回调
            this.onResolveCallbacks.push(() =>
            {
              setTimeout(() =>
              {
                //处理异常
                try {
                  //获取返回值
                  const res = onFulfilled(this.result)
                  resolvePromise(p2, res, resolve, reject)
                } catch (error) {
                  reject(error)
                }
              }, 0);
            })
            //保存失败的回调
            this.onRejectCallbacks.push(() =>
            {
              setTimeout(() =>
              {
                //处理异常
                try {
                  //获取返回值
                  const res = onRejected(this.result)
                  resolvePromise(p2, res, resolve, reject)
                } catch (error) {
                  reject(error)
                }
              }, 0);
            })
          }

        })
        //返回新的promise实例实现链式调用
        return p2
      }

      //catch方法
      catch (onRejected)
      {
        //调用then中的onRejected回调
        return this.then(undefined, onRejected)
      }

      //finally方法
      finally (onFinally)
      {
        return this.then(onFinally, onFinally)
      }

      //resolve方法
      static resolve (value)
      {
        //是一个MyPromise直接返回
        if (value instanceof MyPromise) {
          return value
        }

        //其余转化为MyPromise并返回
        return new MyPromise(resolve =>
        {
          resolve(value)
        })
      }

      //reject方法
      static reject (value)
      {
        //直接返回一个Promise
        return new MyPromise((undefined, reject) =>
        {
          reject(value)
        })
      }

      //race方法
      static race (promises)
      {
        //返回一个promsie
        return new MyPromise((resolve, reject) =>
        {
          //如果参数不是一个数组直接抛出错误
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }

          //遍历数组等待第一个敲定
          promises.forEach(p =>
          {
            //由于p不一定是一个promise 先转化为promise 
            MyPromise.resolve(p).then(res =>
            {
              resolve(res)
            }, error =>
            {
              reject(error)
            })
          })
        })
      }

      //all方法
      static all (promises)
      {
        //返回一个promise
        return new MyPromise((resolve, reject) =>
        {
          //不是数组抛出错误
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }

          //空数组直接兑现
          promises.length === 0 && resolve(promises)

          const result = []
          let count = 0
          //foreach取出全部的promise
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              //记录结果
              result[index] = res
              //判断全部兑现 传递result
              count++
              count === promises.length && resolve(result)
            }, error =>
            {
              //处理拒绝
              reject(error)
            })
          })

        })
      }


      //settled方法
      static allSettled (promises)
      {
        //返回promise
        return new MyPromise((resolve, reject) =>
        {
          //判断数组
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }
          // 为空
          promises.length === 0 && resolve(promises)

          const result = []
          let count = 0
          //遍历数组
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              //记录
              result[index] = { status: FULFILLED, value: res }
              count++
              count === promises.length && resolve(result)
            }, error =>
            {
              result[index] = { status: REJECTED, reason: error }
              count++
              count === promises.length && resolve(result)
            })
          })
        })
      }

      //any方法
      static any (promises)
      {
        // 1. 返回Promise,数组判断
        return new MyPromise((resolve, reject) =>
        {
          if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'))
          }
          // 2. 空数组直接拒绝
          promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))

          // 3. 等待结果
          const errors = []
          let count = 0
          promises.forEach((p, index) =>
          {
            MyPromise.resolve(p).then(res =>
            {
              // 3.1 第一个兑现
              resolve(res)
            }, err =>
            {
              // 3.2 全部拒绝
              errors[index] = err
              count++
              count === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))
            })
          })
        })
      }
    }

六:总结

写完身心俱疲,但又有种知识充斥在脑海中的感觉,以前也只是了解会用promise的几种方法,也不了解其中方法的逻辑,

只有对其实现一下,才会对其更加的掌握,现在对promise有了更深的了解了,希望在以后使用promise的时候,调用其中的方法时候,能够想到其中的逻辑是怎么实现的,这样能更放心的去使用

参考文章:

  • MDN官方Promise

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1077780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go 复合类型之字典类型介绍

Go 复合类型之字典类型介绍 文章目录 Go 复合类型之字典类型介绍一、map类型介绍1.1 什么是 map 类型&#xff1f;1.2 map 类型特性 二.map 变量的声明和初始化2.1 方法一&#xff1a;使用 make 函数声明和初始化&#xff08;推荐&#xff09;2.2 方法二&#xff1a;使用复合字…

计算机网络 | 体系结构

计算机网络 | 体系结构 计算机网络 | 体系结构概念及功能计算机网络简介计算机网络的功能因特网发展阶段小结 组成与分类计算机网络的组成计算机网络的分类小结 标准化工作及相关组织速率相关性能指标速率带宽吞吐量小结 时延相关性能指标时延时延带宽积往返时延RTT利用率小结 …

【photoshop学习】用 Photoshop 做的 15 件创意事

用 Photoshop 做的 15 件创意事 每个人总是谈论 Photoshop 的无限可能。您可以使用该程序做很多事情&#xff0c;列表几乎是无穷无尽的。 嘿&#xff0c;我是卡拉&#xff01;如果您花过一些时间使用 在线ps&#xff0c;您可能见过我&#xff08;并且注意到我提到了这一点&am…

粘性文本整页滚动效果

效果展示 CSS 知识点 background 相关属性综合运用position 属性的 sticky 值运用scroll-behavior 属性运用scroll-snap-type 属性运用scroll-snap-align 属性运用 整体页面效果实现 <div class"container"><!-- 第一屏 --><div class"sec&qu…

【Linux服务端搭建及使用】

连接服务器的软件&#xff1a;mobaxterm 设置root 账号 sudo apt-get install passwd #安装passwd 设置方法 sudo passwd #设置root密码 su root #切换到root账户设置共享文件夹 一、强制删除原有环境 1.删除python rpm -qa|grep pytho…

【已解决】msvcp140.dll丢失怎样修复?msvcp140.dll重新安装的解决方法

今天我要和大家分享的是关于msvcp140.dll丢失的五种不同解决方法。我们知道&#xff0c;在运行一些软件或游戏的时候&#xff0c;经常会遇到“msvcp140.dll丢失”的问题&#xff0c;这可能会影响到我们的使用体验。那么&#xff0c;面对这个问题&#xff0c;我们应该如何应对呢…

【Python】实现excel文档中指定工作表数据的更新操作

在做数值计算时&#xff0c;个人比较习惯利用excel文档的公式做数值计算进行对比&#xff0c;检查异常&#xff0c;虽然计算量大后&#xff0c;excel计算会比较缓慢&#xff0c;但设计简单&#xff0c;易排错 但一般测试过程中使用到的数据都不是最终数值&#xff0c;会不停根据…

win1011安装MG-SOFT+MIB+Browser+v10b

文章目录 安装MG-SOFTSNMP服务配置安装MG-SOFT启动MIB-Browser以及错误解决MIB Browser使用 安装MG-SOFT win10和win11安装基本一样&#xff0c;所以参照下面的操作即可&#xff01; SNMP服务配置 打开设置&#xff0c;应用和功能&#xff0c;可选功能&#xff0c;选择添加功…

探馆天津车展 近距离感受“极致性能王”远航汽车

近年来&#xff0c;新能源汽车产业发展迅猛。得益于新能源车型在成本控制、品质、安全性等多方面的出色表现&#xff0c;消费者对新能源汽车的需求一直呈现刚性。2023年&#xff0c;虽然新能源汽车已经进入无补贴时代&#xff0c;但消费者对新能源汽车的需求依旧有增无减&#…

23年基因蓝皮书略读

2023年基因慧蓝皮书略读 1.发展环境1.1 宏观环境1.2 基因产业内涵 2 应用场景2.1 生育支持与生育健康筛查2.2 老龄化与肿瘤精准防控2.2.1 肿瘤早筛2.2.2 肿瘤伴随诊断2.2.3 MRD检测2.2.4 生物药研发及基因科技 3 产业发展3.1 产业图谱及产业链分析拟上市肿瘤检测公司上市基因企…

论文解析——AMD EPYC和Ryzen处理器系列的开创性的chiplet技术和设计

ISCA 2021 摘要 本文详细解释了推动AMD使用chiplet技术的挑战&#xff0c;产品开发的技术方案&#xff0c;以及如何将chiplet技术从单处理器扩展到多个产品系列。 正文 这些年在将SoC划分成多个die方面有一系列研究&#xff0c;MCM的概念也在不断更新&#xff0c;AMD吸收了…

超低延时直播技术演进之路-进化篇

一、概述 网络基础设施升级、音视频传输技术迭代、WebRTC 开源等因素&#xff0c;驱动音视频服务时延逐渐降低&#xff0c;使超低延时直播技术成为炙手可热的研究方向。实时音视频业务在消费互联网领域蓬勃发展&#xff0c;并逐渐向产业互联网领域加速渗透。经历了行业第一轮的…

并发、并行、同步、异步、阻塞、非阻塞

一、多核、多cpu &#xff08;一&#xff09;多核 Multicore 核是CPU最重要的部分。负责运算。核包括控制单元、运算单元、寄存器等单元。 多核就是指单个CPU中有多个核。 &#xff08;二&#xff09;多cpu Multiprocessor 多cpu就是一个系统拥有多个CPU。每个CPU可能有单个核…

JSON数据处理工具-在线工具箱网站tool.qqmu.com的使用指南

导语&#xff1a;无论是处理JSON数据、进行文本数字处理、解码加密还是使用站长工具&#xff0c;我们都希望能够找到一个功能强大、简便易用的在线平台。tool.qqmu.com作为一款瑞士军刀般的在线工具箱网站&#xff0c;满足了众多用户的需求。本文将介绍tool.qqmu.com的多项功能…

短视频矩阵系统seo源码saas开发---一手源头

一套优秀的短视频全链条获客系统&#xff0c;支持抖音获客seo排名、抖音SEO优化的系统应该如何开发&#xff0c;应该具备哪些功能&#xff1f;今天小编就跟大家分享一下我们的开发思路。 首先&#xff0c;目前公认的、抖音短视频seo优化方向&#xff0c;SaaS源码&#xff0c;系…

VIT(Vision Transformer)学习-模型理解(一)

VIT (Vision Transformer) 模型论文代码(源码)从零详细解读&#xff0c;看不懂来打我_哔哩哔哩_bilibili VIT模型架构图 1.图片切分为patch 2. patch转化为embedding 1&#xff09;将patch展平为一维长度 2&#xff09;token embedding&#xff1a;将拉平之后的序列映射…

初识 C语言文件操作

目录 前言&#xff1a; 为什么我们要使用文件&#xff1f; 什么是文件&#xff1f; 程序文件&#xff1a; 数据文件&#xff1a; 文件名&#xff1a; 文件的打开和关闭 文件指针&#xff1a; 流程&#xff1a; 文件路径&#xff1a; 文件的顺序读写&#xff1a; …

我用PYQT5做的第一个实用的上位机项目(六)

将之前的画面和代码用复制粘贴的方法复制四份&#xff0c;就完成了整个主画面和主程序的基本构建。 下面的工作是关于PLC和通信。 上位机项目&#xff0c;其与PLC通信的模式很多都是这样的&#xff1a;在没有操作和设置的平常显示界面&#xff0c;按照预定周期从PLC读取当前页…

一个命令让redis服务端所有信息无所遁形~(收藏吃灰系列)

Redis服务器是一个事件驱动程序&#xff0c;它主要处理两类事件&#xff1a;文件事件和时间事件。这些事件的处理和Redis命令的执行密切相关。下面我将以Redis服务端命令为切入点&#xff0c;深入解析其工作原理和重要性。 首先&#xff0c;我们先了解Redis服务端有哪些命令。…