在 JavaScript 中,可以使用异步操作来处理那些需要等待某些操作完成后才能继续执行的代码。异步操作可以帮助我们在进行网络请求、读写文件、处理大量数据等情况下,避免阻塞主线程,提高程序的性能和响应能力。
下面介绍几种常见的异步操作的处理方式:
回调函数(Callbacks)
使用回调函数是一种传统的异步操作处理方式。你可以在异步函数中接受一个回调函数作为参数,在异步操作完成后调用该回调函数。例如:
function fetchData(callback) {
// 异步操作,比如发起网络请求
// ...
// 异步操作完成后调用回调函数
callback(result);
}
// 使用回调函数处理异步操作的结果
fetchData(function(result) {
// 处理异步操作的结果
// ...
});
Promise和async/await这两个我一直会搞混,感觉很乱,在这里系统总结一下
他们的区别和联系:
- async/await 是基于 Promise 的语法糖,它们可以一起使用,而不是互斥的关系。
- Promise 是一种基于回调的异步编程模型,它使用 .then() 和 .catch() 方法来处理异步操作。
async/await 是一种基于 Generator 的异步编程模型,它使用 async 和 await 关键字来处理异步操作。
Promise
使用步骤:
- 在要等待执行的函数中创建一个 Promise 对象,并在 Promise 构造函数中编写要异步执行的代码,即异步操作代码
- 异步操作完成后,调用 resolve(value) 方法将 Promise 对象状态改为 Fulfilled,并传递操作的结果 value(这个值会传给.then函数的入参);或者调用 reject(reason) 方法将 Promise 对象状态改为 Rejected,并传递操作失败的原因 reason(这个值会传给.catch函数的入参)
- 返回 Promise 对象,以便在调用该函数时使用 Promise 的方法( .then()、.catch())来处理异步操作的结果或错误
示例:
function asyncOperation() {
return new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true; // 假设异步操作成功
if (success) {
resolve('Success'); // 异步操作成功时调用 resolve
} else {
reject(new Error('Error')); // 异步操作失败时调用 reject,并传递 Error 对象
}
}, 2000);
});
}
const promise = asyncOperation();
promise.then(result => {
console.log(result); // 输出: Success
}).catch(error => {
console.error(error); // 输出: Error 对象或错误信息
});
异步/等待(Async/Await)——较推荐
异步/等待是 ES2017 引入的一种处理异步操作的语法糖,它基于 Promises,并提供了更简洁的代码结构。使用异步/等待,可以在异步函数中使用 await 关键字来等待异步操作的结果
首先,async函数本身会隐式返回一个Promise对象,因此可以使用 Promise 的方法(如 .then()、.catch())来处理 async 函数的结果。什么意思呢?就是如果你在async中写了return语句,那么该返回值会被自动包装在一个 Promise 对象中,并成为该 Promise 对象.then方法的入参,例子:
async function myAsyncFunction() {
return 'Hello, async/await!';
}
const promise = myAsyncFunction();
promise.then(result => {
console.log(result); // 输出: Hello, async/await!
});
如果你在async中不写return,那async仍然隐式地返回了一个已解决的 Promise ,只不过它的值为undefined,如下:
async function myAsyncFunction() {
// 没有明确的返回语句
}
const promise = myAsyncFunction();
promise.then(result => {
console.log(result); // 输出: undefined
});
async/await 使用步骤:
- 在函数声明前加上 async 关键字,表示该函数是一个异步函数,可以使用 await 关键字等待异步操作的完成。
- 在异步操作前使用 await 关键字,等待异步操作的结果。
- 使用 try/catch 块来捕获可能的错误,其中 try 块中的代码表示等待异步操作的完成,catch 块中的代码表示处理异步操作失败的情况。
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Success');
} else {
reject('Error');
}
}, 2000);
});
}
async function handleAsyncOperation() {
try {
const result = await asyncOperation(); // 等待异步操作完成
console.log(result); // 异步操作成功时的处理逻辑
} catch (error) {
console.error(error); // 异步操作失败时的处理逻辑
}
}
上述代码中,await 关键字用于等待异步操作的结果,将结果赋值给变量 result,然后可以直接处理该结果。注意,函数体内使用 await 的函数(即handleAsyncOperation())必须在定义时使用 async 关键字进行声明,且其await的函数(即asyncOperation())应该满足该方法会返回一个 Promise 对象的要求;
原因:
一句话总结: await 关键字只能在异步函数内部使用,并且它需要等待一个 Promise 对象的完成。
具体来说:在 JavaScript 中,await 关键字用于暂停异步函数的执行,等待一个 Promise 对象的状态变为 resolved(已完成)或 rejected(已拒绝),然后获取 Promise 对象的结果。
因此为了使用 await,必须将要等待的操作包装在一个 Promise 对象中。这样,当调用异步函数并使用 await 等待该操作时,await 关键字将暂停函数的执行,直到 Promise 对象的状态变为 resolved 或 rejected——所以一定要在Promise对象中写resolve()和reject(),否则没有返回,await会一直卡在那儿,无法往下执行。
如:
getPostDetail() {
return new Promise((resolve, reject) => {
const url = "/pages/test";
const id = 1;
wx.request({
url: `${url}/${id}`,
method: 'GET',
success: (res) => {
if (res.statusCode === 200) {
const data = res.data;
if (data.errno === 0) {
this.setData({
item: data.data
});
resolve(); // 异步操作成功,调用 resolve(),记得要写这个!否则没有返回await会一直卡在那儿
} else {
console.log(data.errmsg);
reject(data.errmsg); // 异步操作失败,调用 reject(),记得要写这个!否则没有返回await会一直卡在那儿
}
} else {
reject('Request failed'); // 异步请求失败,调用 reject()
}
},
fail: (error) => {
console.log(error);
reject(error); // 异步操作失败,调用 reject()
}
});
});
}
async naviToPost(){
await this.getPostDetail()
let url = `/pages/hhh`
const params = `?info=${encodeURIComponent(JSON.stringify(this.data.item))}`
wx.navigateTo({
url: url + params
});
},