JS-异步编程和Promise

但是我们发现一个问题:

p()调用 =》

new Promise(executor),产生Promise对象 =》

executor执行 =》

异步任务setTimeout执行  =》

setTimeout是异步任务,会被挂起,JS主线程继续执行同步代码  =》

then方法被调用 =》

then方法中this.promiseState值为pending,因为setTimeout是异步任务还没有执行,导致resolve()没有调用,导致this.promiseState未被改变

被解耦的回调函数代码的执行,依赖于Promise对象的状态是完成态,

而Promise对象的状态完成依赖于异步任务的完成,

而异步任务的完成依赖于同步代码的结束,

而同步代码的结束依赖于被解耦的回调函数代码的执行。

死循环了。

未必,我们只要让上面流程中的一环闭环就行了,“被解耦的回调函数代码的执行”,这里我们不能强制要求回调函数的代码执行,因为理论上来说,回调函数的代码一定要在异步任务完成后执行。所以既然异步任务在等这里的同步代码结束,那我们就把回调函数的代码再还回去。

当Promise对象调用then方法,发现this.promiseState为pending时,表示封装的任务一定是异步任务,那么我们就把回调函数再还回去,等待异步任务结束执行。

因为异步任务一定会去调用resolve或reject方法修改this.promiseState,所以我们可以在resolve或reject中执行还回去的回调函数。

至此我们就完成了Promise的异步封装,实现了异步任务和回调函数的解耦。

Promise实现异步任务间串行执行,即异步任务间的同步执行

==============================

传统的JS异步任务,必须要通过回调函数嵌套异步任务,才能实现异步任务之间串行执行。当嵌套层级过深,就会形成回调地狱,导致代码结构臃肿,不易改动。

Promise的出现,让异步任务和其回调函数解耦,回调函数不用定义在异步任务原有框架中,可以在异步任务框架定义。这就从结构上杜绝了回调地狱的可能。

在逻辑上:

当前被解耦的回调函数是随着Promise.prototype.then调用而被传递给改变Promise状态的方法resolve和reject,异步任务的执行触发了resolve和reject的调用,而resolve和reject的调用触发了被解耦的回调函数的调用。

所以可以简单理解为:随着then方法的调用,被解耦的回调函数也被调用了

即我们想要执行异步任务的回调函数,就调用then方法。而then方法本身是同步任务。

那么如果有多个被Promise封装的异步任务,是不是可以通过分别调用then方法来实现串行执行呢?

function Promise(executor){

this.promiseState = ‘pending’

this.promiseResult = null

this.callback = null

let that = this

function resolve(data) {

that.promiseState = ‘fulfilled’

that.promiseResult = data

if(that.callback) {

that.callback.onResolve()

}

}

function reject(data) {

that.promiseState = ‘rejected’

that.promiseResult = data

if(that.callback) {

that.callback.onReject()

}

}

executor(resolve,reject)

}

Promise.prototype.then = function(onResolve, onReject){

if(this.promiseState === ‘fulfilled’) {

onResolve()

} else if(this.promiseState === ‘rejected’) {

onReject()

} else {

this.callback = {

onResolve : onResolve,

onReject : onReject

}

}

}

function p1() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},1000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

function p2() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},2000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

function p3() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},3000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

p1().then(function(value){

console.log(new Date,‘a’)

},function(reason){

console.log(reason)

})

p2().then(function(value){

console.log(new Date,‘b’)

},function(reason){

console.log(reason)

})

p3().then(function(value){

console.log(new Date,‘c’)

},function(reason){

console.log(reason)

})

答案是不行的,因为then方法虽然是同步的,但是then方法的参数,即解耦的回调函数的执行不是then方法触发的(这里指异步情况,如果Promise封装的是同步任务,那这里回调函数就是then方法触发),then方法只负责将回调函数保存到Promise对象的callback属性中,当异步操作完成,异步任务就会调用resolve方法或reject方法,后面resove或reject方法会负责调用回调函数。

即:真正触发异步解耦的回调函数的调用的还是异步操作的完成。

那么如何保证then方法中的回调函数执行完,才继续执行下个同步任务呢?

Promise对then方法做了如下设计:

then方法可以返回一个新的Promise对象,可以用来作为异步任务串行调用过程中下次then的调用者。

即:下一次then的调用者是上一次then的返回值,而then的返回值又取决于其形参回调函数的返回值。

这样就形成了一个依赖关系:

下次then的调用的调用者,依赖于上次then的返回值,

上次then的返回值,依赖于本身形参(回调函数)的返回值

回调函数的返回值,依赖于resolve或reject函数的执行

resolve或reject函数的执行,依赖于异步操作的完成,

所以下次then的调用必须要等上次then回调函数执行完成,即等上次then对应的异步任务的完成

then方法返回的Promise对象生成逻辑如下:

当回调函数的返回值是一个Promise对象时,then就返回一个和该Promise对象有相同状态和结果的新的Promise对象

当回调函数的返回值是一个非Promise对象时,then就返回一个fulfilled状态,以及将回调函数返回值作为结果的新的Promise对象

function Promise(executor){

this.promiseState = ‘pending’

this.promiseResult = null

this.callback = null

let that = this

function resolve(data) {

that.promiseState = ‘fulfilled’

that.promiseResult = data

if(that.callback) {

that.callback.onResolve()

}

}

function reject(data) {

that.promiseState = ‘rejected’

that.promiseResult = data

if(that.callback){

that.callback.onReject()

}

}

executor(resolve,reject)

}

Promise.prototype.then = function(onResolve, onReject){

let that = this

return new Promise((resolve,reject)=>{

function common§ {

if(p instanceof Promise){

p.then(v => {

resolve(v);

}, r => {

reject®;

})

} else {

resolve§

}

}

if(that.promiseState === ‘fulfilled’) {

let p = onResolve(that.promiseResult)

common§

} else if(that.promiseState === ‘rejected’) {

let p = onReject(that.promiseResult)

common§

} else {

that.callback = {

onResolve : function(){

let p = onResolve(that.promiseResult)

common§

},

onReject : function() {

let p = onReject(that.promiseResult)

common§

}

}

}

})

}

function p1() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},1000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

function p2() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},2000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

function p3() {

return new Promise(

function(resolve,reject){

try {

setTimeout(function(){

resolve(‘OK’)

},3000)

} catch(e) {

reject(‘NOK’)

}

}

)

}

p1().then(v=>{

console.log(new Date,‘a’)

return p2()

}).then(v=>{

console.log(new Date,‘b’)

return p3()

}).then(v=>{

console.log(new Date,‘c’)

})

这就是Promise实现异步任务串行执行的原理。

Promise的其他特性


1、Promise对象的状态只能修改一次,即只能从pending-》fulfilled或pending-》rejected

Promise对象的状态修改,是通过resolve和reject方法,所以只要在resolve和reject方法执行前判断Promise对象的状态是pending即可,若不是pending,则状态已经被修改过,不能再次修改

function Promise(executor){

this.promiseState = ‘pending’

this.promiseResult = null

this.callback = null

let that = this

function resolve(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘fulfilled’

that.promiseResult = data

if(that.callback) {

that.callback.onResolve()

}

}

function reject(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘rejected’

that.promiseResult = data

if(that.callback){

that.callback.onReject()

}

}

executor(resolve,reject)

}

Promise.prototype.then = function(onResolve, onReject){

let that = this

return new Promise((resolve,reject)=>{

function common§ {

if(p instanceof Promise){

p.then(v => {

resolve(v);

}, r => {

reject®;

})

} else {

resolve§

}

}

if(that.promiseState === ‘fulfilled’) {

let p = onResolve(that.promiseResult)

common§

} else if(that.promiseState === ‘rejected’) {

let p = onReject(that.promiseResult)

common§

} else {

that.callback = {

onResolve : function(){

let p = onResolve(that.promiseResult)

common§

},

onReject : function() {

let p = onReject(that.promiseResult)

common§

}

}

}

})

}

2、一个Promise对象可以调用多次then方法,且后面的不会覆盖前面的

一个Promise对象的多次then方法调用,当前代码是会发生覆盖的,因为对于异步任务封装而言,Promise对象调用then方法就是将回调函数保存到Promise对象callback属性中,等待异步任务完成后调用。

一个Promise对象的多次then方法调用,就是将多个then方法保存到Promise对象callback属性中,当前callback属性设计就是一个对象,所以每次then调用都会导致callback属性指向改变,即覆盖现象。

function Promise(executor){

this.promiseState = ‘pending’

this.promiseResult = null

this.callback = []

let that = this

function resolve(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘fulfilled’

that.promiseResult = data

if(that.callback) {

that.callback.forEach(item=>{item.onResolve()})

}

}

function reject(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘rejected’

that.promiseResult = data

if(that.callback){

that.callback.forEach(item=>{item.onReject()})

}

}

executor(resolve,reject)

}

Promise.prototype.then = function(onResolve, onReject){

let that = this

return new Promise((resolve,reject)=>{

function common§ {

if(p instanceof Promise){

p.then(v => {

resolve(v);

}, r => {

reject®;

})

} else {

resolve§

}

}

if(that.promiseState === ‘fulfilled’) {

let p = onResolve(that.promiseResult)

common§

} else if(that.promiseState === ‘rejected’) {

let p = onReject(that.promiseResult)

common§

} else {

that.callback.push({

onResolve : function(){

let p = onResolve(that.promiseResult)

common§

},

onReject : function() {

let p = onReject(that.promiseResult)

common§

}

})

}

})

}

3、当我们指定的executor函数,回调函数出现异常时,我们应该做容错机制,此时应该产生一个状态为rejected,结果为异常信息的Promise对象

function Promise(executor){

this.promiseState = ‘pending’

this.promiseResult = null

this.callback = []

let that = this

function resolve(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘fulfilled’

that.promiseResult = data

if(that.callback) {

that.callback.forEach(item=>{item.onResolve()})

}

}

function reject(data) {

if(that.promiseState !== ‘pending’) return

that.promiseState = ‘rejected’

that.promiseResult = data

if(that.callback){

that.callback.forEach(item=>{item.onReject()})

}

}

try {

executor(resolve,reject)

} catch (e) {

reject(e)

}

}

Promise.prototype.then = function(onResolve, onReject){

let that = this

return new Promise((resolve,reject)=>{

function common§ {

if(p instanceof Promise){

p.then(v => {

resolve(v);

}, r => {

reject®;

})

} else {

resolve§

}

}

if(that.promiseState === ‘fulfilled’) {

try {

let p = onResolve(that.promiseResult)

common§

} catch (e) {

reject(e)

}

} else if(that.promiseState === ‘rejected’) {

try {

let p = onReject(that.promiseResult)

common§

} catch (e) {

reject(e)

}

} else {

that.callback.push({

onResolve : function(){

try {

let p = onResolve(that.promiseResult)

common§

} catch (e) {

reject(e)

}

},

onReject : function() {

try {

let p = onReject(that.promiseResult)

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
promiseResult)

common§

} catch (e) {

reject(e)

}

} else if(that.promiseState === ‘rejected’) {

try {

let p = onReject(that.promiseResult)

common§

} catch (e) {

reject(e)

}

} else {

that.callback.push({

onResolve : function(){

try {

let p = onResolve(that.promiseResult)

common§

} catch (e) {

reject(e)

}

},

onReject : function() {

try {

let p = onReject(that.promiseResult)

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-BBDmjPFq-1715540854401)]

[外链图片转存中…(img-aG1QQ1hc-1715540854401)]

[外链图片转存中…(img-spsNZ9B9-1715540854402)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值