1.异步编程的背景
js引擎是基于单线程事件循环的概念构建的,同一时刻只允许一个代码块执行,所以需要跟踪即将运行的代码,每当一段代码准备执行时,都会被添加到任务队列。
- 事件模型:用户点击按钮或按下键盘按键会触发类似onclick事件,它会向任务队列添加一个新任务来响应用户的操作,直到事件触发时才执行。事件模型适用于处理简单的交互,多个异步调用时,必须跟踪每个事件的目标,且必须保证事件在添加后才触发,对复杂的需求来说不灵活。
- 回调模式:回调模式中,被调用的函数是作为参数传入的。通过回调模式可以链接多个调用,但嵌套太多会陷入回调地狱。
2.Promise基础
Promise相当于异步操作结果的占位符,它不会去订阅事件或者传递一个回调函数,而是返回一个Promise。如:
// readFile 承诺将在未来的某个时刻完成
let promise = readFile("example.txt");
readFile()不会立即开始读取文件,函数会先返回一个表示异步读取操作的Promise对象,未来对这个对象的操作完全取决于Promise的生命周期。
每个Promise都会经历一个短暂的生命周期:先是处于进行中(pending),此时操作尚未完成,所以它是未处理(unsettle);一旦异步操作执行结束,则变为已处理(settled)。会进入成功(fulfilled)或失败(rejected)。
3.创建未完成
Promise的执行器会立即执行,然后才执行后续流程中的代码,最后执行then和catch中的代码,。如:
let promise = new Promise(function(resolve, reject) {
console.log("Promise");
resolve();
});
promise.then(function() {
console.log("Resolved");
});
console.log("Hi");
// Promise
// Hi
// Resolved
4.创建已处理
可以分别用resolve和reject来创建,如:
Promise.resolve(42).then(function(value) {
console.log(value); // 42
});
Promise.reject(42).catch(function(value) {
console.log(value); // 42
});
5.全局拒绝处理
在没有拒绝处理程序的情况下拒绝一个Promise,不会提示失败信息,这是js中唯一没有强制报错的地方。
以node.js为例,处理Promise拒绝时会触发process对象上的两个事件:
- unhandledRejection 在一个事件循环中,当Promise被拒绝,并且没有提供拒绝处理程序时,触发该事件。
- rejectionHandled 在一个事件循环后,当Promise被拒绝时,若拒绝程序被调用,触发该事件。
let rejected;
process.on("unhandledRejection", function(reason, promise) {
console.log(reason.message); // "Explosion"
console.log(rejected === promise); // true
});
process.on("rejectionHandled", function(promise) {
console.log(rejected === promise); // true
});
rejected = Promise.reject(new Error("Explosion"));
6.async
用async标记的函数代替生成器,表示该函数以异步模式运行;用await代替yield来调用函数,函数应该返回一个Promise;最终可以按照同步方式编写异步代码,唯一开销是一个基于迭代器的状态机。