JavaScript 是单线程的,但它并不是无法处理异步操作。相反,JavaScript 的单线程特性和其事件循环机制使得它在处理异步任务方面非常高效
回调函数(Callback Functions)
一开始JS使用回调的形式来处理异步的结果,但是异步的弊端很大
例如:无法更好的处理错误,无法追溯数据来源,无法使用同步,回调地狱等问题
javascript">console.log("开始");setTimeout(() => {console.log("异步操作完成");
}, 1000);console.log("结束");//result开始
结束
异步操作完成
回调地狱是最头疼的,所以就需要改变他
javascript">setTimeout(() => {console.log("第一步完成");setTimeout(() => {console.log("第二步完成");setTimeout(() => {console.log("第三步完成");}, 1000);}, 1000);
}, 1000);
Promise(Promise A+ 规范)
所谓Promise 就是一个承诺
Promise的状态
Pending
(待定): 初始状态,既不是成功也不是失败resolved
/fullfilled
(已完成): 表示操作成功完成Rejected
(已失败): 表示操作失败
javascript">//初始状态
let promise = new Promise((resolve, reject) => {// promise 初始状态是 pending
});//Fulfilled
let promise = new Promise((resolve, reject) => {resolve('成功的结果');
});promise.then((value) => {console.log(value); // 输出: 成功的结果
});//Rejected
let promise = new Promise((resolve, reject) => {reject('失败的原因');
});promise.catch((reason) => {console.log(reason); // 输出: 失败的原因
});
切记你从一个状态改变到另一个状态后就无法再改变了
Promise的存储
Promise
的状态可以从pending
变为fulfilled
或rejected
,但一旦变为fulfilled
或rejected
,就不能再变为其他状态。这种状态的不可变性确保了Promise
的一致性和可靠性,每一种状态都会有定义的返回的值
当执行函数调用 resolve
时,Promise
的状态从 pending
变为 fulfilled
resolve
可以接受一个参数,作为 Promise
成功的值, PromiseResult变为存储的数据 , 调用then的第一个回调函数来返回数据
javascript">let promise = new Promise((resolve, reject) => {setTimeout(() => {resolve('成功的结果');}, 1000);
});promise.then((value) => {console.log(value); // 1秒后输出: 成功的结果
});
当执行函数调用 reject
时,Promise
的状态从 pending
变为 rejected
reject
可以接受一个参数,作为 Promise
失败的原因, PromiseResult变为存储的数据 或 异常对象
javascript">let promise = new Promise((resolve, reject) => {setTimeout(() => {reject('失败的原因');}, 1000);
});promise.catch((reason) => {console.log(reason); // 1秒后输出: 失败的原因
});
Promise实例方法
.then
- 用于指定当
Promise
成功时的回调函数- 它接受两个参数,第一个是成功时的回调函数
onFulfilled
- 第二个是失败时的回调函数
onRejected
(可选)- 返回一个新的
Promise
对象
javascript">const p1 = new Promise((resolve, reject) => {resolve("成功!");// 或// reject(new Error("错误!"));
});p1.then((value) => {console.log(value); // 成功!},(reason) => {console.error(reason); // 错误! //但是这个回调不常用,建议使用.catch},
);
.catch
- 用于指定当
Promise
失败时的回调函数onRejected
- 抛出错误也可以使状态变为
Rejected
Promise
已对现,则catch
不会被调用- 返回一个新的
Promise
对象
javascript">let promise = new Promise((resolve, reject) => {reject('失败');
});promise.catch(function(reason) {console.log(reason); // 失败
});
.finally
- 用于指定不论
Promise
最终状态如何都会执行的回调函数- 返回一个新的
Promise
对象
javascript">function checkMail() {return new Promise((resolve, reject) => {if (Math.random() > 0.5) {resolve('Mail has arrived');} else {reject(new Error('Failed to arrive'));}});
}checkMail().then((mail) => {console.log(mail);}).catch((err) => {console.error(err);}).finally(() => {console.log('Experiment completed');});
Promise静态方法
.resolve
- 返回一个成功的以给定值解析后的
Promise
对象- 如果传入的参数是一个
Promise
对象,则参数的结果直接影响返回值- 如果不是
Promise
对象,那么就直接返会成功的Promise
对象- 该函数将嵌套的类
Promise
对象(例如,一个将被兑现为另一个Promise
对象的Promise
对象)展平,转化为单个Promise
对象,其兑现值为一个非thenable
值
javascript">Promise.resolve(42).then(function(value) {console.log(value); // 42 //resolve
});let p1 = Promise.resolve(521);
console.log(p1) //resolve
.reject
- 返回一个失败的 Promise
- 无论参数的形式,结果都是失败的,哪怕是成功的Promise
javascript">function resolved(result) {console.log('Resolved');
}function rejected(result) {console.error(result);
}Promise.reject(new Error('fail')).then(resolved, rejected);
// Expected output: Error: fail
.all
- 接受一个包含多个
Promise
的数组,返回的也是数组- 返回一个新的
Promise
, 当所有传入的Promise
都成功完成(fulfilled
)时完成- 或者只要有一个
Promise
失败(rejected
)时就失败并带有第一个被拒绝的原因
javascript">const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'foo');
});Promise.all([promise1, promise2, promise3]).then((values) => {console.log(values);
});
// Expected output: Array [3, 42, "foo"]
.race
- 接受一个包含多个
Promise
的数组- 返回一个新的
Promise
,谁先执行完毕,谁的结果就决定race
的结果
javascript">const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'one');
});const promise2 = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'two');
});Promise.race([promise1, promise2]).then((value) => {console.log(value);// Both resolve, but promise2 is faster
});
// Expected output: "two"
.any
- 接受一个可迭代对象
- 返回一个新的
Promise
,只要传入的Promise
中有一个成功,并返回第一个兑现的值- 如果所有的
Promise
都失败,则返回一个失败的Promise
,并附带一AggregateError
错误
javascript">const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));const promises = [promise1, promise2, promise3];Promise.any(promises).then((value) => console.log(value));// Expected output: "quick"
关于Promise的详细内容还有许多,本文仅做简略描述,请谅解
async与await (ES8/ES2017)
他的作用就是使你的promise代码看起来像同步一样
async
- 用于声明一个异步函数
- 异步函数默认返回一个
Promise
对象- 如果函数内部返回的是一个非
Promise
的值,它会被自动封装成Promise.resolve(value)
await
- 用于等待一个异步操作(即
Promise
)的完成await
必须在async
函数内部使用- 它会暂停代码执行,直到
Promise
的结果返回(成功或失败)
传统写法
javascript">function fetchData() {return new Promise((resolve) => {setTimeout(() => resolve("数据加载完成"), 1000);});
}fetchData().then((result) => {console.log(result);return "下一步操作";}).then((nextResult) => {console.log(nextResult);}).catch((err) => {console.error(err);});
新式写法
javascript">async function fetchData() {return new Promise((resolve) => {setTimeout(() => resolve("数据加载完成"), 1000);});
}async function run() {try {const result = await fetchData();console.log(result);const nextResult = "下一步操作";console.log(nextResult);} catch (err) {console.error(err);}
}run();