Promise的底层是浏览器实现的,所以我只是实现了里的功能,并非和源码一摸一样。下面为部分源码,完整源码移驾到github中下载: https://github.com/young-monk/my-promise.git 我们首先来定义一个MyPromise类,我在这里使用立即执行函数的方式,防止变量全局污染。 接下来,定义一些内部使用的变量:我这里使用了 我们都知道,当我们 接下来,我们就要实现 接下来我们要实现 因为功能相同,我进行了 2 次封装,都是哪两次封装呢?这是第一次,也就是实现加入任务队列的功能: 还有一次封装,也就是我们上面调用的 如果你能看到这里,说明你已经对Promise已经完全掌握了,下面实现的是几个Promise的静态成员: all成员 race成员 resolve和reject静态成员 ES6 将某一件可能发生异步操作的事情,分为两个阶段: unsettled:未决阶段,表示事情还在进行前期的处理,并没有发生通向结果的那件事 settled:已决阶段,事情已经有了一个结果,不管这个结果是好是坏,整件事情无法逆转 异步操作总是从 未决阶段 逐步发展到 已决阶段的。并且,未决阶段拥有控制何时通向已决阶段的能力。 异步操作分成了三种状态: 一旦这种状态改变,就会固定,不会再改变。是不可逆的Promise状态的改变只有两种情况: 参考流程图: 为了解决地狱回调和异步操作之间的联系,ES6提出了一种异步编程大的解决方案Promise。但是Promise并没有消除回调,只是让回调变得可控。 Promise是一个对象,它可以获取异步操作的消息。为了方便和简易,下面的 注意: Promise创建后会立即执行。 在未决阶段的处理函数中,如果发生未捕获的错误,会将状态推向 一旦状态推向了已决阶段,无法再对状态做任何更改。 Promise并没有消除回调,只是让回调变得可控。 以上代码,立即创建一个Promise函数,并且立即执行函数中的代码,所以首先输出 then():注册一个后续处理函数,当Promise为 catch():注册一个后续处理函数,当Promise为 Promise对象中,无论是 注意:后续的Promise一定会等到前面的Promise有了后续处理结果后,才会变成已决状态 如果前面的Promise的后续处理,返回的是一个Promise,则返回的新的Promise状态和后续处理返回的Promise状态保持一致。 上述代码,在执行 上述代码,对于串联的Promise,then和catch均返回一个全新的Promise,所以在pro1的catch执行时返回的pro2执行的是正常的,并非抛出错误。所以执行的为 上述代码,每一次返回都是一个全新的Promise,所以 上述代码,第一个 上面代码,最后一个输出 该方法返回一个 特殊情况:如果传递的数据是Promise,则直接返回传递的Promise对象 该方法返回一个 返回的新的Promise对象的状态分成两种情况: 上述代码就是一个非常简单的调用方法 上面代码是产生10个Promise对象,每个Promise对象都延迟时间1~5s中的随机时间后将状态推向已决,调用all方法,当10个Promise对象全部完成后再输出,或有一个错误的时候,也输出。 当参数里的任意一个Promise被成功或失败后,新Promise马上也会用参数中那个promise的成功返回值或失败详情作为参数调用新promise绑定的相应句柄,并返回该promise对象 上述代码和 例子:异步加载图片 一旦图片加载完成,就会Promise状态就会发生变化。 async 和 await 是 ES2016 新增两个关键字,它们借鉴了 ES2015 中生成器在实际开发中的应用,目的是简化 Promise api 的使用,并非是替代 Promise。实际上就是生成器函数的一个语法糖。目的是简化在函数的返回值中对Promise的创建。 async 用于修饰函数(无论是函数字面量还是函数表达式),放置在函数最开始的位置,被修饰函数的返回结果一定是 Promise 对象。 注意: 正常情况下, 注意: 如果多个 先让 await用在某个表达式之前,如果表达式是一个Promise,则得到的是 如果
Promise源码分析
const MyPromise = (() => { //在这里定义内部变量 return class { //构造器 constructor(executor) { //... } })()
Symbol
,使用Symbol
的原因是改变量只能内部使用const MyPromise = (() => { //在这里定义内部变量 const PENDING = "pending" const RESOLVED = "resolved" const REJECTED = "rejected" //使用Symbol是为了仅供内部使用 const PromiseStatus = Symbol("PromiseStatus")//当前状态 const PromiseValue = Symbol("PromiseValue")//当前值 return class { //构造器 constructor(executor) { //... } })()
new Promise
的时候,会有一个状态,会有值,还会传入两个函数,resolve
和reject
。那么我们实现一下:constructor(executor) { //初始化 this[PromiseStatus] = PENDING //当前状态 this[PromiseValue] = undefined //当前值 /** * 定义 resolve 函数 * @param {*} data: 要返回的数据 */ const resolve = (data) => { //... } /** * 定义reject函数 * @param {*} data: 要返回的数据 */ const reject = (data) => { //... } //执行 executor(resolve, reject) }
resolve
和reject
函数的功能,其实这两个函数的功能非常简单,就是修改当前的状态和值,并且如果有任务队列,我们就执行任务队列中的内容。我把这两个函数的功能封装一下:/** * 改变状态的函数 * @param {*} data: 数据 * @param {*} status: 要改变的状态,resolve 或 reject * @param {*} queue: 任务队列 */ [changeStatus](data, status, queue) { //如果已经是已决状态,那么直接结束 if (this[PromiseStatus] !== PENDING) return; this[PromiseStatus] = status //修改当前状态 this[PromiseValue] = data //修改值 //变成已决阶段后,执行相应的队列函数 queue.forEach(q => q(data)) } //---- 在 resolve 函数中调用 this[changeStatus](data, RESOLVED, this[thenables]) //---- 在 reject 函数中调用 this[changeStatus](data, REJECTED, this[catchables])
then
和catch
这两个后续处理函数,这两个函数实现什么功能想必大家都知道了,但我们要注意的是,如果调用then或者catch的时候,当前的状态已经是已决状态,那么就要直接执行。如果不是,那么就加入任务队列中,我在构造器中已经声明了 thenables
和 catchables
变量(then
和catch
函数的任务队列) //settled then处理函数 then(thenable, catchable) { //每个then都要返回一个新的promise return this[linkPromise](thenable, catchable) } //settled catch处理函数 catch (catchable) { return this[linkPromise](undefined, catchable) }
/** * then和catch的处理函数,分为两种情况,如果当前已经是已决状态, * 那么直接执行(此时直接执行也要加入事件队列中,无法模拟微队列,只能用宏队列实现下),如果当前还是未决状态, * 那么把当前的处理函数加入相应的任务队列中 * @param {*} handler 处理函数 * @param {*} queue 处理队列 */ [settledHandler](handler, status, queue) { //如果不是函数,那么直接返回 if (typeof handler !== "function") return if (this[PromiseStatus] === status) { //如果已经是已决状态,直接执行 setTimeout(() => { handler(this[PromiseValue]) }, 0); } else { //处于未决状态,加入任务队列 queue.push(handler) } }
linkPromise
函数,为什么要调用这个函数?因为then
和catch
后续处理函数,都要返回一个新的Promise
,我们什么时候知道,then 或 catch 函数执行了,该返回新的Promise呢?这里是比较难的一部分,我们可以将 settledHandler
也就是执行处理函数的功能,反正创建一个新的 Promise中执行:/** * 用于创建一个新的Promise, 当我们调用then和catch处理函数时, 会返回一个新的Promise * @param {*} thenable * @param {*} catchable */ [linkPromise](thenable, catchable) { /** * 返回一个新的Promise的状态处理,如果父级已经变为已决状态, 那么新的Promise也是已决状态 * @param {*} data * @param {*} handler * @param {*} resolve * @param {*} reject */ function exec(data, handler, resolve, reject) { try { //获取返回值 const res = handler(data) //如果返回的是一个Promise,此时我们直接处理一下就可以 if (res instanceof MyPromise) { res.then(data => resolve(data), err => reject(err)) } else { //改变状态,和修改值 resolve(res) } } catch (error) { reject(error) } } //返回新的Promise return new MyPromise((resolve, reject) => { //处理then的 this[settledHandler](data => { //如果传过来的thenable不是函数,那么直接resolve下并结束 if (typeof thenable !== "function") { resolve(data) return } //我们把操作相同的提取封装一下 exec(data, thenable, resolve, reject) }, RESOLVED, this[thenables]) //处理catch的 this[settledHandler](data => { //如果传过来的thenable不是函数,那么直接reject下并结束 if (typeof catchable !== "function") { reject(data) return } //我们把操作相同的提取封装一下 exec(data, catchable, resolve, reject) }, REJECTED, this[catchables]) }) }
/** * 当数组中的每一个值都变为resolved时,返回新的promise的值resolve为一个数组,数组的内容为proms每个Promise的结果,如果有一个变为rejected, 那么直接结束 * @param {*} proms 假定为一个数组 */ static all(proms) { return new MyPromise((resolve, reject) => { const results = proms.map(p => { var obj = { result: undefined, isResolved: false } //判断是否已经全部完成 p.then(data => { obj.result = data obj.isResolved = true //得到是否有非resolve状态的 const unResolved = results.filter(res => !res.isResolved) if (unResolved.length === 0) {//如果没有 那么我们返回新的Promise resolve(results.map(res => res.result)) } //如果有一个reject状态,那么直接返回 }, err => reject(err)) return obj }) console.log(results) }) }
/** * 当数组中有一个处于已决状态,那么结束 * @param {*} proms: 假定是一个数组 */ static race(proms) { return new MyPromise((resolve, reject) => { proms.forEach(p => { p.then(data => resolve(data), err => reject(err)) }) }) }
/** * 返回一个resolved状态的promise * @param {*} data */ static resolve(data) { //如果穿过来的是一个Promise,直接返回就可以 if (data instanceof MyPromise) { return data } return new MyPromise(resolve => resolve(data)) } /** * 返回一个rejected状态的promise * @param {*} err */ static reject(err) { return new MyPromise((resolve, reject) => { reject(err) }) }
Promise正确打开方式
1、异步处理的通用模型
unsettled
和 settled
pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)
pending
通过resolve()
变为fulfilled
。pending
通过reject()
变为rejected
。2、Promise及其基本使用
resolved
统指fulfilled
状态const pro = new Promise((resolve, reject)=>{ /* 未决阶段的处理 通过调用resolve函数将Promise推向已决阶段的resolved状态 通过调用reject函数将Promise推向已决阶段的rejected状态 resolve和reject均可以传递最多一个参数,表示推向状态的数据 */ if(true){ resolve() }else{ reject() } }) pro.then(data=>{ /* 这是thenable函数,如果当前的Promise已经是resolved状态,该函数会立即执行 如果当前是未决阶段,则会加入到作业队列,等待到达resolved状态后执行 data为状态数据 */ },err=>{ /* then函数也可以填catchable函数,也可以不填。我们最好是通过catch方法添加catchable函数 */ }) pro.catch(err=>{ /* 这是catchable函数,如果当前的Promise已经是rejected状态,该函数会立即执行 如果当前是未决阶段,则会加入到作业队列,等待到达rejected状态后执行 err为状态数据 */ })
thenable
和catchable
函数是异步的,就算是立即执行,也会加入到事件队列中等待执行,加入的队列是微队列。rejected
,并会被catchable
捕获。const pro = new Promise((resolve,reject)=>{ console.log("a") setTimeout(() => { console.log("d") }, 0); resolve(1) console.log("b") }) pro.then(data=>{ console.log(data) }) console.log("c") //a b c 1 d
a
,随后将setTimeout
中代码加入宏队列,然后通过resolve()
将Promise
的状态推向已决状态,但是resolve也是异步的,他会加入到微队列中等同步代码执行完毕后再执行。随后输出b
,Promise
函数执行完后,又执行剩下的同步代码输出c
,同步代码执行完毕后,执行微队列中的输出resolve
的结果值1
,再执行宏队列中的setTimeout
,输出b
。3、Promise的方法then,catch,finally
(1)then()和catch()
resolved
状态时运行该函数rejected
状态时运行该函数then
方法还是catch
方法,它们都具有返回值,返回的是一个全新的Promise对象,它的状态满足下面的规则:
resolved
状态数据,应用到新的Promise中;如果后续处理函数发生错误,则把返回值作为rejected状态数据,应用到新的Promise中。const pro1 = new Promise((resolve,reject)=>{ resolve(1) }) console.log(pro1) // 异步调用, const pro2 = pro1.then(result => result *2) console.log(pro2)//pro2是一个Promise对象,状态是pending pro2.then(result=>{console.log(result)},err=>console.log(err))
console.log(pro2)
的时候是同步执行, 此时pro1.then()
还未执行完毕,所以promise
还是pending
状态const pro1 = new Promise((resolve,reject)=>{ throw 1 }) const pro2 = pro1.then(result => result *2,err=> err*3) pro2.then(result=>{console.log(result*2)},err=>console.log(err*3)) //6
err * 3
,result * 2
。const pro1 = new Promise((resolve,reject)=>{ throw 1 }) const pro2 = pro1.then(result => result *2,err=> err*3) pro1.catch(err=>err*2) pro2.then(result=>{console.log(result*2)},err=>console.log(err*3))
pro1.catch(err=>err*2)
并没有变量接收。const pro1 = new Promise((resolve,reject)=>{ resolve(1) }) const pro2 = new Promise((resolve,reject)=>{ resolve(2) }) const pro3 = pro1.then(result=>{ console.log(`结果${result}`) //1 return pro2 }) //pro3的状态是pending pro3.then(result=>{ console.log(result)//2 })
then
方法指定的回调函数,返回的是另一个Promise
对象。这时,第二个then
方法指定的回调函数,就会等待这个新的Promise
对象状态发生变化后再执行const pro1 = new Promise((resolve,reject)=>{ resolve(1) }) const pro2 = new Promise((resolve,reject)=>{ setTimeout(() => { resolve(2) }, 3000); }) pro1.then(result=>{ console.log(`结果${result}`) //1 return pro2 }).then(result=>{ console.log(result)//2 }).then(result=>{ console.log(result)//undefined })
undefined
是因为第二个then
方法没有返会值。(2)finally()
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。const pro1 = new Promise((resolve,reject)=>{ resolve(1) }) pro1.then(result=>{ console.log(`结果${result}`) //结果1 return 3 }).then(result=>{ console.log(result)//3 }).catch(error=>{ console.log(error) }).finally(()=>{ console.log("我一定会执行的")//我一定会执行的 })
4、Promise的静态成员
(1)resolve()
resolved
状态的Promise,传递的数据作为状态数据。有时需要将现有对象转为 Promise 对象,Promise.resolve()
方法就起到这个作用。const pro = Promise.resolve(1) //等同于 const pro = new Promise((resolve,reject)=>{ resolve(1) })
(2)reject()
rejected
状态的Promise,传递的数据作为状态数据const pro = Promise.reject(1) //等同于 const pro = new Promise((resolve,reject)=>{ reject(1) })
(3)all()
Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口。这个方法返回一个新的Promise对象,
fulfilled
,返回的Promise状态才会变成fulfilled
。此时参数的返回值组成一个数组,传递给新Promise的回调函数。rejected
,新Promise的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给新Promise的回调函数。//p1, p2, p3均是promise对象 const pro = Promise.all([p1, p2, p3]);
function getRandom(min,max){ return Math.random() * (max-min) + min } const proms = [] for(let i=0;i<10;i++){ proms.push(new Promise((resolve,reject)=>{ setTimeout(() => { if(Math.random()<0.1){ reject(i) }else{ resolve(i) console.log(i,"完成") } }, getRandom(1000,5000)) })) } const pro = Promise.all(proms) pro.then(res=>{ console.log("全部完成",res) },err=>{ console.log(err,"错误") })
(4)race()
Promise.race()
方法同样是将多个 Promise 对象,包装成一个新的 Promise 对象。Promise.race()
方法的参数与Promise.all()
方法一样。function getRandom(min,max){ return Math.random() * (max-min) + min } const proms = [] for(let i=0;i<10;i++){ proms.push(new Promise((resolve,reject)=>{ setTimeout(() => { if(Math.random()<0.1){ reject(i) }else{ resolve(i) console.log(i,"完成") } }, getRandom(1000,5000)) })) } const pro = Promise.race(proms) pro.then(res=>{ console.log("有完成的",res) },err=>{ console.log(err,"有错误") }) console.log(proms)
all()
例子一样,只不过,当有一个完成或失败的时候,就会执行pro
的then
或catch
回调函数const preloadImage = function (path) { return new Promise(function (resolve, reject) { const image = new Image(); image.onload = resolve(); image.onerror = reject(); image.src = path; }); };
5、async 和 await
(1)async
async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。async function test(){ console.log(1); return 2;//完成时状态数据 } //等同于 function test(){ return new Promise((resolve, reject)=>{ console.log(1); resolve(2); }) }
async function test(){ console.log(1) return 2 } const pro = test() console.log(pro)//promise对象 promiseValue是2
async
函数返回的 Promise 对象,必须等到内部所有await
命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误。也就是说,只有async
函数内部的异步操作执行完,才会执行then
方法指定的回调函数。(2)await
await
命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。await
类似于生成器的yield
,当遇到await
的时候,就会等待await
后面的Promise对象执行完毕后再继续执行下面代码。async function test(){ const namePro = await getName();//异步ajax const passwordPro = await getPassword(); }
test()
函数执行过程中,会先等待getName()
执行完毕后,再执行getPassword()
await
关键字必须出现在async
函数中await
命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。async function test(){ let namePro = getName(); let passwordPro = getPassword(); let name = await namePro; let password = await passwordPro; }
getName()
和getPassword()
执行,然后再等待结果thenable
中的状态数据。async function test1(){ console.log(1); return 2; } async function test2(){ const result = await test1(); console.log(result); } test2(); //等同于 function test1(){ return new Promise((resolve, reject)=>{ console.log(1); resolve(2); }) } function test2(){ return new Promise((resolve, reject)=>{ test1().then(data => { const result = data; console.log(result); resolve(); }) }) } test2();
await
的表达式不是Promise,则会将其使用Promise.resolve包装后按照规则运行async function test(){ const result = await 1 console.log(result) } //---等同 function test(){ return new Promise((resolve,reject)=>{ Promise.resolve(1).then(data =>{ const result = data console.log(result) resolve() }) }) }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算