以前学习写的笔记,感觉还不错,当初收回来,心愿对你有帮忙。

1. 前置常识

1.1 区别实例对象与函数对象

实例对象:new 函数产生的对象, 称为实例对象, 简称为对象

函数对象: 将函数作为对象应用时, 简称为函数对象

function Fn() {}const fn = new Fn() // fn为实例对象Fn.bind({}) // Fn为函数对象

1.2 两种类型的回调函数

同步回调

  • 了解:立刻执行, 齐全执行完了才完结, 不会放入回调队列中
  • 例子: 数组遍历相干的回调函数 / Promise 的 excutor 函数

异步回调

  • 了解:不会立刻执行, 会放入回调队列中未来执行
  • 例子:定时器回调 / ajax 回调 / Promise 的胜利|失败的回调
const arr = [1, 2, 3]arr.forEach(item => console.log(item)) // 同步回调, 不会放入回调队列, 而是立刻执行console.log('forEatch()之后')setTimeout(() => { // 异步回调, 会放入回调队列, 所有同步执行完后才可能执行  console.log('timout 回调')}, 0)console.log('setTimeout 之后')

1.3 JS的error解决

谬误的类型

  • Error:所有谬误的父类型
  • ReferenceError:援用的变量不存在

    console.log(a) // ReferenceError: a is not defined
  • TypeError:数据类型不正确的谬误

    let b = nullconsole.log(b.xxx) // TypeError: Cannot read property 'xxx' of null
  • RangeError:数据值不在其所容许的范畴内

    function fn() {  fn()}fn() // RangeError: Maximum call stack size exceeded
  • SyntaxError:语法错误

    let c = """" // SyntaxError: Unexpected string

错误处理

  • 捕捉谬误:try ... catch
  • 抛出谬误:throw error

error 对象的构造

  • message 属性:谬误相干信息
  • stack 属性:函数调用栈记录信息

2. Promise 是什么?

2.1 了解

形象表白:Promise 是JS中进行异步编程的新的解决方案(旧的是谁?=> 纯回调的模式)

具体表白:

  • 从语法上来说:Promise 是一个构造函数
  • 从性能上来说:Promise 对象用来封装一个异步操作并能够获取其后果

2.2 Promise的状态扭转

Promise的状态扭转只有这2种:

且一个 Promise 对象只能扭转一次,无论变成胜利还是失败,都会有一个后果数据,胜利的后果数据个别称为 value,失败的后果数据个别称为 reason

2.3 Promise根本流程

2.4 Promise的根本应用

示例,如果以后工夫是偶数就代表胜利,否则代表失败

// 1. 创立一个新的Promise对象const p = new Promise((resolve, reject) => { // 执行器函数,同步执行  // 2. 执行异步操作工作  setTimeout(() => {    const time = Date.now() // 如果以后工夫是偶数就代表胜利,否则代表失败    // 3.1 如果胜利了,调用resolve(value)    if (time % 2 === 0) {        resolve('胜利的数据,value = ' + time)    } else {        // 3.2 如果失败了,调用reject(reason)        reject('失败的数据,reason = ' + time)    }  }, 1000);})p.then(value => {  // 承受失去胜利的value数据,专业术语:onResolved  console.log('胜利的回调', value)}, reason => {  // 承受失去失败的reason数据,专业术语:onRejected  console.log('失败的回调', reason)})

3. 为什么要用Promise?

3.1 指定回调函数的形式更加灵便

旧的:回调函数必须在启动异步工作前指定

// 胜利的回调函数function successCallback(result) {  console.log('解决胜利:' + result)}function failureCallback(error) {  console.log('解决失败:' + error)}// 应用纯回调函数createAudioFileSync(audioSettings, successCallback, failureCallback)

Promise:启动异步工作 => 返回 Promise 对象 => 给 Promise 对象绑定回调函数,甚至能够在异步工作完结后指定多个

// 应用 Promiseconst promise = createAudioFileSync(audioSettings)setTimeout(() => {  promise.then(successCallback, failureCallback)}, 3000);

3.2 反对链式调用,能够解决回调天堂问题

什么是回调天堂?回调函数嵌套调用,内部回调函数异步执行的后果是嵌套的回掉执行条件,代码是程度向右扩大

// 回调天堂doSomething(function(result) {  doSomethingElse(result, function(newResult) {    doThirdThing(newResult, function(finalResult) {      console.log('Got the final result: ' + finalResult)    }, failureCallback)  }, failureCallback)}, 

回调天堂的毛病:不便浏览,不便于异样解决

解决方案:Promise 链式调用,代码程度向下扩大

doSomething().then(function(result) {  return doSomethingElse(result)}).then(function(newResult) {  return doThirdThing(newResult)}).then(function(finalResult) {  console.log('Got the final result: ' + finalResult)}).catch(failureCallback)

终极解决方案:async/await,用同步的写法解决异步的操作

async function request() {  try {    const result = await doSomething()    const newResult = await doSomethingElse(result)    const finalResult = await doThirdThing(newResult)    console.log('Got the final result: ' + finalResult)  } catch (error) {    failureCallback(error)  }}

4. Promise的API阐明

4.1 API 阐明

Promise 构造函数

Promise (excutor) {},excutor 会在 Promise 外部立刻同步回调,异步操作在执行器中执行

  • excutor 函数:执行器 (resolve, reject) => {}
  • resolve 函数:外部定义胜利时咱们调用的函数 value => {}
  • reject 函数:外部定义失败时咱们调用的函数 reason => {}

Promise.prototype.then办法

(onResolved, onRejected) => {},指定用于失去胜利 value 的胜利回调和用于失去失败 reason 的失败回调返回一个新的 promise 对象

  • onResolved 函数:胜利的回调函数 (value) => {}
  • onRejected 函数:失败的回调函数 (reason) => {}

Promise.prototype.catch 办法

(onRejected) => {},onRejected 函数:失败的回调函数 (reason) => {},then() 的语法糖, 相当于: then(undefined, onRejected)

Promise.resolve办法

(value) => {},value:胜利的数据或 promise 对象,返回一个胜利/失败的 promise 对象

Promise.reject办法

(reason) => {},reason:失败的起因,返回一个失败的 promise 对象

Promise.all办法

(promises) => {},promises:蕴含 n 个 promise 的数组,返回一个新的 promise, 只有所有的 promise 都胜利才胜利, 只有有一个失败了就间接失败

Promise.race办法

(promises) => {},promises: 蕴含 n 个 promise 的数组,返回一个新的 promise, 第一个实现的 promise 的后果状态就是最终的后果状态

// 产生一个胜利值为 1 的 Promise 对象const p1 = new Promise((resolve, reject) => {  resolve(1)})// 产生一个胜利值为 2 的 Promise 对象const p2 = Promise.resolve(2)// 产生一个失败值为 3 的 Promise 对象const p3 = Promise.reject(3)p1.then(value => console.log(value))p2.then(value => console.log(value))p3.catch(reason => console.error(reason))// const pAll = Promise.all([p1, p2])const pAll = Promise.all([p1, p2, p3])pAll.then(values => {  console.log('all onResolved()', values) // all onResolved() [ 1, 2 ]}, reason => {  console.log('all onRejected()', reason) // all onRejected() 3})const race = Promise.race([p1, p2, p3])race.then(value => {  console.log('all onResolved()', value) }, reason => {  console.log('all onRejected()', reason) })

4.2 Promise的几个关键问题

4.2.1 如何扭转Promise的状态

resolve(value),如果以后是 pendding 就会变为 resolved

reject(reason),如果以后是 pendding 就会变为 rejected

抛出异样,如果以后是 pendding 就会变为 rejected

const p = new Promise((resolve, reject) => {  // resolve(1) // Promise 变为 resolved 胜利状态  // reject(2) // Promise 变为 rejected 失败状态  // Promise 变为 rejected 失败状态,reason为抛出的 error  throw new Error('我抛出的异样')   // 变为 rejected 失败状态,reason为抛出的 3  // throw 3})p.then(  value => {},  reason => { console.log('reason :', reason); })

4.2.2 当一个promise指定多个胜利/失败回调函数, 都会调用吗?

当 promise 扭转为对应状态时都会调用

const p = new Promise((resolve, reject) => {  // 变为 rejected 失败状态,reason为抛出的 3  throw 3})p.then(  value => {},  reason => { console.log('reason :', reason); })p.then(  value => {},  reason => { console.log('reason2 :', reason); })// 后果:// reason : 3// reason2 : 3

4.2.3 扭转promise状态和指定回调函数谁先谁后?

都有可能, 失常状况下是先指定回调再扭转状态, 但也能够先改状态再指定回调。

如何先改状态再指定回调?

  • 在执行器中间接调用 resolve()/reject()
  • 提早更长时间才调用 then()

什么时候能力失去数据?

  • 如果先指定的回调, 那当状态产生扭转时, 回调函数就会调用, 失去数据
  • 如果先扭转的状态, 那当指定回调时, 回调函数就会调用, 失去数据
// 惯例:先指定回调函数,后扭转状态new Promise((resolve, reject) => {  setTimeout(() => {    resolve(1) // 后扭转状态(同时指定数据),异步执行回调函数  }, 1000);}).then( // 先指定回调函数,保留以后指定的回调函数  value => {},  reason => { console.log('reason :', reason); })// 先改状态,后指定回调函数new Promise((resolve, reject) => {  resolve(1) // 先扭转状态(同时指定数据)}).then( // 后指定回调函数,异步执行回调函数  value => { console.log('value2:', value);},  reason => { console.log('reason2 :', reason); })const p = new Promise((resolve, reject) => {  resolve(1) // 先扭转状态(同时指定数据)})setTimeout(() => {  p.then(    value => { console.log('value3:', value);},    reason => { console.log('reason3 :', reason); }  )}, 1500);

4.2.4 promise.then()返回的新 promise 的后果状态由什么决定?

简略表白:由 then()指定的回调函数执行的后果决定

具体表白:

  • 如果抛出异样, 新 promise 变为 rejected, reason 为抛出的异样
  • 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
  • 如果返回的是另一个新 promise, 此 promise 的后果就会成为新 promise 的后果
new Promise((resolve, reject) => {  resolve(1)}).then(  value => {    console.log('onResolved1()', value); // 1    // return 1.1 或     return Promise.resolve(1.1)    // return Promise.reject(1.1)    // throw 1.1  },  reason => {     console.log('onRejected1()', reason);  }).then(  value => { console.log('onResolved2()', value); }, // 1.1  reason => { console.log('onRejected2()', reason) } // 1.1)

4.2.5 promise 如何串连多个操作工作

promise 的 then() 返回一个新的 promise, 能够开成 then() 的链式调用,通过 then 的链式调用串连多个同步/异步工作。

4.2.6 promise 异样传透

当应用 promise 的 then 链式调用时, 能够在最初指定失败的回调,后面任何操作出了异样, 都会传到最初失败的回调中解决。

上面的示例代码演示了异样传透

new Promise((resolve, reject) => {  // resolve(1)  reject(1)}).then(  value => {     console.log('onResolved1()', value);    return 2  }).then(  value => {     console.log('onResolved2()', value);    return 3  }).then(  value => {     console.log('onResolved3()', value);  }).catch(  reason => {     console.log('onRejected()', reason);  // onRejected() 1  })

代码会执行 .catch 中的代码,但实际上代码的执行不是执行到第 3 行就间接跳转到 catch 外面了,而是从第一个 then 调用向下一个个的执行(逐级传递),然而因为咱们 then 外面没有解决异样。在 then 外面没写解决异样实际上相当于默认增加了 reason => { throw reason } 或者 reason => Promise.reject(reason)

new Promise((resolve, reject) => {  reject(1)}).then(  value => {  console.log('onResolved1()', value); },  // reason => { throw reason }  // 或者  reason => Promise.reject(reason))

Promise的异样传透示意图

4.2.7 中断 promise 链

当应用 promise 的 then 链式调用时, 在两头中断, 不再调用前面的回调函数。

方法: 在回调函数中返回一个 pendding 状态的 promise 对象

new Promise((resolve, reject) => { resolve(1)}).then(  value => {     console.log('onResolved1()', value);    return new Promise(() => {}) // 返回一个 pending 的 Promise,中断 promise 链  }).then( // 这个 then 不会执行力  value =>  { console.log('onResolved2()', value); })

5. async与await

Async/await 实际上只是一种基于promises的糖衣语法糖,Async/await 和 promises一样,都是非梗塞式的,Async/await 让异步代码更具同步代码格调,这也是其劣势所在。

  • async function 用来定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其后果,。如果你在代码中应用了异步函数,就会发现它的语法和构造会更像是规范的同步函数。MDN async_function
  • await 操作符用于期待一个Promise 对象。它只能在异步函数 async function 中应用。MDN await

5.1 async函数

async 函数的返回值为 Promise 对象,async 函数返回的 Promise 的后果由函数执行的后果决定

async function fn1() {  return 1}const result = fn1()console.log(result) // Promise { 1 }

在控制台能够看见如下信息

既然是Promise对象,那么咱们用 then 来调用,并抛出谬误,执行 onRejected() 且 reason 为错误信息为“我是谬误”

async function fn1() {  // return 1  // return Promise.resolve(1)  // return Promise.reject(2)  throw '我是谬误'}fn1().then(  value => { console.log('onResolved()', value) },  reason => { console.log('onRejected()', reason) } // onRejected() 我是谬误)

5.2 await表达式

await 右侧的表达式个别为 promise 对象, 但也能够是其它的值:

  • 如果表达式是 promise 对象, await 返回的是 promise 胜利的值
  • 如果表达式是其它值, 间接将此值作为 await 的返回值
function fn2() {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve(1000)    }, 1000);  })}function fn4() { return 6 }async function fn3() {  // const value = await fn2() // await 右侧表达式为Promise,失去的后果就是Promise胜利的value  // const value = await '还能够这样'  const value = await fn4()  console.log('value', value)}fn3() // value 6

await 必须写在 async 函数中, 但 async 函数中能够没有 await,如果 awaitPromise 失败了, 就会抛出异样, 须要通过 try...catch 捕捉解决

function fn2() {  return new Promise((resolve, reject) => {    setTimeout(() => {      // resolve(1000)      reject(1000)    }, 1000);  })}async function fn3() {  try {    const value = await fn2()  } catch (error) {    console.log('失去失败的后果', error)  }}fn3() // 失去失败的后果 1000

5.3 Async/await 比 Promise 更优越的体现

简洁洁净,应用async/await能省去写多少行代码

错误处理,async/wait 能用雷同的构造和好用的经典 try/catch 解决同步和异步谬误,谬误堆栈能指出蕴含谬误的函数。

调试,async/await 的一个极大劣势是它更容易调试,应用async/ await则无需过多箭头函数,并且能像失常的同步调用一样间接跨过await调用。


笔记首发于我的公众号《前端全栈开发者》