promise

64 阅读6分钟

promise

1.问题的产生

- 1.问题的产生
function req(url) {
    setTimeout(() => {
        if (url === 'favo.ico') {
            return 'suc'
        } else {
            return 'err'
        }
    }, 3000);
}

const res = req('favo.ico')
console.log("🚀 ~ res:", res) // undefined



- 2.最初的解决方法
function req(url, suc, err) {
  setTimeout(() => {
    if (url === "favo.ico") {
      suc()
    } else {
      err()
    }
  }, 1000)
}

function suc() {
  console.log("suc")
}

function err() {
  console.log("err")
}

req("favo.icon", suc, err)
// 缺点:太过灵活没有规范,传参有要求导致不便等问题

2.promise引入

- 1.引入
const pro = new Promise((resolve, reject) => {
  console.log("立即执行") // executor立即执行
})


- 2.重构问题的函数
function req(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === "favo.icon") {
        resolve("suc")
      } else {
        reject("err")
      }
    }, 1000)
  })
}

// 第一种写法
req("favo.icon")
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log(err)
  })

// 第二种写法
// req("favo.icon").then(
//   (res) => {
//     console.log(res)
//   },
//   (rej) => {
//     console.log(rej)
//   }
// )

// 好处:
// 统一规范,增强阅读性扩展性;小幅度减少回调地狱



- 3.promise的状态
// pending,fulfilled,rejected
// 注:状态从pending转为其他就不能再改变了



- 4.resolve传入不同值的区别
// 传入一个普通值或对象
const pro = new Promise((resolve, reject) => {
  resolve({ name: "a", age: 1 })
})

pro.then((res) => {
  console.log(res) // { name: "a", age: "b" }
})

// 传入一个promise,新的promise状态决定原promise状态
const pro = new Promise((resolve, reject) => {
  resolve(
    new Promise((resolve, reject) => {
      resolve("aaa")
      //   reject("bbb")
    })
  )
})

pro
  .then((res) => {
    console.log("🚀 ~ pro.then ~ res:", res)
  })
  .catch((err) => {
    console.log("🚀 ~ err:", err)
  })
  
// thenable:传入一个对象,该对象实现了then方法,取决于调用了resolve或reject
const pro = new Promise((resolve, reject) => {
  resolve({
    then(resolve, reject) {
      reject("a")
    },
  })
})

pro
  .then((res) => {
    console.log("🚀 ~ pro.then ~ res:", res)
  })
  .catch((err) => {
    console.log("🚀 ~ err:", err)
  })



- 5.promise的实例方法
- 5.1.then
// 正常使用
const promise = new Promise((resolve, reject) => {
  resolve("a")
  reject("b")
})
promise.then(
  (res) => {},
  (rej) => {}
)

// 只捕获错误,第一位用null或''
const pro = new Promise((resolve, reject) => {
  reject("b")
})
pro.then(null, (rej) => {
  console.log(rej)
})

// 多次调用,多次输出

// then的返回值:then的返回值是一个promise,这个promise的状态如何决定?
// 返回一个普通值,或没有返回值相当于返回一个undefined-->resolve
const pro = new Promise((resolve, reject) => {
  resolve("a")
})
pro
  .then((res) => {
    console.log(res)
  })
  .then((res) => console.log(res))
// a,undefined

// 明确返回一个promise,取决于新promise的状态
const pro = new Promise((resolve, reject) => {
  resolve("a")
})
pro
  .then((res) => {
    return new Promise((resolve, reject) => {
      reject("b")
    })
  })
  .then((res) => console.log(res))
  .catch((rej) => {
    console.log(rej)
  })
  
// 返回一个thenable,取决于thenble
const promise = new Promise((resolve, reject) => {
  resolve("a")
})
promise
  .then((res) => ({
    then(resolve, reject) {
      resolve("b")
    },
  }))
  .then(
    (res) => {
      console.log("🚀 ~ promise.then ~ res:", res)
    },
    (rej) => {
      console.log("🚀 ~ promise.then ~ rej:", rej)
    }
  )
  
  
- 5.2catch
// 多次调用,多次捕获错误

// catch的返回值
// 返回一个普通值
const promise = new Promise((resolve, reject) => { reject() })
promise.catch(() => 1).then((res) => { console.log(res) })

// 返回一个promise
const promise = new Promise((resolve, reject) => { reject('1') })
promise.catch((res) => { return new Promise((resolve, reject) => { resolve(res) }) }).then(res => { console.log(res); }) // 1
promise.catch((res) => { return new Promise((resolve, reject) => { reject(res) }) }).catch(res => { console.log(res); }) // 1

// 返回一个thenable
const promise = new Promise((resolve, reject) => { reject('1') })
promise.catch((res) => ({ then(resolve, reject) { resolve(res) } })).then(res => { console.log(res); })
promise.catch((res) => ({ then(resolve, reject) { reject(res) } })).catch(res => { console.log(res); })



- 5.3.finally
// 永远执行
const promise = new Promise((resolve, reject) => {
    resolve('1')
})
promise.then((res) => console.log(res)).finally(() => { console.log('finally'); })



- 6.Promise上的类(静态)方法
- 6.1.resolve/reject
Promise.resolve('a').then(res => console.log(res))
Promise.reject('b').then('', rej => console.log(rej))


- 6.2.all
// 传入一个可迭代对象,返回一个promise,全为resolve则then,有一个reject用catch捕获
// 全resolve
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(1) }, 1000)
})
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(2) }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(3) }, 3000)
})
Promise.all([promise1, promise2, promise3]).then((res) => console.log(res)) // 3秒后输出[1,2,3]

// 有reject
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(1) }, 1000)
})
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => { reject(2) }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(3) }, 3000)
})
Promise.all([promise1, promise2, promise3]).then((res) => console.log(res)).catch(rej => console.log(rej)) // 2


-6.3.allSettled
// all中有一个reject就拿不到全部数据了,es11中引入allSettled,全有结果就返回,有一个没结果不返回
// 全有结果
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(1) }, 1000)
})
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => { reject(2) }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(3) }, 3000)
})
Promise.allSettled([promise1, promise2, promise3]).then((res) => console.log(res)).catch(rej => console.log(rej))
// [
//     { status: 'fulfilled', value: 1 },
//     { status: 'rejected', reason: 2 },
//     { status: 'fulfilled', value: 3 }
// ]

// 存在没结果的promise
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(1) }, 1000)
})
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => { reject(2) }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => { }, 3000)
})
Promise.allSettled([promise1, promise2, promise3]).then((res) => console.log(res)).catch(rej => console.log(rej))
// 无返回



- 6.4.race
// 返回第一个完成的结果,无论fulfilled还是rejected
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(1)
    }, 1000)
})
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(2)
    }, 2000)
})
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => { }, 3000)
})
Promise.race([promise1, promise2, promise3])
    .then((res) => console.log(res, "then"))
    .catch((rej) => console.log(rej, "catch")) // 1 catch
    
    
    
- 6.5.any
// 返回第一个fulfiled数据
// 全为reject则报错,[AggregateError: All promises were rejected] { [errors]: [ 1, 2, 3 ] }
const pro1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(1)
    }, 1000)
})
const pro2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(2)
    }, 2000)
})
const pro3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(3)
    }, 3000)
})

Promise.any([pro1, pro2, pro3])
    .then((res) => {
        console.log(res)
    })
    .catch((err) => {
        console.log(err)
    })

3.回调地狱

- 1.回调地狱的产生
// 回到最初的问题,异步调用网络请求之后,再次调用,再次调用
function request(params) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (params.includes("ice")) {
                resolve("suc")
            } else {
                reject("err")
            }
        }, 200)
    })
}

// 第一种写法
request('ice.icon').then(res => {
    request(`ice${res}`).then(res => {
        request(`ice${res}`).then(res => {
            console.log(res);
        })
    })
})
// 第二种写法
request('ice.icon').then(res => {
    return request(`ice${res}`)
}).then(res => {
    return request(`ice${res}`)
}).then(res => {
    console.log(res);
})


- 2.使用生成器+promise
function request(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (url.includes("i")) {
                resolve(url)
            } else {
                reject("失败")
            }
        }, 1000)
    })
}

function* getData(params) {
    const res1 = yield request(params)
    const res2 = yield request(res1)
    const res3 = yield request(res2)
}

const generate = getData("icon")

generate.next().value.then((res1) => {
    generate.next(`i${res1}`).value.then((res2) => {
        generate.next(`i${res2}`).value.then((res3) => {
            generate.next(res3)
        })
    })
})


/**
 * 3.封装自动化执行函数
 * 总结:async/await的核心代码其实就是内部主动调用.next方法
 */
function request(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (url.includes("i")) {
                resolve(url)
            } else {
                reject("失败")
            }
        }, 1000)
    })
}

function* getData() {
    const res1 = yield request("i1")
    const res2 = yield request("i2" + res1)
    const res3 = yield request("i3" + res2)
    console.log(res3)
}

function asyncAuto(fn) {
    const generate = fn()
    const _auto = (result) => {
        const nextData = generate.next(result)
        const { done, value } = nextData
        if (done) return

        value.then((res) => {
            _auto(res)
        })
    }
    _auto()
}

asyncAuto(getData)


/**
 * 4.最终方法:async/await
 */
function request(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (url.includes("i")) {
                resolve(url);
            } else {
                reject("失败");
            }
        }, 1000);
    });
}

async function getData() {
    const res1 = await request('i1')
    const res2 = await request('i2' + res1)
    const res3 = await request('i3' + res2)
    console.log(res3);
}

getData()

4.async/await

/**
 * 1.async:异步的,用于申明一个异步函数
 * async内部代码是同步执行的
 */


/**
 * 2.异步函数的返回值
 * 普通函数返回什么就是什么,没返回则是undefined
 *
 * 异步函数:
 * 明确返回一个普通值,相当于promise.resolve("值")
 * 明确返回一个thenable,根据thenable决定
 * 明确返回一个promise,根据promise决定
 */


/**
 * 3.异步函数的异常处理
 * .catch
 * trycatch
 */
// catch捕获
async function hi() {
    console.log(res);
}
hi().catch(err => { console.log(err); })


// try catch
async function hi() {
    try {
        console.log(res)
    } catch (error) {
        console.log(error)
    }
}
hi()



/**
 * 4.await
 * 只能写在async异步函数中,普通函数不行
 *
 * 特点:
 * 通常后跟promise,可以是普通值,可以是thenable,可以是promise
 * 注:这个promise状态变为fulfiled才会执行await后的代码,相当于在.then中的回调,如果状态变为rejected,需要在函数内部trycatch或者链式调用
 */


function request(url) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (url.includes("i")) {
                resolve(url);
            } else {
                reject("失败");
            }
        }, 1000);
    });
}

const getReq = async () => {
    try {
        const res = await request('zz')
        console.log("🚀 ~ getReq ~ res:", res)
    } catch (error) {
        console.log("🚀 ~ getReq ~ error:", error)
    }
}

5.手写相关

1.all

Promise.myAll = function (params) {
  return new Promise((resolve, reject) => {
    let count = 0
    let completeCount = 0
    let result = []
    for (const iterator of params) {
      let i = count
      count++
      Promise.resolve(iterator).then(
        (res) => {
          result[i] = res

          completeCount++
          if (completeCount === count) {
            resolve(result)
          }
        },
        (err) => reject(err)
      )
    }

    if (count === 0) {
      resolve(params)
    }
  })
}

2.超时

// 第一种写法
function req() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("发送请求")
    }, 4000)
  })
}

function overSettimeout() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("超时")
    }, 3000)
  })
}

Promise.race([req(), overSettimeout()]).then(
  (res) => {
    console.log(res)
  },
  (err) => {
    console.log(err)
  }
)

// 第二种方法:封装函数可以传入函数和时间的方法
function req() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("发送请求")
    }, 4000)
  })
}

const promiseSetTimeout = (p) => {
  let timer = null
  const over = new Promise((resolve, reject) => {
    timer = setTimeout(() => {
      reject("超时")
    }, 3000)
  })
  return Promise.race([p(), over])
}

promiseSetTimeout(req)
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log(err, "err")
  })