ES6 Promise 的基本用法

标语

平时积累的零碎的知识,要达到灵活应用的程度,还需要将其系统化。

promise支持

什么是 Promise

Promise 是抽象异步处理对象及对齐做各种操作的组件。

getAsync("fileA.txt", function(error, result){
    if(error){// 取得失败时的处理
        throw error;
    }
    // 取得成功时的处理
});

Node.js 在处理异步时,回调函数中的第一个参数一定是 error ,但是怎么操作 error 并没有规范。

var promise = getAsyncPromise("fileA.txt"); 
promise.then(function(result){
    // 获取文件内容成功时的处理
}).catch(function(error){
    // 获取文件内容失败时的处理
});

Promise 对于异步处理操作和处理规则做了统一的规范,这使得我们在使用 promise 进行异步处理的时候,必须按照接口规定的方法编写处理代码。所以,基于 Promise 统一接口的做法,就可以形成基于接口的各式各样的异步处理模式,将复杂的异步处理轻松地进行模块化。

Promise 实例

Constructor

Promise 类似于 XMLHttpRequest ,从构造函数 Promise 来创建一个 promise 对象作为接口,使用 new 来实例化一个 promise 对象。

var promise = new Promise((resolve, reject) => {});

实例方法

通过 new 生成的对象为了设置其值在 resolve (成功)/ reject (失败)时调用的回调函数,可以使用 promise.then 实例方法。

resolve

onFullFilled 时会被调用。

reject

onRejected 时会被调用。

静态方法

Promise 进行操作的一些辅助方法。

Thenable

类Promise 对象。 拥有名为 .then 方法的对象。

Promise.resolve 方法可以将 thenable 对象转换为 promise 对象。

var thenable = {
	then: function(resolve, reject) {
		resolve(1);
	}
};
Promise.resolve(thenable);
Promise.resolve
  • new Promise() 的快捷方式,将现有对象转换为 Promise 对象;
  • 如果参数是 promise 实例,则直接返回这个实例
  • 如果参数是 thenable 对象,则将其转换为 promise 对象,并对应里面的 then 方法;
  • 如果参数是个原始值,则返回一个 promise 对象,状态为 resolved ,这个值会传递给 then 方法;
  • 没有参数,直接返回一个状态为 resolvedPromise 对象。
var promise = Promise.resolve(1);

这里可以认为是以下代码的语法糖:

var promise = new Promise(resolve => resolve(1));
Promise.reject
  • new Promise() 的快捷方式,将现有对象转换为 Promise 对象;
  • 如果参数是 promise 实例,则直接返回这个实例
  • 如果参数是 thenable 对象,则将其转换为 promise 对象,并对应里面的 then 方法;
  • 如果参数是个原始值,则返回一个 promise 对象,状态为 rejected ,这个值会传递给 then 方法;
  • 没有参数,直接返回一个状态为 rejectedPromise 对象。
Promise.reject(new Error("出错了"))

这里可以认为是以下代码的语法糖:

var promise = new Promise((resolve, reject) => {
	reject(new Error("出错了"));
});
Promise.all
  • 接收一个 Promise 实例数组,或具 Iterator 接口的对象;
  • 如果元素不是 Promise 对象,就用 Promise.resolve 转换为 Promise 对象;
  • 如果全部成功,状态变为 resolved ,返回值将组成一个数组传给回调;
  • 只要有一个失败,状态变为 rejected ,返回值将直接传给回调;
  • all() 的返回值是一个新的 Promise 对象。
var promises = [
	new Promise(resolve => resolve(1)),
	new Promise(resolve => resolve(2)),
	new Promise(resolve => resolve(3))
];
Promise.all(promises).then(res => console.log(res));
// [1, 2, 3]
Promise.race
  • 接收一个 Promise 实例数组,或具 Iterator 接口的对象;
  • 如果元素不是 Promise 对象,就用 Promise.resolve 转换为 Promise 对象;
  • 只要其中有一个 Promise 实例状态发生变化(不论 resolved 还是 rejected),将会触发 then 方法,返回值将传给回调;
  • race() 的返回值是一个新的 Promise 对象。
var promises = [
	new Promise(resolve => resolve(1)),
	new Promise((resolve, reject) => reject(new Error("出错了!"))),
	new Promise(resolve => resolve(3))
];
Promise.race(promises).then(res => console.log(res));
// 1

Promise 的状态

  • “has-resolution” - FullFilled
  • “has-rejection” - OnRejected
  • “unresolved” - Pending (初始化状态)

Promise 只能进行异步操作

为了避免同时使用同步、异步调用可能造成的混乱([详情](http://liubin.org/promises-book/#promise-is-always-async), Promise 在规范上规定只能使用异步调用方式。

Promise # then 方法

then 方法是 onFullFilled 的回调。

Promise chain

promise 可以进行链式调用。

function taskA() {
    console.log("Task A");
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: A or B", error);
}
function finalTask() {
    console.log("Final Task");
}

var promise = Promise.resolve();
promise
    .then(taskA)
    .then(taskB)
    .catch(onRejected)
	.then(finalTask);
// Task A
// Task B
// Final Task

promise-chian

链式调用也可以传递参数。

new Promise(resolve => resolve(1)).
	then(res => res + 1)
	.then(res => res + 1)
	.then(res => {console.log(res)})
	.catch(err => console.error(err));
// 3

Promise # catch

catch 方法是 onRejected 的回调。catch 是 promise.then(undefined, onRejected); 方法的一个别名,如果在 then 方法中存在 onRejected 函数,后面的 catch 方法不生效。

new Promise((jresolve, reject) =>{
    reject(new Error("error"));
}).then(() => {}, err => {
    console.log(err)
}).catch(err => {
	console.error(err);
})
// Error: error
//     at <anonymous>:2:12
//     at new Promise (<anonymous>)
//     at <anonymous>:1:1

then 和 catch 返回值

每次调用 then 和 catch 方法都会返回一个新创建的 promise 对象。

从代码上看, aPromise.then().catch() 像是针对最初的 aPromise 对象进行了一连串的方法调用,然而实际上不管是 then 还是 catch 方法调用,都返回了一个新的 promise 对象。

var aPromise = new Promise(function (resolve) {
    resolve(100);
});
var thenPromise = aPromise.then(function (value) {
    console.log(value);
});
var catchPromise = thenPromise.catch(function (error) {
    console.error(error);
});
console.log(aPromise !== thenPromise); // => true
console.log(thenPromise !== catchPromise);// => true

=== 是严格相等,所以可以判断上述三个对象都不相同,证明 then 和 catch 都返回了和调用者不同的 promise 对象。

所以,在函数调用时要注意调用的 promise 对象,否则会出现断链。

错误用法:

function asyncFunc () {
	return Promise.resolve(1);
}
function badAsyncCall () {
	var promise = asyncFunc();
	promise.then(res => {
		return 2;
	});
	return promise;
}
badAsyncCall().then(res => console.log(res)).catch(err => console.log(err));
// 1

badAsyncCall 方法返回的是 asyncFunc 方法中创建的对象, catch 捕获错误也是针对 asyncFunc 方法中创建的对象,中间出现了断链。

正确用法:

function asyncFunc () {
	return Promise.resolve(1);
}
function anAsyncCall () {
	var promise = asyncFunc();
	return promise.then(res => {
		return 2;
	});
}
anAsyncCall().then(res => console.log(res)).catch(err => console.log(err));
// 2

then or catch?

then 里面使用指定错误处理函数,和使用 catch 相比有什么异同呢?

不能进行错误处理的 onRejected

function throwError (value) {
	throw new Error(value);
}
// <1> onRejected不会被调用
function badMain (onRejected) {
	return Promise.resolve(1).then(throwError, onRejected);
}
// <2> 有异常发生时onRejected会被调用
function goodMain (onRejected) {
	return Promise.resolve(1).then(throwError).catch(onRejected);
}
badMain(function () {
	console.log("bad!");
}); // 1 报错
goodMain(function () {
	console.log("good");
}); // good

badMain 方法中, .then 的第二个参数中指定了用来处理错误的函数,并不能捕获第一个参数 onFullFilled 指定的函数里面出现的错误。goodMain 方法中遵循了 throwError->onRejected 的流程,这时候 throwError 中出现错误的时候, catch 能够捕捉到错误。

.then 方法中指定的 onRejected 函数所指定的回调函数,实际上针对的是其 promise 对象或之前的 promise 对象,而不是 .then 方法中指定的第一个参数( onFullFilled 所指定的对象),这就是 .thencatch 不同的原因。

总结

  • 使用 .then(onFullFilled, onRejected) ,在 onFullFilled 中发生异常的话,onRejected 捕获不到;
  • 使用 .then(onFullFilled).catch(onRejected) ,在 onFullFilled 中发生异常,onRejected 可以捕获到;
  • .then.catch 在本质上是没有区别的,只是需要分场合使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值