# 异步任务的处理

  • 在 Promise 出来之前处理异步一般都是传入回调函数来解决,或者使用事件监听的方式
  • 下面以回调函数举个栗子:
function requsetDate(url, resolve, reject) {
  // 模拟网络请求
  setTimeout(() => {
    if (url === 'https://nekoaimer.com') {
        // 成功时回调
        resolve('success message')
    } else {
        // 失败时回调
        reject('failure message')
    }
  }, 2000)
}
requsetDate('https://nekoaimer.com',
  res => {
    console.log(res) // success message
},
  err => { 
    console.log(err)
})

在上面的解决方案中,我们确确实实可以解决请求函数得到结果之后,获取到对应的回调,但是它存在两个主要的问题:

  • 第一,我们需要自己来设计回调函数、回调函数的名称、回调函数的使用等;
  • 第二,对于不同的人、不同的框架设计出来的方案是不同的,那么我们必须耐心去看别人的源码或者文档,以便可以理解它这个函数到底怎么用;

# 什么是 Promise?

  • Promise 对象用于表示一个异步操作的最终完成 (或失败) 及其结果值。

  • 在通过 new 创建 Promise 对象时,我们需要传入一个回调函数,我们称之为 executor

    • 这个回调函数会被立即执行,并且给传入另外两个回调函数 resolve、reject;
    • 当我们调用 resolve 回调函数时,会执行 Promise 对象的 then 方法传入的回调函数;
    • 当我们调用 reject 回调函数时,会执行 Promise 对象的 catch 方法传入的回调函数;
  • 使用 Promise 对上面方法重构:

function requsetDate(url, resolve, reject) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === 'https://nekoaimer.com') {
          // 传入状态与参数
          resolve('success message')
      } else {
          // 传入状态与参数
          reject('failure message')
      }
    }, 2000)
  })
}
//then 方法传入的回调函数两个回调函数:
// 第一个回调函数,会在 Promise 执行 resolve 函数时,被回调
// 第二个回调函数,会在 Promise 执行 reject 函数时,被回调
requsetDate('https://nekoaimer.com')
.then(res => {
  console.log(res) // success message
}, err => {
  console.log(err)
})

# Promise 三种状态

  • 一个 Promise 必然处于以下几种状态之一:

    • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。

    • 已兑现(fulfilled): 意味着操作成功完成。

    • 已拒绝(rejected): 意味着操作失败。

// 注意: Promise 状态一旦确定下来,那么就是不可更改的 (锁定)
new Promise((resolve, reject) => {
  //pending 状态:待定 / 悬而未决的
  console.log("--------")
  resolve(`success`) // 处于 fulfilled 状态 (已敲定 / 兑现状态)
  console.log('********')
  // 上面 resolve 已经确定了状态  下面就不可更改
  reject(`failure`) // 处于 rejected 状态 (已拒绝状态)
})
  .then(res => {
  // 这里只会执行第一个状态 输出  failure
  console.log(`res:, ${res}`) 
}, err => {
  console.log(`err:, ${err}`)
})

# Promise.resolve(params)

# 普通的值或者对象 pending -> fulfilled

  • 字符串
new Promise((resolve, reject) => {
  resolve(`我是被传入的普通参数-> 字符串`)
})
.then(res => {
    console.log(res) // 我是被传入的普通参数 -> 字符串
})
  • 普通对象
new Promise((resolve, reject) => {
  resolve({message: `我是被传入的普通参数-> 对象`})
})
.then(res => {
    console.log(res) // {message: ' 我是被传入的普通参数 -> 对象 '}
})
  • 函数
new Promise((resolve, reject) => {
  resolve(function foo (){
    console.log(`我是被传入的普通参数-> ${this}`)
  })
})
.then(res => {
   console.log(res) // [Function: foo]
})
  • 箭头函数
new Promise((resolve, reject) => {
  resolve(() => {
    console.log(`我是被传入的普通参数-> ${this}`)
  })
})
.then(res => {
   console.log(res) // () => {console.log (`我是被传入的普通参数 -> ${this}`)}
})

# Promise

  • 传入一个 Promise : 那么当前的 Promise 的状态会由传入的 Promise 来决定,相当于状态进行了移交
const newPromise = new Promise((resolve, reject) => {
  // 如果当前 Promise 状态是 reject, 那么下面的 Promise 状态就会是 reject
  reject('newPromise reject')
})
new Promise((resolve, reject) => {
  // 因为 newPromise 是 Promise, 那么状态的决定会移交给 newPromise, newPromise 的状态是 reject, 那么此时状态就是 reject, 与当前 Promise 的 resolve 状态无关
  resolve(newPromise)
})
.then(res => {
  console.log(res)
})
.catch(err => {
   // 会执行这一步
  console.log(err) // newPromise reject
})

# thenable

  • 传入一个对象,并且这个对象有实现 then 方法 (并且这个对象是实现了 thenable 接口) 那么也会执行该 then 方法,并且又该 then 方法决定后续状态
new Promise((resolve, reject) => {
  const obj = {
    then: function (resolve, reject) {
      resolve('obj*-*resolve~')
    },
    catch: (resolve, reject) => {
      reject('resolve')
    }
  }
  // 传入对象并且有 then 或者 catch 方法 会被自动执行
  resolve(obj)
})
// 如果这里只调用了 then 方法 或者 then&catch 两种方法同时都调用了 都是会执行 then 方法的
.then(res => {
  console.log(`res->  ${res}`) // res->  obj*-*resolve~
})
// 如果没有执行 then 方法就会执行了 catch 方法 
// .catch(err => {
//   console.log(`err->  ${err}`)
// })

# Promise.then()

# then 多次调用

  • 一个 Promise 的 then 方法可以被多次调用:
    • 每次调用我们都可以传入对应的 fulfilled 回调
    • 当 Promise 的状态变成 fulfilled 的时候,这些回调函数都会被执行
// 当我们的 resolve 方法被回调时,所有的 then 方法传入的回调函数都会被调用
const promise = new Promise((resolve, reject) => {
  resolve(i = 0)
})
promise.then(res => {
  console.log(`${++res}次调用`) // 第 1 次调用
})
promise.then(res => {
  console.log(`${res + 2}次调用`) // 第 2 次调用
})
promise.then(res => {
  console.log(`${res + 3}次调用`) // 第 3 次调用
})

# then 返回值

  • then 方法本身是有返回值的,它的返回值是一个 Promise
  • 如果我们返回的是一个普通值 (数值 / 字符串 / 普通对象 /undefined), 那么这个普通的值被作为一个新的 Promise 的 resolve 值

# then 返回值是普通值

new Promise((resolve, reject) => {
   resolve(233)
 })
 .then(res => {
   console.log(res)
 })
// 上面相当于是返回了一个 Promise  所以我们可以进行 then 方法
new Promise((resolve, reject) => {
  resolve(233) // -> new Promise(resolve => {resolve(233)})
})
.then(res => {
  console.log(res) // 233
  return 'lain' // -> new Promise(resolve => {resolve(lain)})
})
.then(res => {
  console.log('lain') // lain
})
// 上面没有 return 默认返回 undefined
.then(res => {
  console.log(res) // undefined
})

# then 返回值是 Promise

  • 如果我们返回的是一个 Promise
new Promise((resolve, reject) => {
  resolve() 
})
.then(res => {
  // 回到了上面 resolve 参数的三种形式:Promise 的情况 这里的 Promise 会决定创建者 (new Promise) 的状态
  return new Promise((resolve, reject) => {
    setTimeout(() => { 
      resolve(2333)
    }, 2000)
  }) 
})
.then(res => {
  console.log(res) // 2s -> 2333
})

# then 返回值是实现 thenable 的对象

  • 如果返回的是一个对象,并且该对象实现了 thenable
new Promise((resolve, reject) => {
  resolve() 
})
.then(res => {
  // 这里也回到了上面讲过的实现了 thenable 对象
  return {
    then: function (resolve, reject) {
      resolve(2333)
    }
  }
})
.then(res => {
  console.log(`res: ${res}`) // res: 2333
})
  • 但是 then 方法返回的 Promise 到底处于什么样的状态呢?
  • Promise 有三种状态,那么这个 Promise 处于什么状态呢?
    • 当 then 方法中的回调函数本身在执行的时候,那么它处于 pending 状态;
    • 当 then 方法中的回调函数返回一个结果时,那么它处于 fulfilled 状态,并且会将结果作为 resolve 的参数;
      • 情况一:返回一个普通的值;
      • 情况二:返回一个 Promise;
    • 情况三:返回一个 thenable 值;
    • 当 then 方法抛出一个异常时,那么它处于 reject 状态;

# Promise.catch()

# then 第二个参数 catch

  • 第一个执行执行 resolve, 第二个参数执行 reject
new Promise((resolve, reject) => {
  reject('Reject Status')
})
.then(null, err => {
  console.log(err) // Reject Status
})
  • 当 then 抛出异常时,那么它处于 reject 状态,也是会调用错误 (拒绝) 捕获的回调函数的
new Promise((resolve, reject) => {
  throw new Error('Reject Status')  
})
.then(null, err => {
  console.log(err) // Error: Reject Status....
  console.log(`----------`) // ----------
})

# catch 优先捕获自身异常

  • 通过 catch 方法来传入错误 (拒绝) 捕获的回调函数
  • 通过上面我们都知道 then 方法是返回一个新的 Promise,而 catch 默认情况下会先捕获自身的 Promise
  • 举个栗子
new Promise((resolve, reject) => {
  throw new Error('Reject Status')  
})
// 我们通过上述会了解到 then 的 return 的这一个普通字符串的返回值返回的也是 Promise
// 但是 catch 拿到的值却依然是第一个 Promise 抛出异常的值
.then(res => {
  console.log(res)
  return res
})  
// 这里会执行第一个 Promise
.catch(err => {
  console.log(err) // Error: Reject Status....
})
  • catch 默认优先捕获 new Promise 的异常, 注释掉第一个 Promise, 才会捕获第二个 Promise 抛出的异常
new Promise((resolve, reject) => {
  // 当我们注释掉抛出异常 那么它就处于 reject 状态
  // throw new Error('Reject Status')  
  resolve()
})
.then(res => {
  // 当第一个 Promise 注释掉,then 返回一个 Promise 状态为 reject 时 
  return new Promise((resolve, reject) => {
    throw new Error('Reject Status2')
  })
})  
// 才会执行 then 的返回值 Promise
.catch(err => {
  console.log(err) // Error: Reject Status2
})

# 抛出异常未捕获到处理异常 (catch)

const promise = new Promise((resolve, reject) => {
  reject(233)
})
promise.then(res => {
  console.log(res);
})
// Uncaught (in promise) 233
  • 优先捕获自身处理的异常 (catch), 没找到就会找 then 返回的新的 Promise 的 catch
const promise = new Promise((resolve, reject) => {
  reject(233)
})
promise.then(res => {
  console.log(res);
})
// 本身没有 catch 捕获, 所以会来的 then 方法返回的新的 Promise 的 catch
.catch(err => {
  console.log('then返回新的Promise的catch', err) //hen 返回新的 Promise 的 catch 233
})
  • 我们可以验证下
const promise = new Promise((resolve, reject) => {
  reject(233)
}).catch(err => {
  console.log('自身Promise的catch', err) // 自身 Promise 的 catch 233
})
promise.then(res => {
  console.log(res);
})
.catch(err => {
  console.log('then返回的新的Promise的catch', err) // undefined
})

# 抛出异常的执行顺序

  • reject 优先的情况下 也会执行下面的代码
const promise = new Promise((resolve, reject) => {
  reject('reject') // 执行 reject 代码
  console.log(`---------`) // 但是这行代码依旧会执行了
  throw new Error('throw new Error')
})
.catch(err => {
  console.log(err) 
})
// 执行顺序:
// ---------
// reject
  • throw new Error 优先的情况下 不会执行下面的代码 类似 return 了
const promise = new Promise((resolve, reject) => {
  throw new Error('throw new Error') // 执行 reject 代码
  console.log(`---------`) // 但是这行代码不会执行了
  reject('reject')
})
.catch(err => {
  console.log(err) 
})
// 执行顺序:
// Error: throw new Error

# Catch 返回值

  • 事实上 catch 方法也是会返回一个 Promise 对象的,所以 catch 方法后面我们可以继续调用 then 方法或者 catch 方法:
  • 下面的代码,后续是 catch 中的 err2 打印,还是 then 中的 res2 打印?
new Promise((resolev, reject) => {
  reject('23333')
})
.then(res1 => { 
  console.log(`res1`, res1)  
})
.catch(err1 => {
  console.log('catch err1 -> ', err1) // catch err1 ->  23333
  return 'catch return value'
})
.then(res2 => {
  console.log(`res2 then -> `, res2) // res2 then ->  catch return value
})
.catch(err2 => {
  console.log(`err2 catch -> `, err2)  
})
  • 答案是 res2 打印,这是因为 catch 传入的回调在执行完后,默认状态依然会是 fulfilled 的;

  • 那么如果我们希望后续继续执行 catch,那么需要抛出一个异常

new Promise((resolev, reject) => {
  reject('23333')
})
.then(res1 => { 
  console.log(`res1`, res1)  
})
.catch(err1 => {
  console.log('catch err1 -> ', err1) // catch err1 ->  23333
  // 也可使用 reject 抛出异常
  throw new Error('catch throw new Error') 
})
.then(res2 => {
  console.log(`res2 then -> `, res2)
})
.catch(err2 => {
  console.log(`err2 catch -> `, err2)  // Error: catch throw new Error
})

未完待续......