文章目录
- 一、概述
- 二、同步模式/异步模式
- 2.1 同步模式
- 2.2 异步模式
- 三、回调函数
- 四、Promise (一种更优的异步编程统一方案)
- 4.1 概述
- 4.2 Promise 的基本用法
- 4.3 Promise 使用案例
- 4.4 Promise 常见误区
- 4.5 Promise 链式调用
- 4.6 Promise 异常处理
- 4.7 Promise 静态方法
- 4.7.1 Promise.resolve()
- 4.7.2 Promise.reject()
- 4.8 并行执行
- 4.8.1 Promise.all()
- 4.8.2 Promise.race()
- 4.9 执行时序(宏任务/微任务)
- 五、Generator 异步方案
- 5.1 为什么要引入 Generator
- 5.2 Generator 概念
- 5.3 体验 Generator 函数异步方案
- 5.4 递归 Generator 函数异步方案
- 六、Async / Await 语法糖(ES8 规范新增)
next() 方法的返回值类似于迭代器,有一个 done 属性和一个 value 属性。函数体为空的生成器函数中间不会停留,调用一次 next() 就会让生成器到达 done: true 状态yield 关键字可以让生成器停止和开始执行,也是生成器最有用的地方,会让生成器到达 done: false 状态。生成器函数在遇到 yield 关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域的状态会被保留。停止执行的生成器函数只能通过在生成器对象上调用 next() 方法来恢复执行function* foo() {
console.log("start");
try {
const res = yield "foo";
console.log(res);
} catch (e) {
console.log(e);
}
}
const generator = foo();
const result = generator.next();
console.log(result);
generator.next("bar"); // 如果传入一个参数,那么会作为 yield 左侧变量的返回值
generator.throw(new Error("Generator error"));
5.3 体验 Generator 函数异步方案
function ajax(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "json";
xhr.onload = function () {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
xhr.send();
});
}
function* main() {
const users = yield ajax("/api/users.json");
console.log(users);
}
const g = main();
const result = g.next();
result.value.then((data) => {
g.next(data);
});
5.4 递归 Generator 函数异步方案
function ajax(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "json";
xhr.onload = function () {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
xhr.send();
});
}
function* main() {
try {
const users = yield ajax("/api/users.json");
console.log(users);
const posts = yield ajax("/api/posts.json");
console.log(posts);
const urls = yield ajax("/api/urls.json");
console.log(urls);
} catch (e) {
console.log(e);
}
}
function co(generator) {
const g = generator();
function handleResult(result) {
if (result.done) return; // 生成器函数结束
result.value.then(
(data) => {
handleResult(g.next(data));
},
(error) => {
g.throw(error);
}
);
}
handleResult(g.next());
}
co(main);
像这样的生成器函数在社区中早就有一个更完善的库,就叫做 co
六、Async / Await 语法糖(ES8 规范新增)
- 相比于 Generator 最大的好处它不需要再配合一个类似 co 这样的执行器,因为他是语言层面的标准异步编程语法
- async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头函数和方法上
- Async 函数可以给我们返回一个 Promise 对象,这样更利于我们对整体代码进行控制
- 使用 async 关键字可以让函数具有异步特征,但总体上其代码仍然是同步求值的。而在参数或闭包方面,异步函数仍然具有普通 JavaScript 函数的正常行为
- 因为异步函数主要针对不会马上完成的任务,所以自然需要一种暂停和恢复执行的能力。使用 await 关键字可以暂停异步函数代码的执行,等待期约解决
- 除此之外,还有一个点需要注意:async 中使用的 await 关键词,只能出现在 async 函数内部,它不能直接在外部也就是最顶层作用于使用
注意:await 关键字会暂停执行异步函数后面的代码,让出 JavaScript 运行时的执行线程。这个行为与生成器函数中的 yield 关键字是一样的
async function main () {
try {
const users = await ajax('/api/users.json')
console.log(users)
const posts = await ajax('/api/posts.json')
console.log(posts)
const urls = await ajax('/api/urls.json')
console.log(urls)
} catch (e) {
console.log(e)
}
}
// co(main)
const promise = main()
promise.then(() => {
console.log('all completed')
})