es6-深入理解promise

391 阅读3分钟

先讲一下什么是回调地狱->callback hell,给大家看一张图片,回调地狱就是异步里面套了异步,下面的异步请求依赖于上一个异步请求的结果,必须嵌套进去,放在回调里面,就形成了回调地狱。为了解决这一问题,es6出现了一个api,就是promise.

promise其实就是一个构造函数,我们typeof promise ,就能得出一个"function",也可以把它理解为一个容器,这个容器中存放了一个异步任务。它有三种状态,Pending(进行中),resolved(已成功),rejected(已失败)。

下面我们创建一个promise容器

Promise容器一旦创建,就开始执行里面的代码

var fs = require('fs')
new Promise(function(){
    fs.readFile('./a.txt','utf8,function(err,data)'{
        if(err){
            //失败了,承诺容器中的任务失败了
            console.log(err)
        }else{
            //承认容器中的任务成功了
            console.log(data)
        }
        
    })
})

下面我们写一个输出,

console.log(1)
new Promise(function(){
    console.log(2)
    fs.readFile('./a.txt','utf8,function(err,data)'{
        if(err){
            //失败了,承诺容器中的任务失败了
            console.log(err)
        }else{
            console.log(3)
            //承认容器中的任务成功了
            console.log(data)
        }
        
    })
})
console.log(4)

输出的结果是什么? 1 2 4 3 为什么会输出这样的呢?js执行顺序不是从上到下么?下面我们简单分析下: 先输出1,紧接着遇到了new promise,立即执行,输出2,我们上边提到了promise里面的任务是一个异步,所以执行输出4,当异步执行完后输出3

在此强调下:promise本身不是异步,但是内部往往都是封装一个异步任务。

下面我们继续,上边提到了promise有成功和失败的状态,所以我们把上边new promise的代码改写下。

var p1=new Promise(function(resolve,reject){
    fs.readFile('./a.txt','utf8,function(err,data)'{
        if(err){
            //失败了,承诺容器中的任务失败了
            //把容器的Pending状态变为失败Rejected
            //调用reject就相当于调用了then方法的第二个参数函数
           reject(err)
        }else{
            //承认容器中的任务成功了
            //console.log(data)
            //把容器的Pending状态变为成功resoved
            //也就是说这里调用的resolve方法实际上就是then方法传递的那个function
            resolve(data)
        }
    })
})

上面的代码描述了我们图中promise的概念,promise里面有一个异步任务,默认的状态pending成功了变成resoved,失败了变成rejected。 那么我们如何使用它呢?

//p1就是promise
//当p1成功了然后(then)做指定的操作
//then方法接收的function就是容器中的resovle函数
p1
    .then(function(data){
        console.log(data)
    },function(err){
        console.log('读取失败了',err)
    })

以上是promise的基础语法, 我用图来表示下

下面我们来说下解决回调地狱问题:

p1
.then(function(data)){
    //当p1读取成功的时候,当前函数中return的结果就可以在后面的thenfunction接收到,
    //当你return 123后面就接收到123
    // return 'hello' 后面就接收到'hello'
    //没有return 后面收到的就是undefined
    //其实我们真正用到的是可以return 一个promise对象
    //当return 一个Promise对象的时候,后续的then中的方法的第一个参数会作为p2的resolve
   // return 123
   
   return p2
},function(err){
    console.log(err)
})
.then(function(data){
    console.log(data) //在此接收p2的返回值
})

var p2=new Promise(function()){
    fs.readFile('./a.txt','utf8,function(err,data)'{
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    })
})

我们也可以多添加几个then去返回多个new Promise,这个就是then的链式调用 上图来描述下,

下面我们封装一个readFile,

var fs = require('fs')
function pReadFile(filePath) {
    return new Promise(function (resolve,reject) {
        fs.readFile(filePath,'utf8',function (err,data) {
            if(err){
                reject(err)
            }else{
                resolve(data)
            }
        }
    }
}
pReadFile('./data/test.txt')
    .then(function(data){
        console.log(data)
        return pReadFile('./data/a.txt')
    })
    .then(function(data){
        console.log(data)
        return pReadFile('./data/b.txt')
    })
    .then(function(data){
        console.log(data  
    })

以上是一个简单完整的小例子。 现在我们封装一个promise的ajax方法。

function pGet(url,callback){
    return new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest()
        xhr.onload = function(){
            callback && callback(JSON.parse(pGet.responseText))
            resolve(JSON.parse(pGet.responseText))
        }
        xhr.onerror = function(){
            reject(err)
        }
        xhr.open("get",url,true)
        xhr.send()
    }
}