ES6 Promise详解之缝合红宝书ES6标准入门

去年暑假的时候就学了Promise,最近在学node的时候又遇到了再复习一遍,写个博客缝合一波阮佬的ES6标准入门与红宝书中的内容,用我自己的白话给大家讲一下。

什么是Promise

所谓Promise简单来说就是一个容器,里面保存着未来才会结束的事件(通常是异步操作)的结果。从语法上来说,Promise是一个对象,从它可以获取异步操作的消息

Promise对象的特点

promise是一个有状态的对象(状态机)

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise的基本使用

 新建的Promise就是一个容器,里面可以存放异步操作,也可以存放同步操作

const fs = require("fs");
const path = require("path");

let filePath = path.join(__dirname, "files", "3.txt");

// 异步操作可能成功或者失败
// 第一个形参resolve , 成功的时候执行的函数
// 第二个形参reject , 失败的时候执行的函数
let p1 = new Promise((resolve, reject)=>{
    //1、同步代码
    console.log("同步代码");

    // pending(进行中)、fulfilled(已成功)和rejected(已失败)
    //2、异步代码
    fs.readFile(filePath,"utf-8",(error1, data1)=>{
        if(error1){
            //失败的时候做的事情
            reject(error1);    // 调用后面p1.then的第二个函数
        }
        //读取完之后做的事情
        resolve(data1);    // 调用后面p1.then的第二个函数
    })
});

p1.then((data1)=>{
    console.log("读取成功", data1);
},(error1)=>{
    console.log("读取失败", error1);
});

Promise的基本API

.then()

then方法定义在原型对象Promise,prototype上,它的作用是为Promise实例添加状态改变时的回调函数。then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Reject状态的回调函数。

then方法返回的是一个新的Promise实例(注意!不是原来的那个Promise实例),因此可以采用链式写法,即then方法后再调用另一个then方法。

Promise的then链式调用的特点

链式调用的特点:

  1. 第一个then执行完会执行第二个then
  2. then里面的函数的返回值,会被下一个then的形参接收
  3. 如果返回的是一个promise对象,下一个then的形参接收到的不是这个promise对象,而是这个promise对象内部调用resolve时候的实际参数
const fs = require("fs");
const path = require("path");

let filePath = path.join(__dirname, "files", "3.txt");

// 新建的Promise就是一个容器,里面可以存放异步操作,也可以存放同步操作

// 异步操作可能成功或者失败
// 第一个形参resolve , 成功的时候执行的函数
// 第二个形参reject , 失败的时候执行的函数
let p1 = new Promise((resolve, reject)=>{
    //1、同步代码
    // console.log("同步代码");

    // pending(进行中)、fulfilled(已成功)和rejected(已失败)
    //2、异步代码
    fs.readFile(filePath,"utf-8",(error1, data1)=>{
        if(error1){
            //失败的时候做的事情
            reject(error1)
        }
        //读取完之后做的事情
        resolve("resolve的形参")
    })
});

//业内把promise then的写法被称为开火车开发

p1.then((data1)=>{
    return p1
},(error1)=>{
    console.log("读取失败", error1);
    return error1
}).then((data)=>{
    console.log(data);   // “resolve("resolve的形参")
});

 .catch()

Promise.prototype.catch方法是.then(null,rejection)的别名,用于指定发生错误时的回调函数。

如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中

Promise 对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前两个回调函数的错误
});
//一般,我们会把以下代码:
p1.then((data1)=>{
    console.log("承诺成功", data1);
},(error1)=>{
    console.log("承诺失败", error1);
});

//写成
p1.then((data1)=>{
    console.log("承诺成功", data1);
}).catch((error1)=>{
    console.log("承诺失败", error1);
}).finally(()=>{
    console.log("承诺成功与失败都会执行这里的代码");
});

 .all()

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

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

上面代码中,Promise.all 方法接受一个数组作为参数,p1、p2、p3 都是 Promise 对象的实例。(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。)

p 的状态由 p1、p2、p3 决定,分成两种情况。

  • (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
  • (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.all([p1,p2]).then((data)=>{
    // data是一个数组,分别是p1和p2最后传来的数据
    console.log(data); // [ '我', '爱' ]
    console.log(data.join(""));  // 我爱
}).catch((error)=>{
    //只要执行p1,p2时其中一个报错,就会执行这里的代码
    console.log(error);
});

.race()

Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

var p = Promise.race([p1,p2,p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。

如果Promise.all方法和Promise.race方法的参数,不是Promise实例,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。

const fs = require("fs")
const path = require("path")
const util = require('util');

let filePath1 = path.join(__dirname, "files", "1.txt") 
let filePath2 = path.join(__dirname, "files", "2.txt") 

let readFilePromise = util.promisify(fs.readFile);

let p1 = readFilePromise(filePath1,"utf-8")
let p2 = readFilePromise(filePath2,"utf-8")
Promise.race([p1,p2]).then((data)=>{
    // p1,p2只要其中一个执行完,就会执行一遍这里的代码,且这里的代码只会执行1次
    console.log(123);
    console.log(data);
});

//123
//我

.resolve()

有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用。

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面代码将 jQuery 生成 deferred 对象,转为一个新的 ES6 的 Promise 对象。

如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。

var p = Promise.resolve('Hello');
 
p.then(function (s){
  console.log(s)
});
// Hello

 .reject()

Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。

var p = Promise.reject('出错了');
 
p.then(null, function (s){
  console.log(s)
});
// 出错了

 上面代码生成一个Promise对象的实例,状态为rejected,回调函数会立即执行。

猜你喜欢

转载自blog.csdn.net/nxcniuxiangchen/article/details/121783659
今日推荐