目录
- 说到Promise就不得不说道说道这 —— 回调天堂
Promise —— 解决回调天堂
- Promise语法标准
- Promise的状态
- Promise根本用法
- Promise初体验
- Promise的实质
Promise链式调用
- 常见误区
- 链式调用的了解
- Promise.prototype.then()
Promise异样解决
- then中回调的onRejected办法
Promise.prototype.catch()(举荐)
- .catch模式和后面then外面的第二个参数的模式,两者异样捕捉的区别:
- 全局对象上的unhandledrejection事件
Promise静态方法
类型转换 —— Promise.resolve()
- 应用场景
- Promise.reject()
- 数据聚合 —— Promise.all()
- 竞争 —— Promise.race()
- Promise执行时序 —— 宏工作 vs 微工作
- 深度分析:手写一个Promise源码
- ES6-ES10学习幅员
说到Promise就不得不说道说道这 —— 回调天堂
a => b => c => d
回调层数越深,那么回调的保护老本越高
//异步加载函数function loadScript (src, callback) { let script = document.createElement('script') script.src = src script.onload = () => { callback() } document.head.append(script)}function test () { console.log('test')}loadScript('./1.js', test)// 1// test
如果有三个这样的形式回调
function loadScript (src, callback) { let script = document.createElement('script') script.src = src script.onload = () => { callback(src) } document.head.append(script)}function test (name) { console.log(name)}loadScript('./1.js', function (script) { console.log(script) loadScript('./2.js', function (script) { console.log(script) loadScript('./3.js', function (script) { console.log(script) //... }) })})// 1// ./1.js// 2// ./2.js// 3// ./3.js
Promise —— 解决回调天堂
尽管回调函数是所有异步编程计划的根基。然而如果咱们间接应用传统回调形式去实现简单的异步流程,就会无奈防止大量的回调函数嵌套。导致回调天堂的问题。
为了防止这个问题。CommonJS
社区提出了Promise
的标准,ES6
中称为语言标准。
Promise
是一个对象,用来表述一个异步工作执行之后是胜利还是失败。
Promise语法标准
new Promise( function(resolve, reject) {…} );
new Promise(fn)
返回一个Promise
对象在
fn
中指定异步等解决
- 处理结果失常的话,调用
resolve
(处理结果值)- 处理结果谬误的话,调用
reject
(Error
对象)
Promise的状态
Promise
外部是有状态的 (pending、fulfilled、rejected) ,Promise
对象依据状态来确定执行哪个办法。Promise
在实例化的时候状态是默认pending
的,
- 当异步操作是实现的,状态会被批改为
fulfilled
- 如果异步操作遇到异样,状态会被批改为
rejected
。无论批改为哪种状态,之后都是不可扭转的。
Promise根本用法
返回resolve
const promise = new Promise((resolve, reject) => { resolve(100)})promise.then((value) => { console.log('resolved', value) // resolve 100},(error) => { console.log('rejected', error)})
返回reject
const promise = new Promise((resolve, reject) => { reject(new Error('promise rejected'))})promise.then((value) => { console.log('resolved', value)},(error) => { console.log('rejected', error) // rejected Error: promise rejected // at E:\professer\lagou\Promise\promise-example.js:4:10 // at new Promise (<anonymous>)})
即使promise
中没有任何的异步操作,then
办法的回调函数依然会进入到事件队列中排队。
Promise初体验
应用Promise
去封装一个ajax
的案例
function ajax (url) { return new Promise((resolve, rejects) => { // 创立一个XMLHttpRequest对象去发送一个申请 const xhr = new XMLHttpRequest() // 先设置一下xhr对象的申请形式是GET,申请的地址就是参数传递的url xhr.open('GET', url) // 设置返回的类型是json,是HTML5的新个性 // 咱们在申请之后拿到的是json对象,而不是字符串 xhr.responseType = 'json' // html5中提供的新事件,申请实现之后(readyState为4)才会执行 xhr.onload = () => { if(this.status === 200) { // 申请胜利将申请后果返回 resolve(this.response) } else { // 申请失败,创立一个谬误对象,返回谬误文本 rejects(new Error(this.statusText)) } } // 开始执行异步申请 xhr.send() })}ajax('/api/user.json').then((res) => { console.log(res)}, (error) => { console.log(error)})
Promise的实质
实质上也是应用回调函数的形式去定义异步工作完结后所须要执行的工作。这里的回调函数是通过then
办法传递过来的
Promise链式调用
常见误区
- 嵌套应用的形式是应用
Promise
最常见的误区。要应用promise
的链式调用的办法尽可能保障异步工作的扁平化。
链式调用的了解
promise
对象then
办法,返回了全新的promise
对象。能够再持续调用then
办法,如果return
的不是promise
对象,而是一个值,那么这个值会作为resolve
的值传递,如果没有值,默认是undefined
- 前面的
then
办法就是在为上一个then
返回的Promise
注册回调 - 后面
then
办法中回调函数的返回值会作为前面then
办法回调的参数 - 如果回调中返回的是
Promise
,那前面then
办法的回调会期待它的完结
Promise.prototype.then()
promise
对象就能够调用.then()
,是promise
原型对象上的办法
promise.then(onFulfilled,onRejected);
onFulfilled
参数对应resolve
,处理结果值,必选
onRejected
参数对应reject,Error
对象,可选
Promise
对象会在变为resolve
或者reject
的时候别离调用相应注册的回调函数。
- 当
handler
返回一个正常值的时候,这个值会传递给Promise
对象的onFulfilled
办法。- 定义的
handler
中产生异样的时候,这个值则会传递给Promise
对象的onRejected
办法。这两个参数都是两个函数类型,如果这两个参数是非函数或者被脱漏,就疏忽掉这两个参数了,返回一个空的
promise
对象。
// 一般的写法会导致有不稳固输入function loadScript (src) { //resolve, reject是能够扭转Promise状态的,Promise的状态是不可逆的 return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(src) //fulfilled,result script.onerror = (err) => reject(err) //rejected,error document.head.append(script) })}loadScript('./1.js') .then(loadScript('./2.js')) .then(loadScript('./3.js')) //不稳固输入 // 1// 2// 3----------------------------------------------------------------------------// 如果把加载2和3的放在1的then办法中function loadScript (src) { //resolve, reject是能够扭转Promise状态的,Promise的状态是不可逆的 return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(src) //fulfilled,result script.onerror = (err) => reject(err) //rejected,error document.head.append(script) })}loadScript('./1.js') .then(() => { loadScript('./2.js') }, (err) => { console.log(err) }).then( () => { loadScript('./3.js') }, (err) => { console.log(err) }) // 稳固输入// 1// 不稳固输入// 2// 3// ----------------------------------------------//然而如果两头有谬误的时候,上面的3还是会执行。loadScript('./1.js') .then(() => { loadScript('./4.js') }, (err) => { console.log(err) }).then( () => { loadScript('./3.js') }, (err) => { console.log(err) })// 1// 报错// 3// 不合乎题意,如果是报错之后,3不应该执行// -------------------------------------------------------loadScript('./1.js') .then(() => { return loadScript('./2.js') }, (err) => { console.log(err) }).then(() => { return loadScript('./3.js') }, (err) => { console.log(err) })// 不加返回值,仍旧是一个空的promise对象,无奈用resolve, reject影响下一步.then()的执行// 增加返回值之后就能够稳固输入// 1// 2// 3
Promise异样解决
异样解决有以下几种办法:
then中回调的onRejected办法
Promise.prototype.catch()(举荐)
catc
h是promise
原型链上的办法,用来捕捉reject
抛出的一场,进行对立的错误处理,应用.catch
办法更为常见,因为更加合乎链式调用。
p.catch(onRejected);
ajax('/api/user.json') .then(function onFulfilled(res) { console.log('onFulfilled', res) }).catch(function onRejected(error) { console.log('onRejected', error) }) // 相当于ajax('/api/user.json') .then(function onFulfilled(res) { console.log('onFulfilled', res) }) .then(undefined, function onRejected(error) { console.log('onRejected', error) })
.catch模式和后面then外面的第二个参数的模式,两者异样捕捉的区别:
.catch()
是对上一个.then()
返回的promise
进行解决,不过第一个promise
的报错也顺延到了catch
中- 而
then
的第二个参数模式,只能捕捉第一个promise
的报错,如果以后then
的resolve
函数解决中有报错是捕捉不到的。
所以.catch
是给整个promise
链条注册的一个失败回调。举荐应用!!!!
function loadScript (src) { //resolve, reject是能够扭转Promise状态的,Promise的状态是不可逆的 return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(src) //fulfilled,result script.onerror = (err) => reject(err) //rejected,error document.head.append(script) })}loadScript('./1.js') .then(() => { return loadScript('./2.js') }).then(() => { return loadScript('./3.js') }) .catch(err => { console.log(err) })// throw new Error 不要用这个办法,要用catch和reject,去扭转promise的状态的形式
全局对象上的unhandledrejection事件
还能够在全局对象上注册一个unhandledrejection
事件,解决那些代码中没有被手动捕捉的promise
异样,当然并不举荐应用。
更正当的是:在代码中明确捕捉每一个可能的异样,而不是丢给全局解决
// 浏览器window.addEventListener('unhandledrejection', event => { const { reason, promise } = event console.log(reason, promise) //reason => Promise 失败起因,个别是一个谬误对象 //promise => 出现异常的Promise对象 event.preventDefault()}, false)// nodeprocess.on('unhandledRejection', (reason, promise) => { console.log(reason, promise) //reason => Promise 失败起因,个别是一个谬误对象 //promise => 出现异常的Promise对象})
Promise静态方法
类型转换 —— Promise.resolve()
静态方法 Promise.resolve(value)
能够认为是 new Promise()
办法的快捷方式。
Promise.resolve(42)//等同于new Promise(function (resolve) { resolve(42)})
如果承受的是一个promise
对象,那么这个对象会原样返回
const promise2 = Promise.resolve(promise)console.log(promise === promise2) // true
如果传入的是一个对象,且这个对象也有一个then
办法,传入胜利和失败的回调,那么在前面执行的时候,也是能够依照promise
的then
来拿到。
(这个then办法,实现了一个thenable的接口,即能够被then的对象)
应用场景
- 能够是把第三方模仿
promise
库转化成promise
对象
Promise.reslove({ then: function(onFulfilled, onRejected) { onFulfilled('foo') }}).then(function (value) { console.log(value) // foo})
- 间接将数值转换成
promise
对象返回
function test (bool) { if (bool) { return new Promise((resolve,reject) => { resolve(30) }) } else { return Promise.resolve(42) }}test(1).then((value) => { console.log(value)})
Promise.reject()
Promise.reject(error)
是和 Promise.resolve(value)
相似的静态方法,是 new Promise()
办法的快捷方式。
创立一个肯定是失败的promise
对象
Promise.reject(new Error('出错了'))//等同于new Promise(function (resolve) { reject(new Error('出错了'))})
数据聚合 —— Promise.all()
如果须要同时进行多个异步工作,应用promise
静态方法中的all办法,能够把多个promise
合并成一个promise
对立去治理。
Promise.all(promiseArray);
Promise.all
生成并返回一个新的Promise
对象,所以它能够应用Promise
实例的所有办法。参数传递promise
数组中所有的Promise
对象都变为resolve
的时候,该办法才会返回, 新创建的Promise
则会应用这些promise
的值。- 参数是一个数组,元素能够是一般值,也能够是一个
promise
对象,输入程序和执行程序无关,- 该函数生成并返回一个新的
Promise
对象,所以它能够应用Promise
实例的所有办法。参数传递promise
数组中所有的Promise
对象都变为resolve
的时候,该办法才会返回实现。只有有一个失败,就会走catch
。- 因为参数数组中的每个元素都是由
Promise.resolve
包装(wrap
)的,所以Paomise.all
能够解决不同类型的promose
对象。
var promise = Promise.all([ // ajax函数是一个异步函数并返回promise,不须要关怀哪个后果先回来,因为是都实现之后整合操作 ajax('/api/users.json'), ajax('/api/posts.json')])Promise.then(function(values) { console.log(values) //返回的是一个数组,每个数组元素对应的是其promise的返回后果}).catch(function(error) { console.log(error) // 只有有一个失败,那么就会整体失败走到catch外面})
竞争 —— Promise.race()
Promise.race(promiseArray);
和
all
一样会接管一个数组,元素能够是一般值也能够是promise
对象,和all
不同的是,它只会期待第一个完结的工作 。
// 上面的例子如果request超过了500ms,那么就会报超时错诶,如果小于500ms,则失常返回。const request = ajax('/api/posts.json')const timeout = new Promise((resovle, reject) => { setTimeout(() => reject(new Error('timeout')), 500)})Promise.race([ request, timeout]).then(value => { console.log(value)}).catch(error => { console.log(error)})
Promise执行时序 —— 宏工作 vs 微工作
执行程序 : 宏工作 => 微工作 => 宏工作
微工作 是promise
之后才退出进去的,目标是为了进步整体的响应能力
咱们目前绝大多数异步调用都是作为宏工作执行,promise
的回调 &MutationObserver
&node
中的process.nextTick
会作为微工作执行
上面的例子,以后宏工作立刻执行,then
是微工作会延后执行,setTImeout
是异步的一个宏工作也会延后执行。以后宏工作执行结束之后,微工作会先执行结束之后下一个宏工作才会执行。
console.log('global start')setTimeout(() => { console.log('setTimeout')}, 0)Promise.resolve() .then(( => { console.log('promise') })) .then(( => { console.log('promise2') })) .then(( => { console.log('promise3') }))console.log('global end')// global start// global end// promise// promise2// promise3// setTimeout
具体的牵扯到eventLoop
的货色之后再进一步探讨。
深度分析:手写一个Promise源码
深度分析:手写一个Promise源码
ES6-ES10学习幅员
说实话这个是最近比较复杂的一个笔记了,给本人点个赞,标个非凡标记。