第12章 异步 
setTimeout 
- 设置一个定时器,在定时器到期后执行其中的回调函数
- setTimeout 只会执行一次
声明定时器
js
// 以下代码输出顺序依次为
// 第一行代码
// 第二行代码
// 1秒后执行
console.log('第一行代码');
let timer = setTimeout(() => {
  console.log('1秒后执行');
}, 1000);
console.log('第二行代码');清除定时器
- clearTiemrout() 用于清除 setTimeout
js
// 加上以下代码后,timer 将不会执行
setTimeout(() => {
  clearTimeout(timer);
  console.log('中断timer');
}, 500);setInterval 
- setInterval 与 setTimeout类似
- setInterval 每过一段时间就会执行一次
- clearInterval() 可以用来清除定时器
js
let interval = setInterval(() => {
  let date = new Date();
  console.log(`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);
}, 1000);
// 五秒之后取消Interval
setTimeout(() => {
  clearInterval(interval);
}, 5000);Promise 
基本概念
- Promise 可以创建自定义的异步操作
- Promise 是一个构造函数
创建 Promise
- 通过 new 可以创建 Promise 实例对象 
- Promise 在创建后会立即执行(同步) 
- resolve:通过 .then 指定的「成功的回调函数」 
- reject:通过 .then 指定的「失败的回调函数」 
js
function odd(number) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (number % 2 !== 0) {
        resolve(`${number}是奇数`);
      } else {
        reject(`${number}不是奇数`);
      }
    }, 500);
  });
}完成回调
- Promise可以使用 .then 获取执行结果
- .then 接受两个参数 - 第一个为成功的回调函数(必须)
- 第二个为失败的回调函数(非必须)
 
js
odd(number).then(
  (res) => {
    console.log('resolve: ' + res);
  },
  (err) => {
    console.log('rejcet: ' + err);
  }
);异常捕获
- reject 用于返回异常信息
- 用 catch 捕获错误信息
- then 失败回调与 catch 的区别: - then 成功回调中抛出的异常,后面的 catch 能捕获到,而 then 的失败回调捕获不到
- then 的失败回调与 catch 捕获错误信息的时候会采用就近原则
- 建议总是使用 catch 捕获错误信息,而不使用 then 的第二个参数(失败回调)
 
js
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('执行失败');
  }, 1000);
});
promise.catch((error) => {
  console.log(error); // 执行失败
});三种状态
- pending、resolved、rejected
- pending 状态,不会触发 then 和 catch
- resolved 状态,会触发后续的 then 回调
- rejected 状态,会触发后续的 catch 回调
- then 正常返回 resolved,里面有报错则返回 rejected
- catch 正常返回 resolved,里面有报错则返回 rejected
多个 Promise 同时执行
- Promise.all 可以使多个 Promise 同时执行 - 所有异步操作全部完成后,会返回一个整体的大 Promise
- then 之后会返回一个数组,里面为每个 Promise 的返回值
- 返回值的顺序与传入 Promise 时的顺序相同
 
- Promise.race 也可以使多个 Promise 同时执行 - 第一个 Promise 执行完毕后,返回该 Promise 结果
 
js
let p1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});
let p2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(2);
  }, 2000);
});
let p3 = new Promise((resolve) => {
  setTimeout(() => {
    resolve(3);
  }, 500);
});
Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [1, 2, 3]
});
Promise.race([p1, p2, p3]).then((values) => {
  console.log(values); // 3
});async & await 
基本概念
- async & await用来简化 Promise 异步操作
- async 创建的函数相当于创建了一个 Promise
使用
- await 可用于接受另一个 async 函数的结果
- await 关键字必须在带 async 的函数中调用
- 出现异常时,可以使用 try...catch 捕获异常
- 第一个 await 之前的代码会同步执行,之后的会异步执行
js
async function async1() {
  let result2 = await async2();
  let result3 = await async3();
  console.log(result2);
  console.log(result3);
}
async function async2() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(10);
    }, 1000);
  });
}
async function async3() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(5);
    }, 500);
  });
}
async1();Event Loop 
概念
- JavaScript 是一门单线程执行的编程语言,同一时间只能做一件事
- 为了防止某个耗时任务导致程序假死,JavaScript 把任务分为同步任务与异步任务
同步任务 & 异步任务
- 同步任务 - 在主线程上执行
- 只有前一个任务执行完毕,才能执行后一个任务
 
- 异步任务 - 由宿主环境(浏览器、Node)进行执行
- 当异步任务执行完毕后,会通知主线程执行回调函数
- 其中异步任务又分为宏任务与微任务
 
宏任务 & 微任务
- 宏任务:DOM 渲染后触发 - 异步 Ajax 请求
- setTimeout、setInterval
- 文件操作
 
- 微任务:DOM 渲染前触发 - Promise.then、.catch与.finally
- process.nextTick
 
执行顺序
- 同步任务由主线程依次执行
- 异步任务委托给宿主环境执行
- 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
- 同步任务执行完毕后,查看是否有未执行的微任务,有则执行
- 所有微任务执行完毕后,执行下一个宏任务
- 每次宏任务执行完毕后,查看是否有未执行的微任务,有则执行
- 重复以上步骤









