Promise对象 异步编程
Promise 的含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise
对象有以下两个特点。
(1)对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise
也有一些缺点:
- 无法取消
Promise
,一旦新建它就会立即执行,无法中途取消。 - 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 当处于
pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
为什么要用promise
1. 指定回调函数的方式更加灵活:
旧的: 必须在启动异步任务前指定
promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
const p = new Promise((resolve, reject) => {
console.log('执行 executor同步函数')
let time = Date.now();
setTimeout(() => {
if (time % 2 === 0) {
resolve(time)
} else {
reject(time)
}
}, 1000) }) setTimeout(() => {
p.then(value => {
console.log('value', value)
}, reason => {
console.log('reason', reason)
})
}, 3000)
2. 支持链式调用, 可以解决回调地狱问题
什么是回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
回调地狱的缺点: 不便于阅读 / 不便于异常处理
解决方案:promise链式调用
终极解决方案:async/await Promise API
1. Promise构造函数: Promise (excutor) {}
excutor 执行器函数: 同步执行 (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
定义:new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>; 2. Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数 (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
then接口定义:then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>; 3. Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
catch接口定义:catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>; 4. Promise.resolve方法: (value) => {}
value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象 resolve<T>(value: T | PromiseLike<T>): Promise<T>; 5. Promise.reject方法: (reason) => {}
reason: 失败的原因
说明: 返回一个失败的promise对象 reject<T = never>(reason?: any): Promise<T>; 6. Promise.all方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>; 7. Promise.race方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;
使用的常见问题
- 如何改变promise的状态?
- resolve(value): 如果当前是pending就会变为resolved
- reject(reason): 如果当前是pending就会变为rejected
- 抛出异常: 如果当前是pending就会变为rejected
- 一个promise指定多个成功/失败回调函数, 都会调用吗?
- 当promise改变为对应状态时都会调用
- 改变promise状态和指定回调函数谁先谁后?(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调(2)如何先改状态再指定回调?①在执行器中直接调用resolve()/reject()②延迟更长时间才调用then()(3)什么时候才能得到数据?①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
- promise.then()返回的新promise的结果状态由什么决定?(1)简单表达: 由then()指定的回调函数执行的结果决定(2)详细表达:①如果抛出异常, 新promise变为rejected, reason为抛出的异常②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
- promise如何串连多个操作任务?(1)promise的then()返回一个新的promise, 可以开成then()的链式调用(2)通过then的链式调用串连多个同步/异步任务
- promise异常传透?(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,(2)前面任何操作出了异常, 都会传到最后失败的回调中处理
- 中断promise链?(1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数(2)办法: 在回调函数中返回一个pending状态的promise对象 return new Promise(()=>{})
// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected' // 参数为executor函数
function Promise(executor) {
const that = this
// 三个属性
that.status = PENDING //Promise对象状态属性,初始状态为 pending
that.data = 'undefined' // 用于存储结果数据
that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) {
// RESOLVED 状态只能改变一次
if (that.status !== PENDING) {
return
}
that.status = RESOLVED
that.data = value
//执行异步回调函数 onResolved
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有成功的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onResolved(value)
})
})
}
} function reject(seaon) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.data = seaon
//执行异步回调函数 onRejected
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有失败的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onRejected(seaon)
})
})
}
} try { //执行器函数立即执行
executor(resolve, reject)
} catch (e) {
reject(e)
}
} //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
//返回一个新的Promise对象
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
// 指定默认的失败的回调(实现错误/异常传透的关键点)
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
} // 抽后传递失败的reason
const that = this
return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
function handle(callback) {
// 调用成功的回调函数 onResolved
//1.如果抛出异常,return的promise就 会失败,reason就 是error
//2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
//3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
try {
const result = callback(that.data);
if (result instanceof Promise) {
result.then(value => resolve(value), reason => reject(reason))
} else {
resolve(result)
}
} catch (e) {
reject(e)
}
} // 当前状态还是pending状态, 将回调函数保存起来
if (that.status === PENDING) {
that.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (that.status === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
//调用失败的回调函数 onRejected
handle(onRejected)
})
}
})
} //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
//返回一个新的Promise对象
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
} // Promise函数对象的 resolve 方法
//返回一个新的Promise对象,Promise.resolve()中可以传入Promise
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
} // Promise函数对象的 reject 方法
//返回一个新的Promise对象 Promise.reject中不能再传入Promise
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
} // Promise函数对象的 all 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
Promise.all = function (promises) {
// 保证返回的值得结果的顺序和传进来的时候一致
// 只有全部都成功长才返回成功
const values = new Array(promises.length) // 指定数组的初始长度
let successCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => { // 由于p有可能不是一个Promise
Promise.resolve(p).then(
value => {
successCount++
values[index] = value
if (successCount === promises.length) {
resolve(values)
}
},
// 如果失败
reason => {
reject(reason)
})
})
}) }
// Promise函数对象的 race 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
value => {
resolve(value)
}, reason => {
reject(reason)
})
})
}) } // 把Promise暴露出去
window.Promise = Promise
})(window)
使用Class定义
// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected' class Promise {
// 参数为executor函数
constructor(executor) {
const that = this
// 三个属性
that.status = PENDING //Promise对象状态属性,初始状态为 pending
that.data = 'undefined' // 用于存储结果数据
that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) {
// RESOLVED 状态只能改变一次
if (that.status !== PENDING) {
return
}
that.status = RESOLVED
that.data = value
//执行异步回调函数 onResolved
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有成功的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onResolved(value)
})
})
}
} function reject(seaon) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.data = seaon
//执行异步回调函数 onRejected
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有失败的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onRejected(seaon)
})
})
}
} try { //执行器函数立即执行
executor(resolve, reject)
} catch (e) {
reject(e)
}
} //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
//返回一个新的Promise对象
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
// 指定默认的失败的回调(实现错误/异常传透的关键点)
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
} // 抽后传递失败的reason
const that = this
return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
function handle(callback) {
// 调用成功的回调函数 onResolved
//1.如果抛出异常,return的promise就 会失败,reason就 是error
//2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
//3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
try {
const result = callback(that.data);
if (result instanceof Promise) {
result.then(value => resolve(value), reason => reject(reason))
} else {
resolve(result)
}
} catch (e) {
reject(e)
}
} // 当前状态还是pending状态, 将回调函数保存起来
if (that.status === PENDING) {
that.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (that.status === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
//调用失败的回调函数 onRejected
handle(onRejected)
})
}
})
} //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
//返回一个新的Promise对象
catch(onRejected) {
return this.then(undefined, onRejected)
} // Promise函数对象的 resolve 方法
//返回一个新的Promise对象,Promise.resolve()中可以传入Promise
static resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
} // Promise函数对象的 reject 方法
//返回一个新的Promise对象 Promise.reject中不能再传入Promise static reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
} // Promise函数对象的 all 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
static all = function (promises) {
// 保证返回的值得结果的顺序和传进来的时候一致
// 只有全部都成功长才返回成功
const values = new Array(promises.length) // 指定数组的初始长度
let successCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => { // 由于p有可能不是一个Promise
Promise.resolve(p).then(
value => {
successCount++
values[index] = value
if (successCount === promises.length) {
resolve(values)
}
},
// 如果失败
reason => {
reject(reason)
})
})
}) } // Promise函数对象的 race 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
static race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
value => {
resolve(value)
}, reason => {
reject(reason)
})
})
}) }
} // 把Promise暴露出去
window.Promise = Promise
})(window)
来自:https://www.bilibili.com/video/BV1MJ41197Eu?from=search&seid=1177747046204864464
Promise对象 异步编程的更多相关文章
- Promise和异步编程
前面的话 JS有很多强大的功能,其中一个是它可以轻松地搞定异步编程.作为一门为Web而生的语言,它从一开始就需要能够响应异步的用户交互,如点击和按键操作等.Node.js用回调函数代替了事件,使异步编 ...
- 《深入理解ES6》笔记—— Promise与异步编程(11)
为什么要异步编程 我们在写前端代码时,经常会对dom做事件处理操作,比如点击.激活焦点.失去焦点等:再比如我们用ajax请求数据,使用回调函数获取返回值.这些都属于异步编程. 也许你已经大概知道Jav ...
- Promise对异步编程的贡献以及基本API了解
异步: 核心: 现在运行的部分和将来运行的部分之间的关系 常用方案: 从现在到将来的等待,通常使用一个回调函数在结果返回时得到结果 控制台(因为console族是由宿主环境即游览器实现的)可能会使用异 ...
- 异步编程——promise
异步编程--promise 定义 Promise是异步编程的一个解决方案,相比传统的解决方法--回调函数,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,也使得代码结构更为清晰,便于维 ...
- 学习Promise异步编程
JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...
- ES6深入学习记录(二)promise对象相关
1.Promise的含义 Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件更合理和强大.ES6将其写进了语言标准,统一了用法,原生提供了promise对象. 所谓Promis ...
- JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上
众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...
- 异步编程:When.js快速上手
前些天我在团内做了一个关于AngularJS的分享.由于AngularJS大量使用Promise,所以我把基于Promise的异步编程也一并介绍了下.很多东西都是一带而过,这里再记录下. Angula ...
- ES6 之 let和const命令 Symbol Promise对象
ECMAScript 6入门 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了. (2016年6月,发布了小幅修订的<ECMASc ...
随机推荐
- spring boot 和shiro的代码实战demo
spring boot和shiro的代码实战 首先说明一下,这里不是基础教程,需要有一定的shiro知识,随便百度一下,都能找到很多的博客叫你基础,所以这里我只给出代码. 官方文档:http://sh ...
- Python实用笔记 (4)循环
for...in循环 names = ['Michael', 'Bob', 'Tracy'] for name in names: print(name) 运行如下: Michael Bob Trac ...
- 浅谈MySQL数据库基本操作
数据库配置 通过配置文件统一配置的目的:统一管理 服务端(mysqld) .客户端(client) 配置了 mysqld(服务端) 的编码为utf8,那么再创建的数据库,默认编码都采用utf8 配置流 ...
- jQuery jqGrid 4.7
https://jeesite.gitee.io/front/jqGrid/4.7/index.html https://jeesite.gitee.io/front/jqGrid/4.7/jqgri ...
- redis 链接数满了
服务器上可以设置timeout参数,这样可以将限制的连接自动释放掉.
- Selenium之浏览器驱动下载和配置使用
浏览器驱动下载 Chrome浏览器驱动:chromedriver , taobao备用地址 Firefox浏览器驱动:geckodriver Edge浏览器驱动:MicrosoftWebDriver ...
- 如何针对 iPhone X 设计网站?
在全面屏的 iPhone X 上,不需要而外的代码,Safari 可以非常完美的展示现有的网站.整个网站的内容都会自动地展示在一个“安全区域”内,并不会被四周的圆角或者“小刘海”遮挡住. Safari ...
- mongodb安装与mongo vue的使用
首先,下载mongodb,然后安装 http://downloads.mongodb.com/win32/mongodb-win32-x86_64-enterprise-windows-64-2.6. ...
- vue+elementUI 图片上传问题
图片上传问题,获取后台的图片,并点击可以更换图片,并把图片存储到数据库中: (1)在编辑页面上,action指的图片上传的地址,header指请求头: (2)因为element-ui有自己上传的接口, ...
- BUUCTF-Misc-No.4
比赛信息 比赛地址:Buuctf靶场 内心os(蛮重要的) 我只想出手把手教程,希望大家能学会然后自己也成为ctf大佬,再来带带我QWQ 被偷走的文件 | SOLVED | foremost分离一下文 ...