Promise 用法

2019-04-11
JavaScript
3196

什么是Promise

Promise 是异步编程的一种解决方案。是一个容器,里面保存着未来将会发生的事

Promise 用法

Promise内部有三种状态pendingfulfilledrejected

状态只能从pending装换到fulfilled或者到rejected,

一旦转化就不可逆转,fulfilled和rejected不能相互转化,

构造函数接收一个函数作为参数,函数立即执行,函数接收两个参数,resolve()和reject(),它们都是函数,在promise函数内部定义

console.log('Hi');

new Promise(((resolve, reject) => {
    console.log('I am promise');
}));

console.log('end');
// Hi -> end -> I am promise

异步操作在参数函数中执行,如果成功,执行resolve([reason]),状态变为fulfilled状态,

如果失败执行reject([error]),状态变为rejected状态。

resolve和reject都是微任务,在本轮任务末尾执行,总是晚于本轮循环的同步任务

setTimeout(function(val) {
    console.log(val)
}, 0, 2);

let promise = new Promise(function(resolve, reject) {
    resolve();
    console.log('Promise');
});

promise.then(function() {
    console.log('resolved.');
});

console.log('Hi!');

// Promise -> Hi! -> resolved. -> 2

解析

setTimeout 为异步任务,需要等待主线程、微任务、dom操作执行完才能执行

Promise 的第一个参数立即执行,见上文,(这里是主线程)resolve(),先执行,触发微任务,需 等待主线程执行完,console.log('Promise');作为主线程第一个打印的内容,

console.log('Hi!'); 位于主线程,第二个执行。

之后主线程完,执行微任务promise.then,打印console.log('resolved.');

微任务完之后执行异步任务setTimeout, console.log(val)

Promise 实例有个then方法,用来处理promise的返回,接收两个参数

第一个参数onFulfilled(),在promise状态变为fulfilled时调用。

第二个参数onRejected() 可选,在promise状态变为rejected时调用。

then方法会返回一个Promise对象,实现链式调用

new Promise(((resolve, reject) => {
    resolve(2);
})).then(val => {
    console.log(val);
}).then()

Promise 实例方法catch,接收一个参数,在promise状态变为rejected时调用

let p = new Promise((resolve, reject) => {
    reject(2)
}).catch(e => {
   console.log(e);
});

Promise.resolve() 快速返回一个fulfilled对象 Promise.reject() 快速返回一个rejected对象

let p = Promise.reject(123);

// console.log(p);
p.then(result => {
  console.log('then', result);
}).catch(result => {
  console.log('catch', result);
});

// catch123

Promise.all() 将多个promise对象包装成一个promise对象

then 方法返回的promise状态怎么判断(划重点)

很多同学在使用promise过程中,基本模式都会,就是then方法接一个then方法的返回值不清楚,下面总结出四点,用于判断then方法的返回状态:

  • 如果内部返回一个基本类型数据或者什么都不返回,状态为fulfilled
  • 只要有错误抛出状态为rejected
  • 如果内部返回一个promise,then返回的状态和这个promise的状态一致
  • 没有执行内部方法,则继承上一个promise的状态

举例说明:

规则1: 如果内部返回一个基本类型数据或者什么都不返回,状态为fulfilled

// demo1
new Promise((resolve, reject) => {
    // resolve 执行之后,状态变为fullfilled
    resolve(2);
}).then(val1 => {
    // 上一个promise返回fullfilled状态,执行此函数打印 val1 -> 2
    console.log(val1);
}, val2 => {
    // 上一个promise返回fullfilled状态, 此函数不执行
    console.log(val2);
}).then(val3 => {
    // 由于上一个then内部只执行 console.log(val1);,没有任何返回,所以,状态为fullfilled,执行此函数,没有返回,val3 为undefined
    console.log(val3);
    return 5;
}, val4 => {
    // 此函数不执行
    console.log(val4);
}).then(val5 => {
    // 由于上一个then内部返回一个普通值5,所以,状态为fullfilled,val5为返回的值5
    console.log(val5);
})

// 所以最终返回 2 -> undefined -> 5

// demo2 在demo1的基础上,第一步reject,看看返回什么
new Promise((resolve, reject) => {
    // resolve 执行之后,状态变为fullfilled
    reject(2);
}).then(val1 => {
    // 上一个promise执行reject,状态变为rejected,此函数不执行
    console.log(val1);
}, val2 => {
    // 上一个promise执行reject,状态变为rejected,此函数执行,打印val2 -> 2
    console.log(val2);
    return 3;
}).then(val3 => {
    // 由于上一个then内部return 2;在reject函数内部,和resolve函数内部同等对待,没有返回值,或者返回普通值,状态统一为fullfilled,val3 为 3
    console.log(val3);
    return 5;
}, val4 => {
    // 解析见上,这个rejecte函数就不执行le
    console.log(val4);
}).then(val5 => {
    // 由于上一个then内部返回一个普通值5,所以,状态为fullfilled,val5为返回的值5
    console.log(val5);
})

// 最后这个返回是 2 -> 3  -> 5

规则2: 只要有错误抛出状态为rejected

// 这个比较好理解在then的reject 或者 resolve 方法中,不论谁throw error,状态都变为rejected

Promise.resolve(2).then(val1 => {
    console.log(val1);
    throw Error('this is a error')
    return 4;
}).then(val3 => {
    // 根据规则2,前一个then函数内部,先throw Error,所以状态变为reject,此函数不执行
    console.log(val3);
}, val4 => {
    // 此函数执行,打印error
    console.log(val4.message);
}).then(val5 => {
    // 这里有回到了规则1,前一个then函数,没有返回任何值,状态为fullfiled,此函数执行
    console.log('val5 ' + val5)
})

// 最后打印 2 -> this is a error -> val5 undefined

规则3: 如果内部返回一个promise,then返回的状态和这个promise的状态一致

Promise.resolve(1).then(val1 => {
    console.log('val1 ' + val1);
    return Promise.reject(3);
}).then(val2 => {
    // 前一个then,返回一个promise,状态根据此promise定,返回的promise为rejected,此函数不执行
    console.log('val2', val2);
}, val3 => {
    // 此函数执行 
    console.log('val3 ' + val3);
})

// 打印 val1 1 -> val3 3

规则4: 没有执行内部方法,则继承上一个promise的状态

Promise.resolve(1).then().then(val2 => {
    // 上一个then为空,我们看它上一个promise的状态,发现为resolve,此函数执行
    console.log('val2', val2);
}, val3 => {
    console.log('val3 ' + val3);
})

// 打印 val2 1

建议

尽量不在then方法写rjected方法,而是在最后写catch方法,then的Rejected方法不能捕获自身Fulfilled中的错误

都不写Rjected 方法,错误就能传递到catch方法中

多用then方法

在使用promise过程中,需要理清楚各个环节的状态

Promise 缺点

Then 方法会纵向拉长代码