1

Promise 是ES6中新出来的API。其实就是对于回调函数的另一种写法,可以帮助我们避免回调地狱。

Promise是一个构造函数,new Promise 返回一个 promise 对象,接收一个带有 resolve 和 reject 两个参数的函数,这个函数在 Promise 构造函数返回所创建 promise 实例对象前被调用。

var p = new Promise(function(resolve, reject) {
    resolve() // 成功时调用
    reject() // 失败时调用
});
p.then(function(res) {
    // 从resolve得到正常结果
}, function(res) {
    // 从reject得到错误信息
})

resolve,reject 是一个函数,处理结束后调用 resolve 或 reject。当调用resolve,会把当前promise对象状态由 pending 标记成功(fulfilled),当调用 reject,会把状态由 pending 标记失败(rejected)。

Promise的三种状态

  • pending :挂起,当前promise执行的任务,正在执行中
  • fulfilled: 完成,当前promise对象执行的任务,已经完成,并且是成功状态
  • rejected: 完成,当前promise对象执行的任务,已经完成,并且处于失败的状态

封装一个支持Promise API的延时函数:

function timeOut(time){
    // 这个函数中就需要返回一个Promise对象
    return new Promise((resolve, reject) => {
        setTimeout(function(){
            // resolve和reject在调用的时候,是可以传递数据的,这个数据会最终被传递到成功或者失败的回调函数中
            resolve(123)
            // resolve()
            // reject()
        }, time)
    })
}

基于Promise处理Ajax请求:

function queryData(url) {
    return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if(xhr.readystate !== 4) return;
            if(xhr.readystate === 4 && xhr.status === 200){
                resolve(xhr.responseText);
            }else{
                reject('出错了');
            }
        }
        xhr.open('get', url);
        xhr.send(null);
    })
}
queryData('http://localhost:3000/data')
    .then(function(res){
        console.log(res);
    }, function(err){
        console.log(err)
    })

//发送多次请求
queryData('url1')
    .then(function(data){
        return queryData('url2');
    })
    .then(function(data){
        return queryData('url3');
    })
    .then(function(data){
        console.log(data);
    })

当 Promise 对象的 fulfilled 或 rejected 任一状态出现时,就会调用 Promise 对象的 .then 方法中绑定的函数。

then 参数中的函数返回值:

  1. 返回 Promise 实例对象

    • 返回的该实例对象会调用下一个 then
  2. 返回普通值

    • 在then方法中,可以直接 return 数据而不是Promise对象
    • 返回的普通值会直接传递给下一个 then,通过 then 参数中函数的参数接受该值

常用API:

  • .then() 得到异步任务的成功信息
Promise
    .then(
        function() {
            console.log('成功的回调')
        },
        function() {
            console.log('失败的回调')
        }
    )
  • .catch() 获取异常信息
Promise
    .then(function() {
        console.log('成功的回调')
    })
    .catch(function() {
        consloe.log('失败的回调')
    })

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

  • .finally() 成功与否都会执行(还不是正式标准)
  • Promise.all() 并发处理多个异步任务,所有任务都执行完成才执行回调函数
const p1 = new Promise((resolve, reject) => {
    resolve(1)
})
const p2 = new Promise((resolve, reject) => {
    resolve(2)
})
const p3 = new Promise((resolve, reject) => {
    resolve(3)
})

Promise
    .all([p1, p2, p3])
    .then(res => {
        console.log("所有异步操作完成了", res) //res: 三个结果的数组,结果顺序和promise实例数组顺序是一致的
    })
    .catch(err => {
        console.log(err)
    })
  • Promise.race() 只要有一个任务完成就会执行回调得到结果
Promise
    .race([p1, p2, p3])
    .then(res => {
        console.log("有一个异步率先完成了", res)
    })

拓展 async/await 的基本用法

async 和 await 这两个关键字是es7提供的,它们可以将Promise的写法进行简化,async和 await 必然同时出现(有 await 必然会有 async)。

  • async 关键字用于函数上(async 函数的返回值是 Promise 实例对象)
  • await 关键字用于 async 函数中(await 可以得到异步的结果)
async function queryData(id){
    const ret = await axios.get('/data');
    return ret;
}
queryData.then(ret => {
    console.log(ret);
})

多个异步请求的场景

async function queryData(id){
    const info = await axios.get('/async1');
    const ret = await axios.get(`/async2?info=`+info.data);
    return ret;
}
queryData.then(ret => {
    console.log(ret);
})

async 和await异常的处理(失败的回调) 使用 try和catch即可

语法:

try { 
    // 成功的回调 
} 
catch(err) {
    // 失败的回调
}

例:

async deleteUser(id) {
    // 成功的回调
    try {
        await this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning"
        })

        let res = await this.$http({
            url: `users/${id}`,
            method: "delete",
            data: id
        })

        console.log(res)
        if (res.data.meta.status === 200) {
            console.log('success', res)
        }
    } 
    // 失败的回调
    catch (err) {
        console.log('已取消删除')
    }
}

sugar_coffee
455 声望19 粉丝