学习Promise日记

学习Promise日记 什么是Promise? ? promise(翻译:承诺;期待;期约),在《javascript高级程序设计》这本书叫做“期约”,‘期约’的解释是尚不存在的结果,我的理解是:很期待我们的约定的结果(真的很期待能跟她约个好结果,比如结婚、生仔、幸福一辈子,哈哈哈)。但是世事难料,她可能会拒丑,哎,别想太多,不管结果怎么样我都要正确的去面对这些结果。其实我比较花心,我约完这个还跟另一个女孩有期约,另一个女孩跟我约完又跟其他帅哥有期约...
? Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。
Promise状态机 Promise状态机有三种状态:待定(pending)、兑现(fulfilled或者resloved)、拒绝(rejected)

callback_pending = (resolve, reject) => {} callback_resolve = (resolve, reject) => resolve() callback_reject = (resolve, reject) => reject() function promise_instance(callback) { return new Promise(callback) } console.log(promise_instanc(callback_pending)); //回调函数未执行resolve,或者reject,状态处于pending状态 console.log(promise_instanc(callback_resolve)); //回调函数执行了resolve, 状态处于兑现(resloved)状态 console.log(promise_instanc(callback_reject)); //回调函数执行了reject, 状态处于拒绝(rejected)状态

Promise.prototype方法中的then()、catch()、finally(),作为Promise在拒绝或者兑现状态的处理程序
Promise.resolve() Promise并不是开始就必须处于pending的状态然后转换为兑现(resloved)、拒绝(rejected)。通过Promise.resolve()这个静态方法,可以把任何值转换为一个resolved状态的Promise
//以下两行p1和p2的打印结果是一样的 let p1 = new Promise((resolve, reject) => resolve(1)) let p2 = Promise.resolve(1) console.log(p1)//Promise {: 1} console.log(p2) //Promise {: 1}

这个方法如果传入的参数是一个Promise,那么它的行为就类似于一个空包装,最终的值是传入的参数的值,可以说是一个幂等函数
let p = Promise.resolve(1) console.log(p === Promise.resolve(p)); // true

根据上条,这个幂等函数会保留传入Promise的状态
let p = new Promise(() => {}) console.log(Promise.resolve(p)); //Promise {} console.log(p); ////Promise {}

它可以包装任何非Promise的值,包括错误对象
let p = Promise.resolve(new Error('error')) console.log(p); //Promise {: Error: error

Promise.reject() 与Promise.resolve()类似,Promise.reject()可以把任何值转换为一个rejected状态的Promise,并且抛出一个异步错误,但是这个错误不能通过try/catch捕获,只能通过Promise的.then()或者.catch()的方法进行捕获。但它不像Promise.resolve()是一个幂等方法,就算传入的是Promise.reject(),它返回的也是一个拒绝理由为Promise.reject()
Promise.reject('err').then(null, (err) => console.log(err)) //err Promise.reject('err').catch((err) => console.log(err)) //err try{ Promise.reject('err') }catch(err){//捕获不到,没有执行catch,是因为它没有通过异步模式捕获 console.log(err); }

Promise.prototype.then() Promise.prototype.then()是Promise实例添加处理程序的主要方法,.then()可以接收两个参数,分别为resolved状态时的回调函数、rejected状态的回调函数。
//resolve先执行 new Promise((resolve, reject) => { resolve('我给你兑现')//首先被执行了,转换为resolve状态 reject('我拒绝你')//如果resolve先执行,不会被执行了,会被静默忽略,因为状态只能转换一次 }).then( (res) => console.log(res), //res拿到resolve传的参数,输出:这是兑现执行的 (rej) => console.log(rej), //这里不执行 ) //reject先执行 new Promise((resolve, reject) => { reject('我拒绝你')//首先被执行了,转换为reject状态 resolve('我给你兑现')//如果reject先执行,不会被执行了,会被静默忽略,因为状态只能转换一次 }).then( (res) => console.log(res), //这里不执行 (rej) => console.log(rej), //rej拿到reject传的参数,输出:这是拒绝执行的 )

Promise.prototype.catch() ? Promise.prototype.catch()是.then(null, () => {}}的语法糖,用来捕获拒绝理由的
new Promise((resolve, reject) => { reject('我拒绝你') }).catch(err => console.log(err) )//我拒绝你

Promise.prototype.finally() Promise.prototype.finally()是Promise无论转换成什么状态都会被执行,它也无法知道是Promise处于什么状态。
后续finally()包裹的内容,除了pending状态或者抛出了错误会返回Promise或者Promise,其余返回的是Promise
pending状态时,无论什么时候resolve或者reject,都会在resolve或者reject时返回Promise
let p2 = p1.finally(() => new Promise(() =>setTimeout(() => resolve('bar'),100))); setTimeout(console.log(p), 0); //Promise setTimeout(() => setTimeout(console.log(p2),200)); //上一个setTimeou 100ms执行完回调后才到这个setTimeout回调,这时拿到的p2已经resolve,输出:Promise :foo

Promise与同步代码执行顺序 Promise被转变状态之后,并不会马上执行,它的处理程序是会被推进消息队列中。所以在同步进程执行完,它的处理程序才会执行。
let p =let Promise.resolve(); p.then(()=> console.log('Promise')); console.log('同步输出')//它的输出顺序为:先输出同步输出 ,再输出Promise

Promise链式调用 Promise能链式调用是因为then()、catch()、finally()都会返回一个新的Promise
如果你真的弄懂了Promise状态处理机制,对下面代码的执行结果就能了如指掌了。
let p = new Promise((resolve, reject) => { resolve('resolve') }) .then(res => console.log(res))//resolve .then(res => console.log(res)) //undefined .then(res => console.log(res))//undefined .then(() => Promise.reject('reject')) .catch(e => { console.log(e); return 8//相当于return Promise.resolve(8) }) //reject .then((res) => { console.log(res); return Error('error') //相当于return Promise.reject('error')抛出异步错误 }) .then( res => console.log(res),//不执行 err => console.log(err) //输出error ) .finally(f => console.log(f))//最后肯定会执行,f得不到任何值,输出undefined

Promise.all() Promise.all()的参数是一个数组,只有当数组的所有Promise为resolved时才执行.then(),否则执行.catch()
Promise.all([ Promise.resolve(1), Promise.resolve(2), new Promise((resolve,reject) => resolve(3)) ]).then(result => console.log(result) ) //[1, 2, 3]//处理程序第一个被reject的 Promise.rece([ Promise.resolve(1), Promise.reject(2), Promise.reject(3), new Promise((resolve, reject) => resolve(3)) ]).then(result=> console.log(result)) //不执行 .catch(e => console.log(e)) //得到第一个被rejected的值,输出:2

Promise.race() Promise.race()的参数也是一个数组,会返回第一个先被转变状态的Promise。
//resolve(100)先被执行的情况 Promise.race([ new Promise((resolve, reject) => setTimeout(()=> resolve(300), 300)), new Promise((resolve, reject) => setTimeout(() => resolve(200), 200)), new Promise((resolve, reject) => setTimeout(() => resolve(100), 100)), ]).then(result=> console.log(result)) // 100 .catch(e => console.log(e)) //不执行 //reject(100)先被执行的情况 Promise.race([ new Promise((resolve, reject) => setTimeout(() => resolve(300), 300)), new Promise((resolve, reject) => setTimeout(() => resolve(200), 200)), new Promise((resolve, reject) => setTimeout(() => reject(100), 100)), ]).then(result => console.log(result)) //不执行 .catch(e => console.log(e)) //100

Promise链式调用的合成 Promise.then()+ Array.reduce()可以把多层链式调用简化为一个通用函数compose,这样使代码更加简洁
function add2(x) { return (x+2)}; function add3(x) { return (x + 3) } function add4(x) { return (x + 4) } function compose(...args) { return x => args.reduce((promise, fn) => promise.then(fn),Promise.resolve(x)) }

Promise的扩展 【学习Promise日记】Promise的进度通知
class TrackablePromise extends Promise { constructor (executor) { const notifyHandlers = []; super((res, rej) => { return executor(res, rej, (status) => { notifyHandlers.map((handlder) => handlder(status)); }) }) this.notifyHandlers = notifyHandlers; } notify(notifyHandler) { this.notifyHandlers.push(notifyHandler); return this } } let p = new TrackablePromise((res, rej, notify) => { function countdown(x) { if(x > 0) { notify(`${20*x}% remaining`); setTimeout(() => countdown(x-1), 1000) }else { res(); } } countdown(5); }) p.notify((x) => setTimeout(console.log, 0, 'progress', x)); p.then(() => setTimeout(console.log, 0, 'completed')); /* (1秒后打印):progress 80% remaining (2秒后打印):progress 60% remaining (3秒后打印):progress 40% remaining (4秒后打印):progress 20% remaining (5秒后打印):completed */

    推荐阅读