对于promise的初步讲解

promise的学习

promise是es6的新特性,也是最终的特性之一,我写这篇文章的目的是为了记录以便复习,和大家共同学习
期间我在学习的过程中参考的博文链接我放在下面
https://www.cnblogs.com/lvdabao/p/es6-promise-1.html#
参考的视频有黑马对promise的讲解

promise的作用

主要用于解决地狱回调函数
我们在初步使用promise的时候经常会使用到.then .catch 等一些原型方法 还有resolve, reject的回调函数

我们下面直接创建一个promise对象来深入了解一下 promise是什么

通过上面这个图我们可以看到Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。
promise更多的是对异步的处理

下面我们来看一下当我们不使用promise,来读取文件

我们使用nodejs的内置fs来读取文件,我们想要文件按顺序读取的时候就要用到一层一层嵌套,也就是套完 这样问题是解决了
但是我们的代码可读性不高,而且日后想要修改的时候也很困难,牵一发而动全身

那么我们如何来使用promise来去解决这个问题呢
我们来自己封装一个读取文件的promise对象

function readFile1(){
    let p=new Promise((resolve,reject)=>{

        fs.readFile('./text/tx1.txt','utf8',(err,DataStr)=>{
            console.log('读取了file1')
            resolve(DataStr)
        })
    })
    return p
}

看这段我们封装一个读取文件函数 返回值是一个promise对象 那么当我们调用这个函数的时候我们实际得到的是一个promise对象,
这也就说明我们可以调用promise的.then()方法 同时这里我先讲解一下Resolve这个方法

resolve

我们可以先将resolved理解成 当我们读取成功后,我们可以将值传给resolve, 再通过.then()进行回调 拿到成功后的值
但实际在Promise中resolved代表一种状态,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。
这下你应该也能够理解到promise为什么叫做promise了 它是一种承诺,一旦确定为一种状态就不能改变

下面我们再理解一下.then方法

.then()方法是我们对promise中执行结果的一个预处理方法,我们可以事先处理我们在成功后要做什么,在失败后要做什么
所以then中可以传入两个参数,一个reolve回调函数,是对成功的处理,一个是reject回调函数,是对失败的处理。
在then方法中还有一个重要的特点,我们可以在resolve中继续返回一个新的promise对象,那么我们可以在这个then方法后继续使用then方法
这是一个重点,决定这我们如何去处理异步函数,如何去解决回调地狱

下面我们来看一下优化后的代码

readFile1().then(
    (data)=>{
        console.log(data);
        return readFile2()
    }
   
).then((data)=>{
    console.log(data)
    return readFile3()
}).then((data)=>{
    console.log(data);
})

是不是看着更加优雅。而且解决了我们的问题 对于异步函数的处理 当然我们这里是利用读取文件进行演示的,你可以参考我上面放的链接中的利用
定时函数进行模拟

对于promise 你应该有个初步的理解了吧 可能刚开始看的时候确实比较迷 我刚开始也 我尼玛这是啥玩意
放一个完整代码吧 方便大家参考

const fs =require('fs')

function readFile1(){
    let p=new Promise((resolve,reject)=>{

        fs.readFile('./text/tx1.txt','utf8',(err,DataStr)=>{
            console.log('读取了file1')
            resolve(DataStr)
        })
    })
    return p
}

function readFile2(){
    let p=new Promise((resolve,reject)=>{

        fs.readFile('./text/tx2.txt','utf8',(err,DataStr)=>{
            console.log('读取了file2')
            resolve(DataStr)
        })
    })
    return p
}
function readFile3(){
    let p=new Promise((resolve,reject)=>{

        fs.readFile('./text/tx3.txt','utf8',(err,DataStr)=>{
            console.log('读取了file3')
            resolve(DataStr)
        })
    })
    return p
}

readFile1().then(
    (data)=>{
        console.log(data);
        return readFile2()
    }
   
).then((data)=>{
    console.log(data)
    return readFile3()
}).then((data)=>{
    console.log(data);
})

##别急我们再来讲解一下reject的使用
当我们读取我我文件发生错误 我们可以将错误的信息传给rejected,当我们读取出错时候我们就可以拿到错误信息

const fs =require('fs')

function readFile1(){
    let p=new Promise((resolve,reject)=>{

        fs.readFile('./text/tx6.txt','utf8',(err,DataStr)=>{
            console.log('读取了file1')
            if(err) return reject(err.message)
            resolve(DataStr)
        })
    })
    return p
}

readFile1().then(
    // 成功的处理
    (data)=>{
        console.log(data);
    },
    // 失败的处理
    (reason,data)=>{
        console.log('reject')
        console.log(reason);

    }

)

打印出来的结果

这样错误信息就被打印出来了

相信你现在对resolve和reject的用法已经有点思路,多多思考 最好可以将我演示的代码敲一遍出来

下面我们来学习一下.catch方法来

catch

就是捕获错误信息,如果你学过java我信息你现在心里已经知道他是干什么的了
我们可以在开头捕获,和结尾捕获错误的信息 但是这两种写法还是有很大的区别的

关于cache的写法
效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,
如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中
我们对上面的代码进行改造后

readFile1().then(
    // 成功的处理
    (data)=>{
        console.log(data);
    },
    // 失败的处理
    // (reason,data)=>{
    //     console.log('reject')
    //     console.log(reason);

    // }

).catch((reason)=>{
    console.log('rejected');
    console.log(reason);
})

结果

看到这里你知道如何使用了吗

我上面还说过catch写在开头 和结尾有很大区别 我们一起来看看

放在结尾

readFile1().then(
    (data)=>{
        console.log(data);
        return readFile2()
    }
   
).then((data)=>{
    console.log(data)
    return readFile3()
}).then((data)=>{
    console.log(data);
}).catch(
    (reason)=>{
        console.log('rejected');
        console.log(reason);
    }
)

放在开头

readFile1().catch(
    (reason)=>{
        console.log('rejected');
        console.log(reason);
    }
).then(
    (data)=>{
        console.log(data);
        return readFile2()
    }
   
).then((data)=>{
    console.log(data)
    return readFile3()
}).then((data)=>{
    console.log(data);
})

通过比较你发先catch在不同地方的区别了吗
在开头捕获到错误剩下的代码会依然执行
但是在结尾如果一遇到错误会立马执行catch里面的语句

下面我们再来介绍一下 Promise.all(),和 Promise.race()方法

all的用法

Promise
.all([readFile1(), readFile2(), readFile3()])
.then(function(results){
    console.log(results);
});

用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,
等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,
all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。所以上面代码的输出结果就是:

有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,是不是很酷?有一个场景是很适合用这个的,
一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后
,我们再进行页面的初始化。

race用法

all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,
这就是race方法,这个词本来就是赛跑的意思。
下面我们将readfile1函数延迟一秒执行


Promise
.race([readFile1(), readFile2(), readFile3()])
.then(function(results){
    console.log(results);
})

结果

这三个异步操作同样是并行执行的。结果你应该可以猜到,1秒后runAsync1已经执行完了,此时then里面的就执行了。

这个race有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:

//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}

//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}

Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});

requestImg函数会异步请求一张图片,我把地址写为"xxxxxx",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。
我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。
如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。运行结果如下:

好了对于promise我也仅仅是个初学者
如果了解更多请看开头的链接,如果有什么想交流的请留言

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值