Javascript高级-EventEmitter 与 Promise

✊不积跬步,无以至千里;不积小流,无以成江海。

实现发布订阅

以下是一个使用 JavaScript 实现发布-订阅模式的基本示例代码:

javascript 复制代码
// 发布者
const publisher = {
  subscribers: [],
  
  // 添加订阅者
  subscribe(callback) {
    this.subscribers.push(callback);
  },
  
  // 取消订阅
  unsubscribe(callback) {
    this.subscribers = this.subscribers.filter(subscriber => subscriber !== callback);
  },
  
  // 发布消息
  publish(data) {
    this.subscribers.forEach(subscriber => subscriber(data));
  }
};

// 订阅者1
function subscriber1(data) {
  console.log('Subscriber 1:', data);
}

// 订阅者2
function subscriber2(data) {
  console.log('Subscriber 2:', data);
}

// 订阅者3
function subscriber3(data) {
  console.log('Subscriber 3:', data);
}

// 添加订阅者
publisher.subscribe(subscriber1);
publisher.subscribe(subscriber2);
publisher.subscribe(subscriber3);

// 发布消息
publisher.publish('Hello, World!');

// 取消订阅订阅者2
publisher.unsubscribe(subscriber2);

// 再次发布消息
publisher.publish('Goodbye!');

当我们运行上述代码时,它会执行以下操作:

  1. 创建一个 publisher 对象,它包含一个空数组 subscribers,用于存储订阅者函数。
  2. 定义了三个订阅者函数 subscriber1subscriber2subscriber3,它们会在收到消息时执行相应的操作。
  3. 使用 publisher.subscribe 方法将订阅者函数添加到 subscribers 数组中。我们添加了 subscriber1subscriber2subscriber3
  4. 使用 publisher.publish 方法发布一条消息。这将触发 publisher 对象中的所有订阅者函数执行相应的操作。在本例中,发布了一条消息 'Hello, World!'
  5. 所有订阅者函数都被调用,并输出相应的消息。因此,我们会在控制台上看到类似以下的输出:
yaml 复制代码
Subscriber 1: Hello, World!
Subscriber 2: Hello, World!
Subscriber 3: Hello, World!
  1. 使用 publisher.unsubscribe 方法取消订阅者2(即 subscriber2)。
  2. 使用 publisher.publish 方法再次发布一条消息。由于已取消订阅者2,只有订阅者1和订阅者3会收到消息。
  3. 在控制台上,我们会看到类似以下的输出:
yaml 复制代码
Subscriber 1: Goodbye!
Subscriber 3: Goodbye!

代码中的 publisher 对象具有以下方法:

  • subscribe(callback): 这个方法用于添加订阅者函数到 subscribers 数组中。订阅者函数是一个回调函数,当发布者发布消息时,这些订阅者函数将被调用。参数 callback 是一个函数,表示要添加为订阅者的回调函数。例如,我们可以使用 publisher.subscribe(subscriber1) 来将 subscriber1 添加为订阅者。当调用 subscribe 方法时,订阅者函数将被添加到 publisher 对象的 subscribers 数组中,以便在以后的消息发布中被调用。

  • unsubscribe(callback): 这个方法用于从 subscribers 数组中取消订阅特定的订阅者函数。通过使用 unsubscribe 方法,我们可以选择性地取消订阅某个订阅者函数,使其不再接收后续的发布消息。参数 callback 是一个函数,表示要取消订阅的回调函数。例如,我们可以使用 publisher.unsubscribe(subscriber2) 来取消订阅 subscriber2。当调用 unsubscribe 方法时,它会遍历 subscribers 数组,并使用 filter 方法来移除与传入的回调函数匹配的订阅者函数。

  • publish(data): 这个方法用于发布消息,将消息传递给所有的订阅者函数。当发布者调用 publish 方法时,所有订阅者函数将会被调用,并接收发布的消息作为参数。参数 data 是要发布的消息数据。例如,我们可以使用 publisher.publish('Hello, World!') 来发布一条消息。当调用 publish 方法时,它会遍历 subscribers 数组,并对每个订阅者函数调用该函数,并将消息作为参数传递给它们。这样,所有的订阅者函数都能够接收到发布的消息,并执行相应的操作

在示例中,我们添加了三个订阅者函数,并发布了一条消息。通过订阅和发布的机制,所有的订阅者函数都能够接收到发布的消息,并执行相应的操作。取消订阅者函数后,它将不再接收到后续的发布消息。

Promise介绍

Promise 是 JavaScript 中用于处理异步操作的一种机制。它是 ECMAScript 6 (ES6) 引入的一种对象,用于管理异步操作的状态和结果。Promise 可以更优雅地处理异步代码,并提供了一种可靠的方式来处理成功、失败和异步操作完成后的结果。

Promise 对象有三种状态:

  1. Pending(进行中): 初始状态,表示异步操作正在进行中,尚未完成。
  2. Fulfilled(已完成): 表示异步操作已成功完成。
  3. Rejected(已拒绝): 表示异步操作失败或被拒绝。

一个 Promise 对象的状态一旦改变,就不会再改变。

使用 Promise 的基本语法如下:

javascript 复制代码
const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  // 如果操作成功,调用 resolve(value)
  // 如果操作失败,调用 reject(error)
});

myPromise
  .then((value) => {
    // 处理操作成功的结果
  })
  .catch((error) => {
    // 处理操作失败的结果
  });

在上述代码中,我们创建了一个 Promise 对象 myPromise,并传入一个执行器函数(executor function)。执行器函数接收两个参数 resolvereject,分别是用于将 Promise 状态改变为 Fulfilled 和 Rejected 的函数。

在执行器函数中,我们执行异步操作,并根据操作的结果调用 resolvereject。如果操作成功,我们调用 resolve 函数,并传入成功的结果(value);如果操作失败,我们调用 reject 函数,并传入失败的原因(error)。

使用 .then() 方法,我们可以在 Promise 对象状态变为 Fulfilled 时处理操作成功的结果。通过 .catch() 方法,我们可以在 Promise 对象状态变为 Rejected 时处理操作失败的结果。

Promise 还提供了其他方法,如 .finally().all().race() 等,用于处理多个 Promise 对象的组合和并行操作。

使用 Promise 可以更好地管理异步代码,避免回调地狱(callback hell)的问题,使代码更加清晰、可读和可维护。它已成为现代 JavaScript 开发中处理异步操作的标准方式。

Promise API

Promise API 提供了一些方法来处理 Promise 对象的状态和结果。下面是一些常用的 Promise API:

  1. Promise.resolve(value): 返回一个状态为 Fulfilled 的 Promise 对象,并将给定的 value 作为成功的结果。
  2. Promise.reject(reason): 返回一个状态为 Rejected 的 Promise 对象,并将给定的 reason 作为失败的原因。
  3. Promise.all(iterable): 接收一个可迭代对象(如数组)作为参数,返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都变为 Fulfilled 状态时变为 Fulfilled,并将所有 Promise 对象的结果作为一个数组传递。
  4. Promise.race(iterable): 接收一个可迭代对象作为参数,返回一个新的 Promise 对象。该 Promise 对象在第一个变为 Fulfilled 或 Rejected 状态的 Promise 对象完成时变为相同的状态,并将第一个完成的 Promise 对象的结果传递。
  5. Promise.allSettled(iterable): 接收一个可迭代对象作为参数,返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都变为 Fulfilled 或 Rejected 状态时变为 Fulfilled,并返回包含每个 Promise 对象状态和结果的对象数组。
  6. Promise.prototype.then(onFulfilled, onRejected): 在 Promise 对象的状态变为 Fulfilled 时调用 onFulfilled 回调函数,在状态变为 Rejected 时调用 onRejected 回调函数。该方法返回一个新的 Promise 对象,可以用于链式调用。
  7. Promise.prototype.catch(onRejected): 在 Promise 对象的状态变为 Rejected 时调用 onRejected 回调函数。该方法返回一个新的 Promise 对象,用于处理 Promise 对象的错误。
  8. Promise.prototype.finally(onFinally): 在 Promise 对象的状态变为 Fulfilled 或 Rejected 时,无论如何都会调用 onFinally 回调函数。该方法返回一个新的 Promise 对象,用于添加最终处理。

这些是 Promise API 的一些常见方法,用于处理 Promise 对象的状态、结果和错误。通过使用这些方法,我们可以更灵活地处理异步操作和多个 Promise 对象的组合。

Promise的实现

Promise 是 JavaScript 的内置对象,它的实现涉及到一些复杂的异步操作和状态管理。下面是一个简化版的 Promise 实现,用于演示其基本原理:

ini 复制代码
class Promise {
  constructor(executor) {
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(callback => callback(this.value));
      }
    };

    const reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(callback => callback(this.reason));
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      if (this.status === 'fulfilled') {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.status === 'rejected') {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      if (this.status === 'pending') {
        this.onFulfilledCallbacks.push((value) => {
          setTimeout(() => {
            try {
              const result = onFulfilled(value);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push((reason) => {
          setTimeout(() => {
            try {
              const result = onRejected(reason);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }
}
  1. 首先,我们定义了一个名为 Promise 的类,它代表了一个 Promise 对象。

  2. 在构造函数中,我们初始化了 Promise 对象的初始状态为 'pending',并创建了用于存储结果和回调函数的变量。

  3. resolvereject 是两个内部函数,用于将 Promise 对象的状态从 'pending' 改变为 'fulfilled''rejected'。它们接受一个参数,分别是成功的结果 value 和失败的原因 reason。当状态改变时,它们会触发相应的成功或失败的回调函数。

  4. 在构造函数中,我们调用了 executor 函数,并传入 resolvereject 函数作为参数。executor 函数是在创建 Promise 对象时传入的函数,它接受这两个参数,并用于执行异步操作。我们用 try-catch 块包裹 executor 函数的执行,以处理可能的异常。

  5. then 方法用于注册成功和失败的回调函数,并返回一个新的 Promise 对象。它接受两个参数:onFulfilled 回调函数和 onRejected 回调函数,分别用于处理成功和失败的情况。在 then 方法内部,我们根据 Promise 对象的当前状态执行相应的回调函数。

    • 如果状态为 'fulfilled',我们使用 setTimeout 来模拟异步操作,并在下一个事件循环中执行 onFulfilled 回调函数。如果回调函数执行成功,则调用新的 Promise 对象的 resolve 方法,传递成功的结果。
    • 如果状态为 'rejected',我们使用 setTimeout 来模拟异步操作,并在下一个事件循环中执行 onRejected 回调函数。如果回调函数执行成功,则调用新的 Promise 对象的 resolve 方法,传递成功的结果。
    • 如果状态为 'pending',表示 Promise 对象的状态还未确定,我们将 onFulfilledonRejected 回调函数分别放入 onFulfilledCallbacksonRejectedCallbacks 数组中,以便在 Promise 对象状态确定后执行。
  6. catch 方法是 then 方法的一种特殊形式,用于注册处理失败的回调函数。它实际上是调用 then 方法的简写形式,将第一个参数设置为 null

这个简化版的 Promise 实现提供了基本的 Promise 功能,包括状态管理、回调函数注册、链式调用等。然而,真正的 Promise 实现要更复杂,涉及到更多的细节和错误处理机制。这个示例仅用于说明 Promise 的基本原理,实际使用中应使用原生的 JavaScript Promise 对象或符合 Promise/A+ 规范的第三方库。

相关推荐
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&3 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
一路向前的月光8 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   8 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web8 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
Jiaberrr9 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
安冬的码畜日常11 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ11 小时前
html+css+js实现step进度条效果
javascript·css·html