拼拼凑凑的Promise

293 阅读4分钟

一、 为什么是 Promise?

1 所有的 js 代码都是单线程执行的。

所有的事件,渲染,一切都是单线程的,我们并不希望个耗时操作阻塞用户进程,于是就有了异步的概念。

1.1 异步的基本原理

JavaScript 引擎负责解析,执行 JavaScript 代码,但它并不能单独运行,通常都得有一个宿主环境,一般如浏览器或 Node 服务器,前文说到的单线程是指在这些宿主环境创建单一线程,提供一种机制,调用 JavaScript 引擎完成多个 JavaScript 代码块的调度,这种机制就称为事件循环( Event Loop )。

1.2 异步的常见实现方法

  • 回调函数
  • Promise对象
  • Generator

1.3 为什么选择 Promise

1.3.1 回调函数

回调函数在处理越多的异步逻辑时,就需要越深的回调嵌套(回调地狱):

1.代码逻辑书写顺序与执行顺序不一致,不利于阅读与维护。

2.异步操作的顺序变更时,需要大规模的代码重构。

3.回调函数基本都是匿名函数,bug 追踪困难。
1.3.2 Generator

Generator 虽然也可以实现异步,但他仍是一个新的标准。 推荐大家去尝试一下这种新的写法。 不仅仅是在 dva 中使用。

Promise 可以更直观,更易用的方式 来解决 "回调地狱"

二、什么是 Promise?

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

有个标准叫做: Promises / A +

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject

Promise 新建后就会立即执行。

new Promise((resolve, reject) => {
  resolve(1)
})
new Promise((resolve, reject) => {
  reject(1)
})

1 术语

 "promise"是具有then方法的对象或函数,其行为符合此规范。

 "thenable"是定义then方法的对象或函数。 thenable对象指的是具有then方法的对象。

 "value"是任意合法的Javascript值,(包括undefined,thenable, promise)

 "exception"是使用throw语句抛出的值

 "reason"是表示promise为什么被rejected的值

2 Promise 相当于一个状态机

一个 promise 必须处于三种状态之一: 请求态(pending), 完成态(fulfilled),拒绝态(rejected)

  • 当promise处于请求状态(pending)时,promise可以转为fulfilled或rejected状态
  • 当promise处于完成状态(fulfilled)时
    • promise不能转为任何其他状态
    • 必须有一个值,且此值不能改变
  • 当promise处于请求状态(pending)时
    • promise不能转为任何其他状态
    • 必须有一个原因(reason),且此原因不能改变

3 Promise 的方法(常用)

3.1 then()

Promise.prototype.then()

then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

// 基本使用
new Promise((resolve, reject) => {
  resolve(1)
})
.then(value => {
  console.log(value) // 1
})

一般来说,不要在then()方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

// then 捕获错误(不建议)

// bad
new Promise((resolve, reject) => {
  resolve(1)
})
.then(success => {
  console.log(success) // 1
}, error => {
  console.log(error)
})

// bad
new Promise((resolve, reject) => {
  reject(1)
})
.then(success => {
  console.log(success)
}, error => {
  console.log('then 捕获错误', error) // then 捕获错误 1
})
.catch(error => {
  console.log('catch 捕获错误', error) // 思考:这行会被执行吗??
})
3.2 catch()
// 基本使用
new Promise((resolve, reject) => {
  reject(1)
})
.catch(e => {
  console.log('e',e) // e 1
})

关于错误捕获:

// try...catch() ?
try{
  y + 1
}catch(e){
 console.log('try...catch捕获的错误=>',e) // try...catch捕获的错误=> ReferenceError: "y is not defined"
}

// try ...promise... catch() ?

// 1.
try{
  new Promise((resolve, reject) => {
  	reject(1)
    c + 1
  })
}catch(e){
 console.log('try ...promise... catch捕获的错误=>',e) // 思考:c+1 能否被捕获??
}

// 2.
try{
  new Promise((resolve, reject) => {
  	reject(1)
    c + 1
	})
  .catch(e => {
    console.log('promise catch捕获的错误',e)  // 思考:c+1 能否被捕获??
    cc + 1
  })
}catch(e){
 console.log('try ...promise... catch捕获的错误=>',e) // cc+1 思考:能否被捕获??
}

// 3.
try{
  new Promise((resolve, reject) => {
  	reject(1)
    c + 1
	})
  .catch(e => {
    console.log('promise catch捕获的错误',e) // 思考:c+1 能否被捕获??
    cc + 1
  })
  .catch(e => {
     console.log('promise catch捕获的错误2',e) // cc+1 思考:能否被捕获??
  })
}catch(e){
 console.log('try ...promise... catch捕获的错误=>',e) // cc+1 思考:能否被捕获??
}
3.3 all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

只有当所有的promise执行完毕并得到结果后才会更改外部promise的状态,并且返回全部的promise的结果。

const promiseList = [0,1,2,3,4,5].map(t => {
  return new Promise((resolve,reject) => {
    resolve(t+1)
  })
})

Promise.all(promiseList).then(res => {
  console.log(res) // [1,2,3,4,5,6]
})
3.4 race()

Promise.race()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

只有最早执行完毕的promise会更改外部包装promise的状态,并且只返回最早的promise结果。


// race()
const promise1 = new Promise((resolve,reject) => {
  setTimeout(()=>{
    resolve('1000')
  },1000)
})

const promise2 = new Promise((resolve,reject) => {
  setTimeout(()=>{
    resolve('500')
  },500)
})

Promise.race([promise1,promise2]).then(res => {
  console.log(res)  // '500'
})
3.5 finally()

三、一些思考

1 then()中有then() ?

2 catch() + then() ?

3 如何使用Promise ?

4 all() 的catch() ?