单线程
单线程是指在一个程序中只有一个执行线程。在单线程的程序中,所有的任务都是按顺序执行的,即每个任务都必须等待前面的任务执行完毕之后才能开始执行。这种方式被称为串行执行,因为所有的任务都是在同一个线程中按照顺序执行的。在单线程的程序中,所有的操作都是同步的。
优缺点: 单线程的优点是代码简单易懂,因为所有的代码都是按照顺序执行的。另外,由于只有一个线程在执行,因此不需要考虑线程间的同步问题,这样可以减少一些并发问题的出现。单线程的缺点也显而易见,最大的缺点是性能问题。
异步队列
异步队列是一种数据结构,用于处理异步任务。它通常用于多线程或多进程的程序中,用于处理一些需要耗费时间的任务,例如网络请求、文件读写等。 异步队列可以让程序在执行异步任务的同时,不会阻塞其他任务的执行。
异步队列中的任务会被放入一个队列中,并按照先进先出的顺序执行。在异步队列中,任务的执行是由一个线程或进程池来完成的。当一个任务被加入到队列中时,线程或进程池会检查当前是否有空闲的线程或进程可用,如果有则立即将任务分配给其中的一个线程或进程执行。如果当前没有空闲的线程或进程可用,则任务会等待直到有线程或进程空闲。
异步队列虽然可以提高程序的效率,但它并不能保证任务的执行顺序 。如果任务的执行顺序对程序的正确性有影响,那么就需要采用其他方式来保证任务的顺序。
回调函数
回调函数是一种常用的编程技巧,它允许在某个函数或方法执行完毕后,调用另一个函数或方法进行后续处理。回调函数通常作为参数传递给原始函数,以便在原始函数执行完毕后被调用。
回调函数常用于事件驱动的编程模型中。例如,在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 实例有三种状态:pending、fulfilled 和 rejected。当 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 实现代码包含了 then
、catch
、resolve
、reject
、all
和 race
这些方法。then
方法用于注册成功和失败的回调函数,catch
方法用于注册失败的回调函数,resolve
方法用于创建一个以给定值解决的 Promise 对象,reject
方法用于创建一个以给定原因拒绝的 Promise 对象,all
方法用于创建一个 Promise 对象,该对象在所有给定的 Promise 对象都成功解决时解决,并且在任何一个 Promise 对象被拒绝时拒绝,race
方法用于创建一个 Promise 对象,该对象在任何给定的 Promise 对象解决或拒绝时都会解决或拒绝。
注意,这个 Promise 实现代码仅仅是一个简单的实现,它并没有考虑到一些关键问题,比如错误处理、性能问题、安全问题等。在实际开发中,我们需要使用更加完善和稳健的 Promise 实现,或者直接使用浏览器或 Node.js 内置的 Promise 对象。