一、什么是异步编程
二、JS中异步编程有哪些方法
1、回调函数(callback)
回调函数是一种特殊的函数,它作为参数传递给另一个函数,并在被调用函数执行完毕后被调用。回调函数是最基本的异步处理方式。
function fetchData(callback) {
setTimeout(() => {
const data = "Hello, World!";
callback(data);
}, 1000);
}
fetchData((data) => {
console.log(data);
});
2、Promise
Promise 是一个表示异步操作最终完成或失败的对象,并返回结果值。它提供了 .then()
和 .catch()
方法来处理成功和失败的回调。
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "Hello, World!";
resolve(data);
}, 1000);
});
}
fetchData().then((data) => {
console.log(data);
}).catch((error) => {
console.error(error);
});
3、Async/Await
async用于声明一个function是异步的,而await则可以认为是 async await的简写形式,是等待一个异步方法执行完成的。
async function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "Hello, World!";
resolve(data);
}, 1000);
});
}
async function printData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
printData();
4、事件循环
事件循环是单线程的JavaScript在处理异步事件时进行的一种循环过程。对于异步事件它会先加入到事件队列中挂起,等主线程空闲时会去执行事件队列中的事件。如此反复循环。事件循环的设计使得 JavaScript 可以在单线程下处理异步操作,避免了阻塞的情况,保证了程序的响应性和流畅性。
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
Promise.resolve().then(function() {
console.log("promise1");
}).then(function() {
console.log("promise2");
});
console.log("script end");
这段代码的运行结果:
script start
script end
promise1
promise2
setTimeout
- 首先输出 "script start"。
- 执行setTimeout,将"setTimeout"加入定时器队列。
- 执行Promise.resolve(),将第一个.then中的"promise1"加入微任务队列。
- 输出 "script end"。
- 执行第一个.then中的任务,输出 "promise1"。
- 执行第二个.then中的任务,输出 "promise2"。
- 最后执行定时器任务,输出 "setTimeout"。
三、promise的概念
Promise是一个构造函数,是异步编程的一种解决方案。Promise 是 ES6新引入的一个特性,它允许你在异步操作(如网络请求)完成后执行某些代码。它代表了一个将来才会知道结果的操作。他有三个状态:
- Pending(进行中):初始状态,既没有成功,也没有失败。
- Fulfilled(已成功):操作成功完成。
- Rejected(已失败):操作失败。
而promise执行的过程,就是由pending到fulfilled和rejected的过程(不可逆)
四、promise对比callback的优点
1、解决了回调地狱问题: Promise 通过链式调用 then 方法的方式,避免了传统 callback 嵌套过多导致的回调地狱问题,使代码结构更加清晰和易于维护。
2、提供了更好的错误处理机制: Promise 提供了 catch 方法用于捕获链式调用中的错误,并且可以通过 Promise.all 或 Promise.race 等方法进行多个异步操作的错误处理。
3、支持并发和串行的异步操作: Promise 可以通过 Promise.all 和 Promise.race 来管理多个异步操作的并发执行或串行执行,使得复杂的异步操作更加容易管理。
4、状态管理更清晰: Promise 的状态包括 pending、fulfilled 和 rejected,状态的切换更加明确,便于跟踪和处理异步操作的状态。
5、更容易进行异步操作的组合: Promise 的 then 方法返回一个新的 Promise 对象,可以方便地进行异步操作的组合和串联,提高了代码的可读性和可维护性。
五、.then的链式调用和多次调用同一个promise.then的结果
1、.then的链式调用
在 Promise 中,每次调用 .then()
方法都会返回一个新的 Promise 对象,因此可以进行链式调用。链式调用的每一个 .then()
方法都可以处理上一个 .then()
方法返回的 Promise 对象的结果。链式调用可以使代码更加清晰和易读,便于处理异步操作的结果。
myPromise.then(func1)
.then(func2)
.then(func3);
2、.then的多次调用
当多次调用同一个 promise.then()
方法时,之前的 .then()
方法会捕获并处理前一个 .then()
方法返回的 Promise 对象的结果。如果同一个 promise.then()
被多次调用,那么每次调用的处理函数会在 Promise 状态改变时都会被执行。这种方式可以用于多个处理逻辑需要同时应用在同一个 Promise 结果上的情况。
const myPromise = new Promise((resolve, reject) => {
resolve("Hello");
});
myPromise.then(result => console.log(result));
myPromise.then(result => console.log(result.toUpperCase()));
总结:链式调用 .then()
返回的每个 Promise 对象都可以单独处理结果,而多次调用同一个 promise.then()
会共享同一个 Promise 对象的结果。
六、promise实例上的方法有哪些
1、then():接收两个函数作为参数,第一个函数在 Promise 成功时调用,第二个在失败时调用。
// 创建一个 Promise 对象,模拟异步操作
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber); // 成功时调用 resolve
} else {
reject("Failed"); // 失败时调用 reject
}
}, 1000);
});
// 使用 Promise 的 then 方法处理成功和失败的情况
myPromise.then(result => {
console.log("Resolved with result: " + result);
}).catch(error => {
console.log("Rejected with error: " + error);
}).finally(() => {
console.log("Promise is settled"); // 无论成功或失败都会执行
});
// 创建一个 Promise 对象,模拟异步操作
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber); // 成功时调用 resolve
} else {
reject("Failed"); // 失败时调用 reject
}
}, 1000);
});
// 使用 Promise 的 catch 方法捕获 Promise 对象状态改变时的错误
myPromise.then(result => {
console.log("Resolved with result: " + result);
}).catch(error => {
console.log("Rejected with error: " + error); // 捕获并处理错误
}).finally(() => {
console.log("Promise is settled"); // 无论成功或失败都会执行
});
3、finally():无论 Promise 最终状态如何都会执行。
// 创建一个 Promise 对象,模拟异步操作
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber); // 成功时调用 resolve
} else {
reject("Failed"); // 失败时调用 reject
}
}, 1000);
});
// 使用 Promise 的 finally 方法,在 Promise 对象状态改变时都会执行的回调函数
myPromise.then(result => {
console.log("Resolved with result: " + result);
}).catch(error => {
console.log("Rejected with error: " + error); // 捕获并处理错误
}).finally(() => {
console.log("Promise is settled"); // 无论成功或失败都会执行
});
七、promise的静态方法有哪些
1、Promise.all()
:等待所有的 Promise 完成,有任一失败则失败。
// 使用 Promise.all 来处理多个 Promise 对象
const promise1 = Promise.resolve("Promise 1");
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve("Promise 2");
}, 2000);
});
Promise.all([promise1, promise2]).then(values => {
console.log("All promises resolved with values: ", values);
});
2、Promise.race()
:返回最先改变状态的 Promise 的结果。
// 使用 Promise.race 来处理多个 Promise 对象
const racePromise1 = new Promise((resolve) => {
setTimeout(() => {
resolve("Race Promise 1");
}, 1000);
});
const racePromise2 = new Promise((resolve) => {
setTimeout(() => {
resolve("Race Promise 2");
}, 500);
Promise.race([racePromise1, racePromise2]).then(value => {
console.log("The first promise to resolve is: ", value);
});
3、Promise.allSettled()
不管所有的 Promise 是成功还是失败,都会等待所有的 Promise 都有一个结果后才会返回。返回的结果是每个 Promise 的状态和结果。
// 使用 Promise.allSettled 来处理多个 Promise 对象,无论成功或失败都会返回结果
const settledPromise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Settled Promise 1");
}, 1500);
});
const settledPromise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Settled Promise 2 failed");
}, 1000);
});
Promise.allSettled([settledPromise1, settledPromise2]).then(results => {
console.log("All promises settled with results: ", results);
});
4、Promise.any()
它在传入的可迭代对象中的任意一个 Promise 成功时解决,并返回第一个解决的 Promise 的值。如果传入的可迭代对象中的所有 Promise 都失败了,则返回一个拒绝的 Promise,其中包含一个 AggregateError,包含所有失败的 Promise 的原因
// 使用 Promise.any 来处理多个 Promise 对象,只要有一个成功就返回
const anyPromise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Any Promise 1 failed");
}, 1500);
});
const anyPromise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Any Promise 2");
}, 1000);
});
Promise.any([anyPromise1, anyPromise2]).then(value => {
console.log("The first promise to resolve is: ", value);
}).catch(errors => {
console.log("All promises were rejected with errors: ", errors);
});
5、Promise.resolve()
和 Promise.reject()
:快速创建已解决或已拒绝的 Promise。
// 使用 Promise.resolve 返回一个 resolved 的 Promise 对象
const resolvedPromise = Promise.resolve("Resolved value");
// 使用 Promise.reject 返回一个 rejected 的 Promise 对象
const rejectedPromise = Promise.reject("Rejected reason");
八、静态方法如何定义
在静态方法中,返回一个Promise对象,通过setTimeout模拟异步操作,并在1秒后通过resolve方法返回结果。
class MyClass {
static staticMethod() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("This is a static method");
}, 1000);
});
}
}
MyClass.staticMethod().then(result => {
console.log(result);
});
九、实例上的方法如何定义
在实例方法中,我们返回一个Promise对象,通过setTimeout模拟异步操作,并在1秒后通过resolve方法返回带有实例属性name的结果。
class MyClass {
constructor(name) {
this.name = name;
}
instanceMethod() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello, my name is " + this.name);
}, 1000);
});
}
}
const myInstance = new MyClass("Alice");
myInstance.instanceMethod().then(result => {
console.log(result);
});
十、创建一个promise
// 创建一个 Promise 对象
const myPromise = new Promise((resolve, reject) => {
// 在 Promise 内部进行异步操作
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber); // 成功时调用 resolve
} else {
reject("Promise rejected"); // 失败时调用 reject
}
}, 1000);
});
// 使用 then 方法处理 Promise 的 resolve 结果
myPromise.then(result => {
console.log("Resolved with result: " + result);
}).catch(error => {
console.log("Rejected with error: " + error); // 捕获并处理错误
});
创建了一个Promise对象myPromise
,传入一个executor函数,该函数接受两个参数resolve
和reject
。在executor函数内部,我们使用setTimeout模拟异步操作,1秒后生成一个随机数,如果随机数大于0.5,则调用resolve方法并传入随机数作为成功的结果;如果随机数小于等于0.5,则调用reject方法并传入错误信息作为失败的原因。然后我们使用then方法来处理Promise的resolve结果,并使用catch方法来捕获并处理Promise的reject结果。