此篇讲解Promise的使用 介绍promise常用方法
begin enjoy👇

Promise由来

  • 在大前端或者全栈开发中,无论是前端还是后端,异步行为总是伴随着开发者
  • 前端常见的异步场景有:Ajax请求、注册事件、setTimeout
  • 服务端node中是更为典型的异步场景,绝大多数操作都是以异步线程来完成的,例如文件系统操作、数据库等
  • 通常在异步编程中使用回调函数来监听异步行为的结果,这样会产生一个问题:代码的编写和维护困难

更多的时候,开发者希望能以同步化代码的方式处理异步的业务场景,类似于:

        const xhr = new XMLHttpRequest;
        let result;

        xhr.open("get", "localhost", true);
        xhr.send(null);

        //定义回调函数来接收结果
        xhr.onloadend = function () {
            if (this.status == 200) {
                result = this.response;
            }
        }

其后使用ajax响应的数据 渲染界面 设置样式 填充容器

但是这种做法在异步场景中是不合法的,

  1. 回调函数需要在请求之前设置
  2. 所有ajax响应之后的处理 都必须在回调函数中设置
//代码应该这么改变:
const xhr = new XMLHttpRequest;
let result;

//回调函数要先定义后使用,
//当请求完成ajax会调用该函数
xhr.onloadend = function () {
    if (this.status == 200) {
        result = this.response;
        /*
        * ajax之后的处理必须写在回调函数内,代码不但多,
          而且犬牙交错,给代码的编写和维护带来困难
        */ 
        
        //渲染界面 产生了input#btn
        //设置样式
        //填充容器

        //绑定事件,设置效果
        //....
        btn.addEventListener("click", function() {
            //....
        })
    }
}
xhr.open("get", "localhost", true);
xhr.send(null);

Promise起步

es6中增加了Promise的构造函数 用来封装一个异步的业务实现, Promise构造函数 接收一个函数参数,该函数用来写入异步的业务

const pms = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest;
    xhr.onloadend = function () {
        if (this.status == 200) {//成功
            //返回一个结果
            resolve(this.responseText);
        } else {//失败
            //拒绝的原因
            reject(this.statusText); // 404 NOT FOUND
        }
    }
    xhr.open("get", "http://localhost/");
    xhr.send(null);
});

//使用then方法写入回调函数,也就是将来要执行的部分
//整个代码是平行、自上而下的运行
pms.then((value) => {
    console.log(value);
}, (reason) => {
    console.log(reason);
});

Promise是承诺,信守承诺 约定了结果 一定不会改变 Promise初始化时的状态的是 pending 一旦决议成功,状态由pending->fulfilled,并且产生一个值 一旦决议失败,状态由pending->rejected,伴随一个拒绝原因 无论是成功还是失败,它只有一个结果,决议一次

const p = new Promise((resolve, reject) => {
    
    //决议失败
    reject("NOT FOUND");

    //决议成功
    resolve("hello world");
    
});
//在控制台打印Promise对象,可以通过其内部属性<state>查看Promise的状态
console.log(p);
  • then方法写入将来要执行代码,也就是回调函数
  • 它接收两个参数,分别是成功时的处理以及失败时的处理
  • 如果只传入第一个参数 则表示只设置状态为fulfilled的处理
const p1 = new Promise((resolve, reject) => {
    resolve("hello world");
});
p1.then((value) => {
    console.log(value); //hello world
});

//如果只想设置状态为rejected的处理,需要将fulfilled设为null
const p2 = new Promise((resolve, reject) => {
    reject("NOT FOUND");
});

// p2.then(null, (reason) => {
//     console.log(reason);    //NOT FOUND
// });

//如果只捕获rejected状态,可以使用catch方法
p2.catch((reason) => {
    console.log(reason);
});

Promise链式操作

then和catch方法 返回值是一个新的Promise对象 上一个Promise决议的返回值作为新的Promise状态,返回值有三种情况:

  • 返回的是一个值,例如 "hello world", 123, false等,,那么新的Promise的状态是fulfilled
  • 如果上一个Promise扔出一个错误:throw new Error(),新的Promise的状态是rejected
  • 如果上一个Promise返回的是一个Promise对象,返回的Promise的决议作为新的Promise的状态
const p1 = new Promise((resolve, reject) => {
    // resolve("Ok");
    reject("ERR"); //实际业务中 当拒绝时一般都会产生Error
});

const p2 = p1.then((value) => {
    console.log(value);
}, (reason)=> {
    console.log(reason); //ERR
    //如果返回一个值 新的Promise状态就是fulfilled且接收该值
    // return "hello world";
    // return false;  
    //如果扔出一个错误 新的Promise的状态就是 rejected且接收错误对象 
    // throw new Error("NOT FOUND");
    //如果返回一个Promise对象,该Promise的决议作为新的Promise的状态
    return p1;
});

p2.then((value) => {
    console.log(value); //false
}, (reason) => {
    console.log(reason);//Error('NOT FOUND')
});

Promise静态方法

race方法

const pms1 = Promise.resolve(1),
    pms2 = new Promise((resolve) => {
        setTimeout(() => {
            resolve(2);
        }, 100);
    }),
    pms3 = 3,
    pms4 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(4);
        }, 10);
    });

//race()方法接收一组值,等待第一个 完成或者拒绝的Promise 再决议
Promise.race([pms1, pms3]).then((value) => {
    //pms1先完成
    console.log(value); //1
}, (reason) => {
    console.log(reason);
});

Promise.race([pms2, pms4]).then((value) => {

    console.log(value);
}, (reason) => {
    //pm4先拒绝
    console.log(reason); //4
});

all方法

all()也接收一组值,只有当所有的值都完成,其结果才是完成的fulfilled, 如果有一个被拒绝,那么结果就拒绝

Promise.all([pms1, pms2, pms3]).then((value) => {
    console.log(value); //(3) [1, 2, 3]
}, () => {

});

Promise.all([pms1, pms2, pms3, pms4]).then((value) => {

}, (reason) => {
    console.log(reason); //4
});

Promise封装ajax

function ajax(url, data = null) {
    //使用Promise来封装Ajax操作
    const pms = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest;
        xhr.onloadend = function () {
            if (this.status == 200) {
                resolve(this.responseText);
            } else {
                reject(this.status);
            }
        }
        xhr.open("get", url + "?" + data);
        xhr.send(null);
    });

    return pms;
}
ajax("http://localhost").then((result) => {
    console.log(result);
});

posted @ Zycin (非转载 来自个人学习资料整理)