ES6 promise 用法小结

Js 是一⻔单线程语言,早期解决异步问题,大部分是通过回调函数进行。

比如我们发送 ajax 请求,就是常见的一个异步场景,发送请求后,一段时间服务器给我们响应,然后才拿到结果。如果我们希望在异步结束之后执行某个操作,就只能通过回调函数的方式进行操作

const request = function (callback) {setTimeout(function () {callback()}, 1000)
}
request(function () {console.log(123)
})
// 以上代码执行结果:1s 后输出 123
// request 就是一个异步函数,里面执行的 setTimeout 会在 1s 之后调用传入的 callback 函数,
// 如果后续还有内容需要在异步函数结束时输出,就需要多个异步函数进行嵌套,非常不利于后续的维护。
setTimeout(function () {console.log(123)setTimeout(function () {console.log(321)// ...}, 2000)
}, 1000)

为了使回调函数以更优雅的方式进行调用,在 ES6 中引入了 promise,让异步 操作的变得「同步化」。

1,Promise 基础

通过 new Promise() 即可构造一个 promise 实例,这个构造函数接受一个函数,接受两个参数:resolvereject,代表改变实例的状态到 已完成 或是 已拒绝

const promise = new Promise(function (resolve, reject) {console.log('promise called')setTimeout(function () {resolve()}, 3000)
})promise.then(function () {console.log('promise resolve callback')
})// 先打印出 promise called, 3s 后打印 promise resolve callback
function promise1() {return new Promise(function (resolve, reject) {setTimeout(function () {console.log('1s后输出')resolve()}, 1000)})
}function promise2() {return new Promise(function (resolve, reject) {setTimeout(function () {console.log('2s后输出')resolve()}, 2000)})
}
// 以下两个promise实例,串联起来即可写为:
promise1().then(function () {return promise2()
})
或
promise1().then(promise2)

控制台打印结果:1s之后出现 1s后输出,再经过2s出现2s后输出。实例中,当前promise如果状态变为已完成(执行resolve方法),就会去执行 then 方法中的下一个 promise 函数。同样的如果promise变成已拒绝状态(执行reject方法),就会进入后续的异常处理函数中。

function promise3() {return new Promise(function (resolve, reject) {var random = Math.random() * 10 // 随机一个 1 - 10的数字setTimeout(function () {if (random >= 5) {resolve(random) // 把随机生成的数字传给了 resolve, 在 then 中可以拿到这个值} else {reject(random)  // 把随机生成的数字传给了 reject,在 then 中可以拿到这个值}}, 1000)})
}var onResolve = function (val) {  console.log('已完成:输出的数字是:', val)
}var onReject = function (val) {console.log('已拒绝:输出的数字是:', val)
}// promise 的then也可以接受两个参数,第一个参数是 resolve 后执行的,第二个参数是 reject 后执行的
promise3().then(onResolve, onReject)// 也可以通过 .catch 方法拦截状态变为已拒绝时的 promise
promise3().catch(onReject).then(onResolve)// 也可以通过 try catch 进行拦截状态变为已拒绝的 promise
try {promise3().then(onResolve)
} catch (e) {onReject(e)
}

以上使用3种方式拦截最终变为「已拒绝」状态的 promise,分别是使用 then 的第二个参数,使用 .catch 方法捕获前方 promise 抛出的异常,使用 try catch 拦截代码块中 promise 抛出的异常

我们可以发现,在改变 promise 状态时调用 resolvereject 函数的时候,可以给下一步 then 中执行的函数传递参数。

2,封装异步操作为promise

我们可以将任何接受回调的函数封装为一个promise, 实例:

// 原函数
function func(callback) {setTimeout(function () {console.log('1s 后显示')callback()}, 1000)
}var callback = function () {console.log('在异步结束后打印')
}
// 用传入回调函数的方式执行
func(callback)


以上实例是最传统的使用传入回调函数的方式在异步结束后执行函数。我们可以通过封装 promise的方式,将这个异步函数变为 promise:

function func() {return new Promise(function (resolve, reject) {setTimeout(function () {console.log('1s 后显示')resolve()})})
}var callback = function () {console.log('在异步结束后打印')
}func().then(function () {callback()
})

再比如,我们发送 ajax 请求也可以封装为 promise:

function ajax(url, success, fail) {var client = new XMLHttpRequest();client.open('GET', url)client.onreadystatechange = function () {if (this.readyState !== 4) {// this.readyState扩展:// 0: 未初始化,还没调用 send() 方法// 1: 载入,已调用send()方法,正在发送请求// 2: 载入完成,send()执行完毕,已接受全部响应内容// 3: 交互,正在解析响应内容// 4: 完成,响应内容解析完成,可以直接使用responseText数据return}if (this.status === 200) {success(this.response)} else {fail(new Error(this.statusText))}}client.send()
}ajax('http://localhost:8080/home/swiper', function (res) {console.log('成功')console.log(res)
}, function (err) {console.log('失败', err)
})


以上 ajax 请求,通过封装 promise 的方式,在原来的执行回调函数的地方,更改当前 promise的状态,就可以通过链式调用:

function ajax(url) {return new Promise(function (resolve, reject) {var ct = new XMLHttpRequest();ct.open('GET', url)ct.onreadystatechange = function () {if (this.readyState !== 4) {return}if (this.status === 200) {resolve(this.response)} else {reject(new Error(this.statusText))}}ct.send()})
}ajax('http://localhost:8080/home/swiper').catch(function () {console.log('失败')
}).then(function (res) {console.log('成功')console.log(res)
})

我们可以把任何一个函数或者是异步函数改为promise,尤其是异步函数,改为 promise中后即可进行链式调用,增强可读性

3,小总结

  • 1,promise 有三种状态,进行中(Pending)已完成(Fulfilled)已拒绝(Rejected),进行中状态可以更改为已完成 或 已拒绝,已经更改过状态后无法继续更改(例如从已完成改为已拒绝)。

  • 2,ES6 中的 Promise 构造函数,我们构造之后需要传入一个函数,他接受两个函数参数,执行第一个参数之后就会改变当前 promise 为已完成状态,执行第二个参数之后就会变为 已拒绝 状态。

  • 3,必须有一个then方法用以访问其当前值和原因。promise的 then 方法接受两个参数:promise.then(onFulfilled, onRejected) 他们都是可选参数,他们都是函数。如果 onFulfilledonRejected 不是函数,则需要忽略他们

  • 4,已拒绝的 promise,后续可以通过 .catch 方法或是 .then 方法的第二个参数或是 try catch 进行捕获。

  • 5,then方法可以被同一个promise调用多次。

    • 当 promise 成功执行的时候,所有的 onFulfilled 需按照其注册顺序依次回调
    • 当 promise 被拒绝执行的时候,所有的 onRejected 需按照其注册顺序依次回调
      then 方法必须返回一个 promise 对象: promise2 = promise1.then(onFulfilled, onRejected)
    • 只要 onFulfilled 或者 onRejected 返回一个值 xpromise2 都会进入 onFulfilled 状态
    • 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
    • 如果 onFulfilled 不是函数且 promise1 状态变为已完成, promise2 必须成功执行并返回相同的值
    • 如果 onRejected 不是函数且 promise1 状态变为已拒绝, promise2 必须执行拒绝回调并返回相同的据因
var promise1 = new Promise((resolve, reject) => {reject()
})
promise1.then(null, function () {return 123}).then(null, null).then(null, null).then(() => {console.log('promise2 已完成')},() => {console.log('promise2 已拒绝')})

以上代码输出:promise2 已完成

以上代码可改写为:

var promise1 = new Promise(function (resolve, reject) { reject() })
var promise2 = promise1.then(null, function () { return 123 })
var promise3 = promise2.then(null, null) // 如果 onFulfilled 不是函数且 promise2 状态变为已完成, promise3 必须成功执行并返回和 promise2 相同的值, 即 123
var promise4 = promise3.then(null, null) // 同理,promise4 也能拿到 123 的值
promise4.then(val => {console.log('promise2 已完成', val)  // promise2 已完成 123}, () => {console.log('promise2 已拒绝')})

实例:

var promise1 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(1)resolve()}, 1000)})
}var promise2 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(2)resolve()}, 2000)})
}promise1().then(function () {return promise2()  // 此处返回一个 promise 实例}).then(function () {console.log('已完成')}, function () {console.log('已拒绝')})

4, promise 构造函数上的 静态方法

  • 4.1, promise.resolve

返回一个 promise 实例,并将它的状态设置为已完成,同时将他的结果作为传入 promise 实例的值

var promise = Promise.resolve(123)
promise.then(function (val) {console.log('已完成', val)
})


Promise.resolve 的参数也可以处理对象、函数等内容

  • 4.2,promise.reject

返回一个 promise 实例,并将它的状态设置为已拒绝,同时也将他的结果作为原因传入 onRejected 函数

var promise = Promise.reject(123)
promise.then(null, function (val) {console.log('已拒绝', val)
})

  • 4.3,Promise.all

返回一个 promise 实例,接受一个数组,里面含有多个 promise 实例,当所有 promise 实例都成 已完成 状态时,进入已完成状态,否则进入已拒绝状态。

var promise1 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(1)resolve()}, 1000)})
}var promise2 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(2)resolve()}, 1000)})
}Promise.all([promise1(), promise2()]).then(function () {console.log('全部 promise 均已完成')
})

以上代码为多个 promise 同时进行,等待 1s 打印 1 之后,再等待 1s 就 会打印 2 和全部 promise 均已完成。

  • 4.4,Promise.race
    返回一个 promise 实例,接受一个数组,里面含有多个 promise 实例,当有一个 promise 实例状态改变时,就进入该状态且不可改变。这里所有的 promise 实例为竞争关系,只选择第一个进入改变状态的 promise 的值。
var promise1 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(1)resolve(1)}, 1000)})
}var promise2 = function () {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(2)resolve(2)}, 1000)})
}Promise.race([promise1(), promise2()]).then(function (val) {console.log('有一个 promise 状态已经改变', val)
})

5, generator / async await

ES6 之后,我们可以使用 generator 和 async/await 来操作 promise,比起使用 promise 串行的调用来说,从语法层面 让调用关系 显得更加串行。

function promise1() {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(1)resolve()}, 1000)})
}function promise2() {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(2)resolve()}, 1000)})
}// 使用 generator 函数
function* gen() {yield promise1()yield promise2()
}
var g = gen()
g.next()
g.next() // 1 2// 使用 async/await 函数
(async function () {try {await promise1()await promise2()console.log('已完成')} catch (e) {console.log(e)console.log('已拒绝')}
}())  // 1 2 已完成

ES6 promise 用法小结相关推荐

  1. ES6 Promise用法小结

    目录 1.什么是Promise reject的用法 catch的用法 all的用法 race的用法 1.什么是Promise Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有a ...

  2. Vue进阶(四十五):精解 ES6 Promise 用法

    文章目录 一.前言 二.链式操作用法 三.reject 用法 四.catch 用法 五.all 用法 六.race 用法 七.总结 八.拓展阅读 一.前言 复杂难懂概念先不讲,我们先简单粗暴地把Pro ...

  3. ES6 Promise用法讲解

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果. ES6 规定,Promise对象是一个构造函数,用来生成Promise实例. 下面代码创造了一个 ...

  4. Promise用法小结

    定义:是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息.Promise 提供统一的 API,各种异步操作都可 ...

  5. ES6 — Promise基础用法详解(resolve、reject、then、catch,all,)

    ES6 - Promise基础用法详解 Promise 是一个构造函数,它自身拥有all.reject.resolve这几个眼熟的方法, 原型上有then.catch等同样熟悉的方法. 所以,在开始一 ...

  6. promise用法_图解 Promise 实现原理(四):Promise 静态方法实现

    作者:Morrain 转发链接:https://mp.weixin.qq.com/s/Lp_5BXdpm7G29Z7zT_S-bQ 前言 Promise 是异步编程的一种解决方案,它由社区最早提出和实 ...

  7. promise用法_图解 Promise 实现原理(一)—— 基础实现

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/UNzYgpnKzmW6bAapYxnXRQ 作者:孔垂亮 很多同学在学习 Promise 时 ...

  8. keep sb updated_keep的用法小结

    keep 的用法小结 keep 是高考常考词汇之一,其含义丰富,与其搭配的短语也很多,其主要用法 1. 保留.保存.保持.留下 e.g. We'd better keep a seat for him ...

  9. promise用法详解

    一.什么是promise 1.promise简介 Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all.reject.resolve这几个方法,原型上有then.catch等 ...

最新文章

  1. oracle cache keep pool,请问:alter table ……storage(buffer_pool keep) 与cache的区别
  2. 14种常见HTTP状态码
  3. 数据结构与算法 —— 二叉树
  4. 【调参实战】BN和Dropout对小模型有什么影响?全局池化相比全连接有什么劣势?...
  5. springboot参数校验,对象的某属性校验
  6. 浙江省第二届大学生网络与信息安全竞赛在线预赛
  7. Qt输入输出之QProcess
  8. 做生意做不过中国,于是英国发动了鸦片战争
  9. java快速生成接口文档方法总结
  10. 语音识别百度阿里哪家强?识别率评测
  11. rman异机恢复 Linux _RAC至Win_Single Instance note
  12. win10系统设置番茄家园开机音乐以及关机音乐(亲测有效)
  13. 基于IP搭建SAN存储
  14. 无线路由器连接无线路由器
  15. 字美杯装饮料茶点打印机
  16. 易语言大漠圆形椭圆形渐开线结合鼠标特征码刷怪
  17. TOJ 5238: C实验:变量交换函数
  18. HyperLPR车牌识别库代码分析(12)
  19. 在HTML中怎么去掉超链接(标签 a)的下划线?
  20. Android的Paint和Canvas的使用总结

热门文章

  1. android 铃声管理器,android RingtoneManager 铃声管理器
  2. vue项目使用公共js方法@令狐张豪
  3. 最女孩子不要急,容易追到的不长久
  4. 什么时候需要分布式锁?
  5. cs硕士妹子找工作经历【阿里人搜等互联网】(励志用的)
  6. SF09 | 资金流向交易策略源码,绩效突出,适应性兼容性强,5分钟短线交易模型;
  7. 6月份读书学习好文记录
  8. 【ARMv8 编程】ARMv8 指令集介绍
  9. VMware 虚拟机安装的ubuntu系统鼠标故障解决方案
  10. 1.secureCRT注册机patch失败