如今promise大行其道,关于异步方面的几乎都有它的影子,新的fetch api返回的是promise对象,generator中的yield后面一般也会跟promise对象,async的await后面一般也是promise对象。

  既然promise这么重要,这里也整理了一些关于它的知识,加深下自己对promise的理解。

1,基础

  promise是一个异步操作的最终结果。它有三种状态,初始状态为Pending,状态只能转变为resolved或者rejected,并且不可逆。

  基本用法为

let promise = new Promise((resolve, reject) => {
//异步代码.... if (/*操作成功 */) {
resolve(result)
} else {
reject(error)
}
})

  必须有then方法,接受两个可选的函数参数:onResolve和onRejected。then方法必须返回一个promise对象以便接下来的链式调用。为了保证其中回调的执行顺序,回调必须使用异步。

  

2,API

  实例方法:

    .then(onResolve, onReject)   :     promise状态改变时的回调,返回一个新的promise实例

    .catch()   :     本质上就是then方法中的onReject,返回值是一个新的promise

  静态方法:

    Promise.resolve()  :  1,将对象转为promise对象。

              2,如果参数是promise实例,直接返回

              3,如果参数为thenable对象,则转换为promise对象,并执行then方法

              4,如果参数为原始类型,返回一个promise对象,状态为resolved,参数为那个原始类型

              5,如果没有参数则返回一个状态为resolved的promise的对象

    Promise.reject()  : 和上面的差不多,只是状态改变为rejected

    Promise.all()   :      1,接收一个promise实例的数组

              2,如果全部成功,则状态转为resolved,返回值为一个数组

              3,只要有一个失败,状态就转为rejected,直接返回错误

              4,返回值也是为新的promise对象

    Promise.race()   :    和all差不多,不同的是只要有一个实例的状态改变了就结束了。

3,promise的误区

  1,把promise当做callback来使用

    

getData1().then(res1 => {
getData2(res).then(res2 => {
getData3(res).then(......)
})
})

    promise的目的本来就是用来解决异步回调地狱的,这种写法虽然可行,但完全违背了promise的设计初衷。

    可以改成以下的写法:

getData1()
.then(res1 => {
return getData2(res1)
})
.then(res2 => {
return getData3(res2)
})
.then(......)

  2,没有处理错误    

    如果在使用promise时没有处理错误,promise抛出的错误将不会传递到外层代码,即不会有任何反应,不会终止当前脚本的继续执行。

    promise捕获错误有两种方式: 一种是在then中定义rejected状态的回调(then的第二个参数),第二种是用catch方法

    由于promise对象的错误具有冒泡的性质,会一直向后传递,也就是说错误总是会被下一个catch捕获。所以一般来说,不要在then方法中定义rejected状态的回调,而总是使用catch来捕获错误。使用catch可以捕获到前面的then方法中执行的错误。

4,promise.resolve()

   promise.resolve还有一个作用,就是将现有的对象转为promise对象

   thenable对象指的是具有then方法的对象。比如:

let thenable = {
then: function(resolve,reject) {
resolve(111)
}
}

    promise.resolve方法会将这个对象转为Promise对象,然后立即执行里面的then方法。

let thenable = {
then: function (resolve, reject) {
resolve(123)
}
}
let p = Promise.resolve(thenable)
p.then(result => {
console.log(result) //
})

     then方法执行后,对象p的状态就变为resolved,从而立即执行紧跟着的then方法的回调函数。


5,promise.reject()

let p = Promise.reject('出错了')
等同于
let p = new Promise((resolve, reject) => reject('出错了'))

  Promise.reject()的参数会原封不动的作为后续方法的参数,这一点与Promise.resolve方法不一致。

const thenable = {
then (resolve, reject) {
reject('错误!')
}
}
Promise.reject(thenable).catch(e => {
console.log(e === thenable) // true
})

  上面的代码中,Promise.reject()的参数为一个thenable对象,执行之后,后面catch方法的参数不是reject抛出的错误这个字符串,而是thenable对象。

 

6,附加方法

  1,done()

    由于Promise的错误不会冒泡到全局,所以Promise链式调用时,最后一个方法如果抛出错误,不管是then还是catch,都有可能无法捕捉到,这里的done方法,总是处于回调链的末端,保证抛出的任何错误都能被捕捉到。 

Promise.prototype.done = (onResolved, onRejected) => {
this.then(onResolved, onRejected).catch( reason => {
setTimeout(() => {throw reason}, 0)
})
}

    done方法可以像then方法那样使用,提供resolved和rejected状态的回调函数。

  2,finally()

    不管Promise对象最后的状态如何,finally参数的回调函数都会执行。

Promise.prototype.finally = callback => {
let P = this.constructor
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.reject(callback()).then(() => {throw reason})
)
}

7,实战应用

  图片懒加载

    let images = []

    function loadImg(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = url
})
}
function preLoadImg(imgs) {
let arr = []
imgs.forEach(url => {
let image = loadImg(url).then(img => images.push(img)).catch(error => console.log(error))
arr.push(image)
}) Promise.all(arr).then(() => {
console.log('全部图片加载完成之后要处理的事情')
}) }

              

深入理解promise的更多相关文章

  1. 大白话讲解Promise(二)理解Promise规范

    上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...

  2. 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)

    本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...

  3. 理解Promise的三种姿势

    译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...

  4. 理解Promise的3种姿势

    译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...

  5. 分步理解 Promise 的实现

    一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...

  6. 理解promise 02

    1:promise是什么? 就是(链式)包装的回调函数. 2:语法 new Promise( function(resolve, reject) {...} /* executor */ ); exe ...

  7. 160701、理解 Promise 的工作原理

    Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...

  8. 160623、理解 Promise 的工作原理

    Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...

  9. 理解Promise简单实现的背后原理

    在写javascript时我们往往离不开异步操作,过去我们往往通过回调函数多层嵌套来解决后一个异步操作依赖前一个异步操作,然后为了解决回调地域的痛点,出现了一些解决方案比如事件订阅/发布的.事件监听的 ...

  10. 理解promise 01

    原文地址: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 用Javascript的小伙伴们,是时候承认了,关于 ...

随机推荐

  1. 268. Missing Number序列中遗失的数字

    [抄题]: Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is ...

  2. solr开发之基本操作

    package zr.com.util; import java.io.IOException; import java.util.List; import java.util.Map; import ...

  3. Linux 与 BSD

    1)Linux 与 BSD 有什么不同? http://linux.cn/article-3186-1.html 2)BSD(Unix)家族 http://blog.csdn.net/cradmin/ ...

  4. Python基础 之列表、字典、元组、集合

    基础数据类型汇总 一.列表(list) 例如:删除索引为奇数的元素 lis=[11,22,33,44,55] #第一种: for i in range(len(lis)): if i%2==1: de ...

  5. Oracle——单行函数

    两种 SQL 函数 单行函数 字符函数 大小写控制函数 SELECT employee_id, last_name, department_id FROM employees WHERE last_n ...

  6. Mbatis——动态SQL

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...

  7. Java 自定义异常类

    类1:public class LogicException extends RuntimeException {    //业务逻辑异常    /**     *      * @param mes ...

  8. Instruments Tutorial for iOS: How To Debug Memory Leaks【转】

    If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for vis ...

  9. Ubuntu的Unable to locate package无法更新源问题解决方案

    https://blog.csdn.net/long19910605/article/details/47017889/ 问题: 更新源时提示不能联网(does the network require ...

  10. 温故而知新:什么是wcf

    1.什么是WCF.WCF是Windows Communication Fundation的缩写,是微软在.net 3.0 的时候引进的,用于开发可交互的分布式应用程序,是由微软发展的一组数据通信的应用 ...