Promise详解以及和async await的区别


一、什么是Promise

Promise是ES6中的一个内置对象,实际是一个构造函数,是JS中进行异步编程的新的解决方案。

特点:

  • ① 三种状态:pending(进行中)、resolved(已完成)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都不能改变这个状态。
  • ② 两种状态的转化:其一,从pending(进行中)到resolved(已完成)。其二,从pending(进行中)到rejected(已失败)。只有这两种形式的转变。
  • Promise构造函数的原型对象上,有then()和catch()等方法,then()第一个参数接收resolved()传来的数据,catch()第一个参数接收rejected()传来的数据。

作用:

  • ① 通常用来解决异步调用问题
  • ② 解决多层回调嵌套的方案
  • ③ 提高代码可读性、更便于维护
let p = new Promise(function(resolve, reject){
    //做一些异步操作
    setTimeout(function(){
        console.log('执行完成Promise');
        resolve('要返回的数据');
    }, 2000);
});
p.then(data => {
    console.log(data);
    console.log('这是成功操作');
});
p.catch(error => {
    console.log(error);
    console.log('这是失败操作');
})

流程如下:

二 、Promise几种常用方法

1.Promise.all()

将多个Promise封装成一个新的Promise,成功时返回的是一个结果数组,失败时,返回的是最先rejected状态的值。

使用场景:一次发送多个请求并根据请求顺序获取和使用数据

// Promise.all调用
Promise.all([
    Promise.resolve("直接返回成功"),
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve({
                message: "第一个请求结果",
            })
        },1000)
    }), 
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve({
                message: "第二个请求结果",
            })
        },1000)
    }),

]).then(results => {
    // 三个promise都是成功的,所以会输出一个数组
    console.log("调用结果数组results:", results);
    console.log("调用结果一起处理操作...");
}).catch(error => {
    console.log("Promise.all调用错误!!", error);
});

// 上面的也可以拆分写为:
let promise1 = Promise.resolve("直接返回成功");

let promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({
            message: "第一个请求结果",
        });
    }, 1000);
});

let promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({
            message: "第二个请求结果",
        });
    }, 1000);
});
let promise4 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject("直接返回失败1");
    }, 1000);
});
let promise5 = Promise.reject("直接返回失败2");

Promise.all([promise1, promise2, promise3])
.then((results) => {
  //三个promise都是成功的,所以会输出一个数组
    console.log("调用结果数组results:", results);
    console.log("调用结果一起处理操作...");   
}) 

//若是里面有一个失败的,则:直接返回promise4的失败结果
Promise.all([promise1, promise2, promise3, promise4])
.then((results) => {
    console.log(results)  
}).catch((error) => {
  //promise4是失败的,所以只会返回promise4的失败结果
    console.log(error)    //promise4
})

Promise.all([promise1, promise2, promise3, promise4, promise5]).then((results) => {
console.log(results)
}, (error) => {
  //promise4个promise5都是失败的,但是promise5比promise4最先失败,所以返回promise5的失败结果
    console.log(error)    //promise5
})

三、Promise的链式调用

我们可以用 promise.then()promise.catch()promise.finally()这些方法将进一步的操作与一个变为已敲定状态的 promise 关联起来。这些方法还会返回一个新生成的promise 对象,这个对象可以被非强制性的用来做链式调用

// 1,Promise原始链式调用
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("请求结果:", 1);
        resolve(1);
    }, 1000)
}).then(data => {
    console.log("第一次对结果处理");
    return new Promise((resolve, reject) => {
        resolve(data * 2);
    });
}).then(data => {
    console.log("第二次对结果处理");
    return new Promise((resolve, reject) => {
        resolve(data * 3);
    });
}).then(data => {
    console.log("第三次对结果处理");
    data *= 4;
    console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
    console.log("链式调用中某个环节出现错误!!", err);
})

// 2,Promise的链式简化写法
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("请求结果:", 1);
        resolve(1);
    }, 1000)
}).then(data => {
    console.log("第一次对结果处理");
    return Promise.resolve(data * 2);
}).then(data => {
    console.log("第二次对结果处理");
    return Promise.resolve(data * 3);
}).then(data => {
    console.log("第三次对结果处理");
    data *= 4;
    console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
    console.log("链式调用中某个环节出现错误!!", err);
})

// 3,Promise的链式最简化写法
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("请求结果:", 1);
        resolve(1);
    }, 1000)
}).then(data => {
    console.log("第一次对结果处理");
    return data * 2
}).then(data => {
    console.log("第二次对结果处理");
    return data * 3
}).then(data => {
    console.log("第三次对结果处理");
    data *= 4;
    console.log("Promise的链式调用结束,最终结果:", data);
}).catch(err => {
    console.log("链式调用中某个环节出现错误!!", err);
})

四、什么是Async/Await

什么是Async/Await

asyncawaitGenerator函数的语法糖,原理是通过Generator函数加自动执行器来实现的,这就使得
asyncawait跟普通函数一样了,不用再一直next执行了。

他吸收了Generator函数的优点,可以通过await来把函数分状态执行,但是又不用一直next,可以自动执行。

var fs = require('fs');

var readFile = function (fileName){
    return new Promise(function (resolve, reject){
        fs.readFile(fileName, function(error, data){
        if (error) reject(error);
            resolve(data);
        });
    });
};

var gen = function* (){
    var f1 = yield readFile('/usr/web');
    var f2 = yield readFile('/usr/ngnix');
    console.log(f1.toString());
    console.log(f2.toString());
};

写成 async 函数,就是下面这样。

var asyncReadFile = async function (){
    var f1 = await readFile('/usr/web');
    var f2 = await readFile('/usr/ngnix');
    console.log(f1.toString());
    console.log(f2.toString());
};

比较发现,async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await,仅此而已。

参考来源:async 函数的含义和用法

Async/Await的特点

① async/await是ES8新特性
② async/await是写异步代码的新方式,以前的方法有回调函数和Promise
③ async/await是Generator函数的语法糖,原理是通过Generator函数加自动执行器来实现的
④ async/await与Promise一样,是非阻塞的
⑤ async/await使得异步代码看起来像同步代码,这正是它的魔力所在

async 函数一定会返回一个 promise 对象。如果一个 async 函数的返回值看起来不是 promise,那么它将会被隐式地包装在一个 promise 中。

例如:

async function foo() {
   return 1
}
// 等价于:
function foo() {
   return Promise.resolve(1)
}

async 函数的函数体可以被看作是由 0 个或者多个 await 表达式分割开来的。从第一行代码直到(并包括)第一个 await 表达式(如果有的话)都是同步运行的。这样的话,一个不含 await 表达式的 async 函数是会同步运行的。然而,如果函数体内有一个 await 表达式,async 函数就一定会异步执行。

async function foo() {
   await 1
}
// 等价于:
function foo() {
   return Promise.resolve(1).then(() => undefined)
}

参考来源:async 函数

五、Promise和async await区别

Async/await 比 Promise 更优越的表现

1、简洁干净:使用 async/await 能省去写多少行代码

2、错误处理:async/wait 能用相同的结构和好用的经典 try/catch 处理同步和异步错误,错误堆栈能指出包含错误的函数。

3、调试:async/await 的一个极大优势是它更容易调试,使用 async/await 则无需过多箭头函数,并且能像正常的同步调用一样直接跨过 await 调用。

Async/await进一步优化了Promise.then()的缺点,使代码更简洁,所以在项目中尽量使用Async/await


文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录