Promise是啥?

promise是什么?

Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
——阮一峰es6教程

本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,它代表了一个异步操作的最终完成或者失败。

  • 语法上Promise()是一个构造函数
  • 从功能上来说:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

promise的作用

支持链式操作,解决回调地狱,让异步代码按照顺序执行

回调地狱是什么?

回调函数嵌套调用(外部回调函数异步执行的结果是嵌套的回调执行的条件)


回调地狱

总结为八个字就是:异步回调,层层嵌套

Promise的三种状态

Promise对象有三种状态

  • pending(进行中)
  • fulfilled(已成功)
  • rejected(已失败)

对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态

promise的状态改变

Promise状态改变只有两种情况

  • 从pending(进行中)变为fulfilled(成功)
  • 从pending(进行中)变为rejected(失败)

一旦状态改变,就不会再变,任何时候都可以得到这个结果

Promise的使用流程

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

  1. 创建promise实例对象
    let p1 = new Promise((resolve,reject)=>{
     //你的异步代码
    if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    })
    /* 
    参数:回调函数  (resolve,reject)=>{  //你想要的异步操作 }
        resolve : 完成回调
        reject  : 回调失败 
    */
    

resolve函数的作用是,将Promise对象的状态从从 pending变为 resolved(成功),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去

reject函数的作用是,将Promise对象的状态从 pending 变为 rejected(失败),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

  1. 调用实例对象的then方法
    p1.then(function(value) {
      // success
    }, function(error) {
      // failure
    })
    

then方法可以接受两个回调函数作为参数。
第一个回调函数是Promise对象的状态变为resolved(成功)时调用,第二个回调函数是Promise对象的状态变为rejected(失败)时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

举个例子

const fs = require('fs');
//(1)调用Promise构造函数,生成promise实例对象
let p =  new Promise( (resolve,reject)=>{
    //异步操作: 读取文件a
    fs.readFile(`a.txt`, 'utf8', (err, data) => {
        if(!err){//成功
            /* 
            (1)resolve:执行then方法里面的第一个函数
            */
           resolve(data);
        }else{//失败
            /* 
            (1)reject:执行then方法里面的第二个函数
            */
           reject(err);
        }
    });
} );

//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p.then(data=>{
    console.log(data);
},err=>{
    console.log(err);
});

注意 : Promise对象在创建的时候,里面的异步就会立即执行
不要在创建promise的时候处理异步结果,应该调用resolve()或者reject()交给then()方法来处理

解决回调地狱

我们来看一个读取文本内容的例子。
首先创建四个内容不同的文本a、b、c、d,然后创建Promise实例对象,调用then方法,解决回调地狱

const fs = require('fs');
//Promise是一个构造函数,用于创建promise实例
//(1)调用Promise构造函数,生成promise实例对象
/* 
参数:回调函数  (resolve,reject)=>{  //你想要的异步操作 }
    resolve : 完成回调
    reject  : 失败回调 
*/
let p1 = new Promise((resolve, reject) => {
    //异步操作: 读取文件a
    fs.readFile(`a.txt`, 'utf8', (err, data) => {
        if (!err) {//成功
            /* 
            (1)resolve:执行then方法里面的第一个函数
            (2)resolve底层原理:修改promise状态从pending(进行中)变为fulfilled(成功)
            */
            resolve(data);
        } else {//失败
            /* 
            (1)reject:执行then方法里面的第二个函数
            (2)rreject底层原理:修改promise状态从pending(进行中)变为rejected(失败)
            */
            reject(err);
        }
    });
});
let p2 = new Promise((resolve, reject) => {
    //异步操作: 读取文件a
    fs.readFile(`b.txt`, 'utf8', (err, data) => {
        if (!err) {//成功
            resolve(data);

        } else {//失败
            reject(err);
        }
    });
});
let p3 = new Promise((resolve, reject) => {
    //异步操作: 读取文件a
    fs.readFile(`${__dirname}/data/c.txt`, 'utf8', (err, data) => {
        if (!err) {//成功
            resolve(data);

        } else {//失败
            reject(err);
        }
    });
});
let p4 = new Promise((resolve, reject) => {
    //异步操作: 读取文件a
    fs.readFile(`d.txt`, 'utf8', (err, data) => {
        if (!err) {//成功
            resolve(data);

        } else {//失败
            reject(err);
        }
    });
});
//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p1.then(data=>{
    console.log(data);
    return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
    console.log(data);
    return p3;
})
.then(data=>{//p3的then
    console.log(data);
    return p4; 
})
.then(data=>{//p4的then
    console.log(data);
});
// p1.then(data => {
//     console.log(data);
//     p2.then(data => {
//         console.log(data);
//         p3.then(data => {
//             console.log(data);
//             p4.then(data => {
//                 console.log(data);
//             });
//         });
//     });
// });

promise解决回调地狱 : 在上一个promisethen方法中返回下一个promise实例对象
总结promise本质不是修改异步的顺序(异步永远是无序的),而是通过控制异步结果的顺序,从而实现异步代码有序执行。

Promise解决回调地狱函数封装

以上的代码看起来有些冗余,我们可以通过函数封装的方式使代码变得精简。

const fs = require('fs');
//Promise是一个构造函数,用于创建promise实例
//封装一个创建promise的函数
function createPromise(filename){
    return new Promise((resolve,reject)=>{
        fs.readFile(`${filename}.txt`, 'utf8', (err, data) => {
            if (!err) {//成功
                resolve(data);
    
            } else {//失败
                reject(err);
            }
        });
    });
};
let p1 = createPromise('a');
let p2 = createPromise('b');
let p3 = createPromise('c');
let p4 = createPromise('d');
//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p1.then(data=>{
    console.log(data);
    return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
    console.log(data);
    return p3;
})
.then(data=>{//p3的then
    console.log(data);
    return p4; 
})
.then(data=>{//p4的then
    console.log(data);
});

Promise中的其他方法

catch() : 用于统一处理错误信息。catch上面所有的promise任何一个出错就会进入catch

all() : 将多个promise对象放入数组中合并成一个promise,要等所有的promise全部执行完毕才会执行then() : 逻辑与

race():将多个promise对象放入数组中合并成一个promise,任何一个promise执行完毕就会执行且其他的promise停止执行then(): 逻辑或

Promise.prototype.catch()

还是以上面例子的代码为例

p1.then(data=>{
    console.log(data);
    return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
    console.log(data);
    return p3;
})
.then(data=>{//p3的then
    console.log(data);
    return p4; 
})
.then(data=>{//p4的then
    console.log(data);
})
.catch(err=>{
    //统一处理出错信息:上面所有的promise,任何一个出现错误都会进入这个方法
    console.log(err);
    
});

Promise.all()

语法:

const p = Promise.all([p1, p2, p3]);

还是以上面获取文本的代码为例,使用all方法

//Promise.all([p1,p2,p3,p4]) : 多个promise合成一个
let pAll = Promise.all([p1,p2,p3,p4]);

//(2)调用promise实例的then方法

pAll.then(data=>{
    //执行时机: pAll中 所有 promise完成才执行then
    //data是一个数组,依次存储每一个promise的结果
    console.log(data);
    
});

Promise.race()

语法:

const p = Promise.race([p1, p2, p3]);
// race():将多个promise对象合并为一个promise,只要有任何一个promise完成就会执行then,且其他promise停止执行
let pAll = Promise.race([p1,p2,p3,p4]);

//(2)调用promise实例的then方法

pAll.then(data=>{
    //执行时机: pAll中 任何一个 promise完成就会执行then
    //data : 第一个执行完毕的promise的结果
    console.log(data);
    
});

async函数

async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。asyncawait关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise
async函数还可以被作为表达式来定义。
————来自mdn中async函数

async的好处是在不阻塞主线程的情况下使用同步代码异步访问资源的能力,
也就是同步代码,异步执行
作用:
将异步的代码以同步的方式进行书写

用法:

  • async 用来修饰异步代码所在的函数
  • await 用来修饰异步代码
  • 使用 await 修饰后的异步代码可以同步的方式来接收返回结果
async function name([param[, param[, ... param]]]) {
    statements 
}

参数

name
函数名称。
param
要传递给函数的参数的名称。
statements
包含函数主体的表达式。可以使用await机制。

返回值

一个Promise,这个promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝。

注意点:

  • await 修饰的异步函数必须返回一个 promise 对象

  • async & await 修改的代码依旧是异步代码,只是写法变成为了同步

try...catch

作用:捕获代码的异常

 try {
            可能报错的代码
 }catch(error){
            (error)不想要错误信息时,(error)带括号一起删除
            error就是报的错误
            如果try里面代码报错了,这里的catch就会执行
            如果try里面代码没报错了,这里的catch就不会执行
}

例子:

async function getData() {
        try {
          const res = await axios({
            url: "http://localhost:1337/au/code123",
            method: "post",
            data: {
              mobile: "13695956584",
            },
          });
          //   .then((res) => {
          window.console.log(res);
          //   })
        } catch (error) {
          //   .catch((error) => {
          window.console.log(error);
          alert("出错了");
          //   });
        }
        window.console.log(123);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271