JavaScript之异步

单线程

单线程是指在一个程序中只有一个执行线程。在单线程的程序中,所有的任务都是按顺序执行的,即每个任务都必须等待前面的任务执行完毕之后才能开始执行。这种方式被称为串行执行,因为所有的任务都是在同一个线程中按照顺序执行的。在单线程的程序中,所有的操作都是同步的。

优缺点: 单线程的优点是代码简单易懂,因为所有的代码都是按照顺序执行的。另外,由于只有一个线程在执行,因此不需要考虑线程间的同步问题,这样可以减少一些并发问题的出现。单线程的缺点也显而易见,最大的缺点是性能问题。

异步队列

异步队列是一种数据结构,用于处理异步任务。它通常用于多线程或多进程的程序中,用于处理一些需要耗费时间的任务,例如网络请求、文件读写等。 异步队列可以让程序在执行异步任务的同时,不会阻塞其他任务的执行。
异步队列中的任务会被放入一个队列中,并按照先进先出的顺序执行。在异步队列中,任务的执行是由一个线程或进程池来完成的。当一个任务被加入到队列中时,线程或进程池会检查当前是否有空闲的线程或进程可用,如果有则立即将任务分配给其中的一个线程或进程执行。如果当前没有空闲的线程或进程可用,则任务会等待直到有线程或进程空闲。
异步队列虽然可以提高程序的效率,但它并不能保证任务的执行顺序 。如果任务的执行顺序对程序的正确性有影响,那么就需要采用其他方式来保证任务的顺序。

回调函数

回调函数是一种常用的编程技巧,它允许在某个函数或方法执行完毕后,调用另一个函数或方法进行后续处理。回调函数通常作为参数传递给原始函数,以便在原始函数执行完毕后被调用。

回调函数常用于事件驱动的编程模型中。例如,在Web开发中,当用户单击一个按钮时,浏览器会触发一个事件,开发人员可以在事件处理程序中注册一个回调函数,以便在事件发生时执行一些额外的操作。在这种情况下,回调函数通常被定义为一个独立的函数,它可以在事件发生时被调用,完成相应的操作。

Generator 和 Async/Await

Generator 是一种特殊的函数,它可以在执行过程中暂停,并在需要时恢复执行。Generator 通过使用 yield 关键字来实现这种暂停和恢复的机制。当生成器函数执行到一个 yield 语句时,它会暂停执行并返回一个值,等待下一次调用时恢复执行。

异步编程模型中的 Generator 通常被称为“协程”(coroutine),它可以在执行过程中暂停和恢复,可以用于处理异步事件和异步操作。使用协程可以使异步编程变得更加简洁和可读,同时也可以避免回调函数嵌套过多的问题。

在 JavaScript 中,Async/Await 是一种基于 Generator 的异步编程模型。使用 Async/Await 可以使异步编程变得更加简单和直观,避免了回调函数嵌套和错误处理的问题。在 Async/Await 中,使用 async 关键字声明一个异步函数,该函数内部可以使用 await 关键字等待异步操作完成并返回结果。

Generator 和 Async/Await 的 核心思想 都是让程序可以在异步操作执行期间暂停和恢复执行。使用 Generator 或 Async/Await 可以使异步编程变得更加简洁和可读,同时也可以避免回调函数嵌套和错误处理的问题。

Promise

Promise 是一种异步编程的解决方案,它可以避免回调函数嵌套和错误处理的问题,使异步编程变得更加简单和直观。Promise 对象表示一个异步操作的最终完成或失败,并且可以链式调用多个异步操作。

在 JavaScript 中,Promise 是一个构造函数,通过 new 关键字来创建一个 Promise 实例。Promise 的构造函数接受一个函数作为参数,该函数接受两个参数:resolve 和 reject。当异步操作成功完成时,调用 resolve 函数并传递异步操作的结果;当异步操作失败时,调用 reject 函数并传递错误信息。

Promise 实例有三种状态:pendingfulfilledrejected。当 Promise 对象刚刚被创建时,它的状态为 pending。当异步操作成功完成时,Promise 对象的状态会变为 fulfilled;当异步操作失败时,Promise 对象的状态会变为 rejected。Promise 对象的状态一旦发生改变,就不会再改变。

使用 Promise 可以链式调用多个异步操作,使用 then 和 catch 方法来处理成功和失败的情况。then 方法接受两个参数,第一个参数是成功的回调函数,第二个参数是失败的回调函数;catch 方法接受一个参数,用于处理失败的情况。

总之,Promise 是一种异步编程的解决方案,它可以避免回调函数嵌套和错误处理的问题,使异步编程变得更加简单和直观。Promise 对象表示一个异步操作的最终完成或失败,并且可以链式调用多个异步操作。使用 then 和 catch 方法可以处理成功和失败的情况。

手写Promise

以下是一个基本的 Promise 实现代码,用于展示 Promise 的实现原理:

class MyPromise {
    
    
  constructor(executor) {
    
    
    this.state = 'pending'; // 保存初始化状态
    this.value = null;  // 用于保存resolve传入的值
    this.reason = null;  // 用于保存rejected传入的值
    this.onFulfilledCallbacks = []; // 用于保存reslove的回调函数
    this.onRejectedCallbacks = [];  // 用于保存reject的回调函数
    
    //  状态变为resolved方法
    const resolve = value => {
    
    
      // 只有状态为pending 时才能改变
      if (this.state === 'pending') {
    
    
        this.state = 'fulfilled'; // 修改状态
        this.value = value;  // 设置传入的值
        this.onFulfilledCallbacks.forEach(callback => callback(value)); // 执行回调函数
      }
    };
  	
  	// 状态转变为rejected 方法
    const reject = reason => {
    
    
      // 只有状态为pending时才能转变
      if (this.state === 'pending') {
    
    
        this.state = 'rejected'; // 修改状态
        this.reason = reason;  // 设置传入的值
        this.onRejectedCallbacks.forEach(callback => callback(reason)); // 执行回调函数
      }
    };
  	// 将两个方法传入函数执行
    try {
    
    
      executor(resolve, reject);
    } catch (error) {
    
    
      // 遇到错误时,补货错误,执行reject函数
      reject(error);
    }
  }
  
  then(onFulfilled, onRejected) {
    
    
  	// 判断两个参数是否为函数类型,因为这两个参数是可选参数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
    
     throw reason };
  	
  	// 封装前一个promise成功时执行的函数
    const promise2 = new MyPromise((resolve, reject) => {
    
    
      if (this.state === 'fulfilled') {
    
    
        setTimeout(() => {
    
    
          try {
    
    
            const x = onFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
    
    
            reject(error);
          }
        });
      }
  	  // 封装前一个promise失败时执行的函数
      if (this.state === 'rejected') {
    
    
        setTimeout(() => {
    
    
          try {
    
    
            const x = onRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
    
    
            reject(error);
          }
        });
      }
  	  // 如果是等待状态,则将函数加入到对应列表中
      if (this.state === 'pending') {
    
    
        this.onFulfilledCallbacks.push(value => {
    
    
          setTimeout(() => {
    
    
            try {
    
    
              const x = onFulfilled(value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
    
    
              reject(error);
            }
          });
        });
  
        this.onRejectedCallbacks.push(reason => {
    
    
          setTimeout(() => {
    
    
            try {
    
    
              const x = onRejected(reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
    
    
              reject(error);
            }
          });
        });
      }
    });
  
    return promise2;
  }
  
  catch(onRejected) {
    
    
    return this.then(null, onRejected);
  }
  
  resolvePromise(promise2, x, resolve, reject) {
    
    
    if (promise2 === x) {
    
    
      reject(new TypeError('Chaining cycle detected'));
    }
  
    if (x && (typeof x === 'object' || typeof x === 'function')) {
    
    
      let called = false;
  
      try {
    
    
        const then = x.then;
  
        if (typeof then === 'function') {
    
    
          then.call(
            x,
            y => {
    
    
              if (called) return;
              called = true;
              this.resolvePromise(promise2, y, resolve, reject);
            },
            reason => {
    
    
              if (called) return;
              called = true;
              reject(reason);
            }
          );
        } else {
    
    
          resolve(x);
        }
      } catch (error) {
    
    
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
    
    
      resolve(x);
    }
  }
  
  // 如果状态凝固,则执行对应状态的函数
  static resolve(value) {
    
    
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }
  
  static reject(reason) {
    
    
    return new MyPromise((resolve, reject) => reject(reason));
  }
  
  // 接受一个Promise实例的数组或具有Iterator接口的对象作为参数
  // 参数其中一个失败,则触发失败状态,第一个触发失败的Promise错误的信息作为Promise.all的错误信息
  static all(promises) {
    
    
    return new MyPromise((resolve, reject) => {
    
    
      const values = [];
      let count = 0;
  
      for (let i = 0; i < promises.length; i++) {
    
    
        MyPromise.resolve(promises[i]).then(
          value => {
    
    
            values[i] = value;
            count++;
  
            if (count === promises.length) {
    
    
              resolve(values);
            }
          },
          reject
        );
      }
    });
  }
  // 该方法的参数是Promise的数组
  // 因为Promise的状态只能改变一次,我们需要把Promise.race中产生的Promise对象的resolve方法,
  // 注入到数组中的每一个Promise实例中的回调函数中即可。
  static race(promises) {
    
    
    return new MyPromise((resolve, reject) => {
    
    
      for (let i = 0; i < promises.length; i++) {
    
    
        MyPromise.resolve(promises[i]).then(resolve, reject);
      }
    });
  }
}

这个 Promise 实现代码包含了 thencatchresolverejectallrace 这些方法。then 方法用于注册成功和失败的回调函数,catch 方法用于注册失败的回调函数,resolve 方法用于创建一个以给定值解决的 Promise 对象,reject 方法用于创建一个以给定原因拒绝的 Promise 对象,all 方法用于创建一个 Promise 对象,该对象在所有给定的 Promise 对象都成功解决时解决,并且在任何一个 Promise 对象被拒绝时拒绝,race 方法用于创建一个 Promise 对象,该对象在任何给定的 Promise 对象解决或拒绝时都会解决或拒绝。

注意,这个 Promise 实现代码仅仅是一个简单的实现,它并没有考虑到一些关键问题,比如错误处理、性能问题、安全问题等。在实际开发中,我们需要使用更加完善和稳健的 Promise 实现,或者直接使用浏览器或 Node.js 内置的 Promise 对象。

猜你喜欢

转载自blog.csdn.net/qq_48439911/article/details/130507458