Web-高级服务器端事件

异步和回调函数

        在诸如Java之类的编程语言中,主程序流程发生在主线程上。一些与程序的主要流程独立发生的事件将作为新线程或进程产生,与主线程并行执行代码。但是,使用JavaScript来实现这一点有一定的挑战。默认情况下,JavaScript是同步且单线程的。因此,不可能创建新线程并同时运行它们。JavaScript通过非阻塞的异步I/O模型来处理这个问题。这意味着JavaScript的执行被阻塞,但I/O操作不会被阻塞。然而,浏览器提供了一组API来处理这种功能。

        JavaScript指向一个函数,该函数将在异步操作的结果被获取时执行,例如返回数据或在异步操作期间发生错误。我们称这个函数为"回调函数"。同时,JavaScript继续正常执行代码。正因为如此,那些进行各种外部调用的框架提供了回调函数以在稍后执行。

        因此,回调函数被作为值传递给另一个函数,只有在事件发生后才会执行这个函数。然而,每个回调函数都会增加一层嵌套,当有许多回调函数时,代码开始变得非常复杂。为了解决这个问题,JavaScript引入了几个功能,允许我们编写异步代码而无需使用回调函数:Promise(ES6)和Async/Await(ES2017)。

        Promise通常被定义为最终会变得可用的值的代理。通过使用Promise,您可以避免在处理异步代码时遇到回调函数的问题。一旦调用一个Promise,它就进入待定阶段。在此期间,调用函数继续执行,而Promise挂起,直到解决为止,并向调用函数提供所请求的任何数据。

Promises和Observables

        JavaScript Promise是一种使异步过程看起来像一系列函数调用的方式。它通过保存调用链,只在事件发生时处理链条。关键在于,JavaScript在程序中移到下一条语句,而调用链在后台等待并执行。您可以将其视为程序执行中的一个"分叉"。

        Promise是使用Promise类实现的。通常,我们不需要创建自己的Promise对象,因为我们将使用返回Promise对象的标准库。然而,了解它们的结构对于理解Promise的工作方式是有用的。以下是在TypeScript中创建新Promise对象的大纲,尽管您不必这样做。我们将在我们的第6周模块中详细介绍这个。

  let promise = new Promise( (resolve, reject) =>
    // do some stuff, e.g. request data from a server
    // check data for errors
    // if success:
    resolve();
    // if error
    reject();
  }

        1. 我们使用可观察对象的主要原因有:
   - 异步和响应式编程:可观察对象提供了处理异步事件流的强大机制。它们允许您在时间上处理数据和事件,使您能够实时地对其进行响应和处理。
   - 事件驱动架构:可观察对象非常适用于事件驱动的架构,在该架构中有多个事件源并且需要同时处理它们。它们提供了一种方便的方式来管理和组合不同的事件流。
   - 数据流和转换:可观察对象可用于数据流场景,其中您需要在数据到达时进行处理。它们允许您在数据流上应用各种转换操作(如过滤、映射、归约)。

        2. 观察者(Observer)和可观察对象(Observable)的区别如下:
   - 观察者:观察者是一个订阅可观察对象以接收通知或更新的对象或函数。它定义了在有新数据可用时要执行的逻辑。
   - 可观察对象:可观察对象是数据或事件的源头,可以被一个或多个观察者观察。它表示随时间推移的值流,可以进行订阅。可观察对象提供了发出值、处理错误和完成流的方法。

   是的,一个可观察对象可以有多个观察者。这被称为多播或广播。当多个观察者订阅同一个可观察对象时,每个观察者将独立地接收到发出的值。可观察对象可以同时向所有观察者发出值,确保每个观察者接收相同的数据流。这允许并行处理或同一数据流的多个消费者。

事件驱动编程


        事件驱动程序是一种编程范式,它基于一系列事件来确定程序的流程,例如传感器输出、用户输入或来自其他线程的消息。此外,事件驱动编程还可以被定义为一种应用程序架构技术,其中应用程序具有一个明确分为两个部分的主循环:第一部分处理事件选择(也称为事件检测),而第二部分处理事件处理。

        虽然Node.js是一个单线程应用程序,但它通过事件和回调的概念来支持并发。Node.js的每个API都是异步的,并且由于是单线程的,它利用异步调用来保持并发性。Node.js使用观察者模式。Node线程维护一个事件循环,当一个任务完成时,它触发相应的事件,从而触发事件监听器函数。

事件和EventEmiiter类


        通过对在浏览器中使用JavaScript与用户进行交互的经验,您会了解到许多与用户的交互是通过事件来实现的,例如鼠标点击、键盘按键、响应鼠标移动等。

        在Node.js中,我们可以使用事件模块来构建类似的系统。特别是,事件模块中的EventEmitter类将用于处理Node.js中的事件。

// Import events module
var events = require('events');

// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

        事件发射器可以从应用程序的另一部分启动新事件,并且可以配置监听器来监听此事件以采取相应行动。
        EventEmitter类提供了一些成员函数。通过这些成员函数,我们可以发布事件并监听它们。
以下是当事件"pay"被触发时将执行的函数示例。
        使用emit()方法来触发一个事件。

var events = require('events');
var eventEmitter = new events.EventEmitter();

//Create an event handler:
var myEventHandler = function () {
  console.log('The amount to be paid is $25.00');
}

//Assign the event handler to an event:
eventEmitter.on('bill', myEventHandler);

//Fire the 'bill' event:
eventEmitter.emit('bill');

事件循环

        事件循环是一个无限循环,它等待任务,执行它们,然后在接收到额外任务之前进入睡眠状态。
        在JavaScript程序中,事件循环在同一个(单一)线程上运行。因此,阻塞事件循环导致整个线程被阻塞。
        事件循环无法启动或停止。一旦进程启动,它就进入事件循环,并在不再需要执行回调函数时结束。因此,事件循环有可能无限运行。

// Import events module
var events = require('events');

// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

// Create an event handler as follows
var connectHandler = function connected() {
   console.log('connection succesful.');
  
   // Fire the data_received event 
   eventEmitter.emit('data_received');
}

// Bind the connection event with the handler
eventEmitter.on('connection', connectHandler);
 
// Bind the data_received event with the anonymous function
eventEmitter.on('data_received', function() {
   console.log('data received succesfully.');
});

// Fire the connection event 
eventEmitter.emit('connection');

console.log("Program Ended.");

猜你喜欢

转载自blog.csdn.net/qq_54813250/article/details/133443002