logo头像

叩首问路,码梦为生

Promise入门

幕课网上的视频——Promise入门笔记,Promise 作为 ES6 中最重要的特性之一,对其进行了解和学习是非常有必要的,课程的源码已经上传至我的github

Promise是什么

MDN

  • The Promise object is used for asynchronous computations.
  • A Promise represents a value which may be available now, or in the future, or never.

MDN中文

  • Promise对象用于异步计算。
  • 一个Promise表示一个现在、将来或永不可能可用的值。

按照用途来解释

  • 主要用于异步计算
  • 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
  • 可以在对象之间传递和操作Promise,帮助我们处理队列。

回调存在的问题

  1. 嵌套层次很深,难以维护
  2. 无法正常使用 return 和 throw
  3. 无法正常检索堆栈信息
  4. 多个回调之间难以建立联系

Promise 详解

  • Promise 是一个代理对象,它和原先要进行的操作并无关系
  • 它通过引入一个回调,避免更多的回调

Promise 有 3 个状态

  1. pending[待定]——初始状态
  2. fulfilled[实现\——操作成功
  3. rejected[被否决]——操作失败

当 Promise 的状态发生改变,就会触发 .then() 里的响应函数处理后续步骤;Promise 状态一经改变,不会再变;只有在连续多个回调顺序执行的时候,Promise才会显示出其威力

.then()

  • .then() 接受两个函数作为参数,分别代表 fulfilled 和 rejected
  • .then() 返回一个新的 Promise 实例,所以它可以链式调用
  • 当前面的 Promise 状态改变时,.then() 根据其最终状态,选择特定的状态响应函数执行
  • 状态响应函数可以返回新的 Promise,或其它值
  • 如果返回新的 Promise,那么下一级 .then() 会在新的 Promise 状态改变之后执行
  • 如果返回其它任何值,则会立刻执行下一级 .then()

错误处理

Promise 会自动捕获内部异常,并交给 rejected 响应函数处理 最好是在语句的最后通过 catch 捕获错误,因为 catch 可以捕获 resolve 回调中发生的错误,而 reject 回调无法捕获;catch 也会返回一个 Promise 实例,并且它返回的 Promise 实例如果没有错误的话也是 fulfilled 状态,所以 catch() 后面的 .then() 也都会触发,但是 catch() 后面的 .catch() 不会触发(如果在第一个catch()中没有抛出错误

强烈建议在所有队列最后都加上.catch(),以避免漏掉错误处理造成意想不到的问题:

1
2
3
4
5
6
doSomething()
.doAnotherThing()
.doMoreThing()
.catch( err => {
console.log(err);
});

实现队列

有时候我们不希望所有动作一起发生,而是按照一定顺序,逐个进行:

1
2
3
4
5
let promise = doSomething();
promise = promise.then(doSomethingElse);
promise = promise.then(doSomethingElse2);
promise = promise.then(doSomethingElse3);
...

使用.forEach()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function queue(things) {
let promise = Promise.resolve();
things.forEach( thing => {
promise = promise.then( () => {
return new Promise( resolve => {
doThing(thing, () => {
resolve();
})
})
})
});
return promise;
}
queue(\['lots', 'of', 'things', ....\]);

使用.reduce()

1
2
3
4
5
6
7
8
9
10
11
12
function queue(things) {
return things.reduce( (promise, thing) => {
promise = promise.then( () => {
return new Promise( resolve => {
doThing(thing, () => {
resolve();
})
})
})
}, Promise.resolve());
}
queue(\['lots', 'of', 'things', ....\]);

Promise常用函数

Promise.resolve()

返回一个 fulfilled 的 Promise 实例,或原始 Promise 实例

  • 参数为空,返回一个状态为 fulfilled 的 Promise 实例
  • 参数是一个跟 Promise 无关的值,同上,不过 fulfilled 响应函数会得到这个参数
  • 参数为 Promise 实例,则返回该实例,不做任何修改
  • 参数为 thenable(有 then 方法),立刻执行它的 .then()

Promise.reject()

返回一个 rejected 的 Promise 实例

  • Promise.reject()不认thenable
  • 其他和 Promise.resolve() 类似

Promise.all()

Promise.all(\[p1, p2, p3, ...\]) 用于将多个 Promise 实例包装成一个新的 Promise 实例 当所有子 Promise 都完成,该 Promise 完成,返回值是全部值的数组;有任何一个失败,该 Promise 失败,返回值是第一个失败的子Promise的结果,最常见的是和 .map() 连用

###Promise.race()

类似 Promise.all() ,区别在于它有任意一个完成就算完成。

常见用法:

  • 把异步操作和定时器放在一起
  • 如果定时器先触发,就认为超时,告知用户

async/await

ES2017 新增运算符,新的语言元素

  • 赋予 JavaScript 以顺序手法编写异步脚本的能力!
  • 既保留异步运算的无阻赛特性,还继续使用同步写法。
  • 还能正常使用 return/try/catch
支付宝打赏 微信打赏

听说赞过就能年薪百万