Promise
promises是为了解决异步编程中回调函数存在的一些问题而产生的,它不是用了取代回调函数的,而是使得回调函数更加的好用。Node.js使得异步编程更加的流行,promise的用处也得到了很好的体现。
- 基本语法;
- Promise状态和Promise静态方法
Promise.resolve()
,Promise.reject()
;
- 异常处理,通过事件的方式;
- 另外2个静态方法:
Promise.all()
,Promise.race()
一.基本语法
1.异步编程的几种模式
我们知道javascript是单线程的,所有要执行的代码都放在队列中,称之为job queue.
一般js异步模式可以分为: callback模式, promise模式, generator模式
2.什么是promise
promise可以称为future,是一个异步操作的占位符,首先它是一个对象。它有2种状态状态:
-
unsettled状态: 表示异步操作还未完成,内部属性[[PromiseState]]设置为
pending
;
-
settled状态: 表示异步操作完成,成功: 内部属性[[PromiseState]]设置为
fulfilled
; 失败:rejected
.
3.then()方法
当promise完成操作之后,可以通过 then()
方法进行操作,then语法:
then(fulfillmentCallback, rejectCallback)
第一个回调表示成功之后执行,第二个回调表示失败后执行,这两个回调只会执行一个,也可以分开写:
then(fulfillmentCallback);
then(null, rejectCallback);
// 等价于
catch(rejectCallback)
4.thenable对象
一个对象拥有一个then()方法,我们称这个对象为 thenable对象, all promises are thenable, but all thenables are not promises
// 返回一个对象,包含一个then方法
function foo(x) {
return {
then: function(resolve, reject) {
setTimeout(resolve, 0, "回掉函数"+x);
return this;
}
};
}
Promise.all([foo(1), foo(2)]).then(function(args) {
console.log(args);
})
// ["回调参数1", "回调参数2"]
二.创建一个promise
1.创建一个 Unsettled Promises, 使用构造器
新的promises通过Promise构造函数创建,此时promise状态为pending
, 这个构造函数接受唯一一个参数: 一个function,我们称之为 executor
(这个executor不是异步的,调用时会立即执行).
而这个executor
包含2个参数: 2个函数 resolve()
, reject()
。当executor成功执行,会调用resolve;当executor执行失败,会调用rejected()
下面以Node.js读取文件为例子:
let fs = requrie("fs");
function readFile(filename) {
return new Promise(function(resolve, reject) {
fs.readFile(filename, {encoding: "utf8"}, function(err, contents) {
// Node.js 的 `error-first`模式
// 失败调用reject
if (err) {
reject(err);
return;
}
// 成功时调用resolve
resolve(contents);
});
});
}
let promise = readFile("a.txt");
promise.then(function(contents) {
console.log(contents);
}).catch(function(err) {
console.log(err.message);
})
2.创建 Settled promises: Promise.resolve(), Promise.reject()
通过构造器我们可以创建 unsettled promises, 我们可以通过静态方法 Promise.resolve()
,Promise.rejected()
创建 settled promises.
-
Promise.resolve(): 接受一个参数,返回一个promise,在
fulfilled
状态 -
Promise.reject(): 接受一个参数,返回一个promise, 在
rejected
状态
1.Promise.resolve():
添加一个fulfillment handler来接受返回的promise中的数据
var promiseResolve = Promise.resolve(42);
promiseResolve.then(function(value) {
console.log(value); // 42
})
如果reject handler添加给这个promise,则这个handler将永远不会调用,因为一但promise状态确定将不会更改,即:
var promiseResolve = Promise.revolve(42);
// 这个handler永远不会执行
promiseRevolve.catch(function(err) {
console.log(err);
});
2.Promise.reject():
添加一个 rejected handler:
var promiseRejected = Promise.reject(42);
promiseRejected.catch(function(value) {
console.log(value); // 42
});
3.thenable对象可以作为参数传入Promise.resolve静态方法中,依据thenable方法中调用的函数
此条在chrome中存在问题,待更正, 可以在Node.js中运行
如果thenable中调用resolve则返回的promise为fulfilled
状态;如果thenable中调用的是reject则返回的promise是rejected
状态:
let thenable1 = {
then: function(resolve, reject) {
resolve(42);
}
};
var p1 = Promise.resolve(thenable1); // "fulfilled"状态
p1.then(function(value) { // 使用fulfillment handler
console.log(value); // 42
});
let thenable2 = {
then: function(resolve, reject) {
reject(43);
}
};
// 注意这个地方也是使用Promise.resolve()
var p2 = Promise.resolve(thenable2); // "rejected"状态
p2.catch(function(value) { // 使用reject handler
console.log(value); // 43
});
三.全局Promise Rejection 处理
promise最有争议的地方就是当一个promise失败但是没有rejection handler处理错误时静默失败。不过浏览器和Node.js都有相应的处理机制,两者大同小异,都是通过事件的方式监听。
- Node.js Rejection Handling
两个事件:
-
unhandledRejection
:当promise失败(rejected),但又没有处理时触发,event handler 有2个参数:reason
,promise
;
-
rejectionHandled
: 当promise失败(rejected),被处理时触发,hanler 有1个参数:promise
;
let rejected;
process.on("unhandledRejection", function(reason, promise) {
console.log(reason.message); // "boom"
console.log(rejected === promise); // true
});
rejected = Promise.reject(new Error("boom")); // 出现reject, 没有catch处理
处理:
let rejected;
process.on("rejectionHandled", function(promise) {
console.log(rejected === promise); // true
});
rejected = Promise.reject(new Error("boom"));
// 等待添加rejection handler
setTimeout(function() {
rejected.catch(function(value) { // 处理rejection
console.log(value.message); // "boom"
});
}, 1000);
将可能出现的rejection存储在map中,然后检查是否存在相应的handler:
let rejections = new Map();
// 当一个rejection出现,添加到map中
process.on("unhandledRejection", function(reason, promise) {
rejections.set(promise, reason);
});
// 存在handler,则将其从map集合中删除
process.on("rejectionHanled", function(promise) {
rejections.delete(promise);
});
// 间隔一段时间对集合中的查看处理,清空
setInterval(function() {
rejections.forEach(function(reason, promise) {
console.log(reason.message ? reason.message : reason);
// 用某种方法处理这些rejections
handleRejection(promise, reason);
});
// 清空集合
rejections.clear();
}, 60000);
2.浏览器rejection处理
浏览器和Node.js处理大同小异,通过事件:
-
unhandledRejection
rejectionhandled
这2个事件的 event
对象都包含3个属性: type
, promise
, reason
(这点和Node.js不同)
处理方式:
var rejections = new Map();
window.onunhandledrejection = function(event) {
rejections.set(event.promise, event.reason);
}
window.onrejectionhandled = function(event) {
rejections.delete(event.promise);
}
setInterval(function() {
rejections.forEach(function(event) {
console.log(event.reason.message ? event.reason.message : event.reason);
// 处理
handleRejection(event.promise, event.reason);
});
rejections.clear();
}, 60000);
四.Promise.all() Promise.race()
1.Promise.all()
这个静态方法接受一个可迭代的promises(比如数组),当数组中的每个promise都为fulfilled状态时,返回一个promise.当失败时,立马结束而不等待其他promise完成
let p1 = new Promise((resolve, reject) => {resolve(42)});
let p2 = new Promise((resolve, reject) => {resolve(43)});
let p3 = new Promise((resolve, reject) => {resolve(44)});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
console.log(Array.isArray(value)); // true value为一个数组
console.log(value[0]); // 42
console.log(value[1]); // 43
console.log(value[2]); // 44
});
其中也promise 状态为rejected:
let p1 = new Promise((resolve, reject) => {resolve(42)});
let p2 = new Promise((resolve, reject) => {reject(43)}); // reject
let p3 = new Promise((resolve, reject) => {resolve(44)});
let p4 = Promise.all([p1, p2, p3]);
p4.catch(function(value) {
console.log(Array.isArray(value)); // false
console.log(value); // 43
})
当有promise被rejected的时候,value永远为单个值,而不是一个数组
2.Promise.race()
返回一个合适的promise,只要数组中任何promise先完成了。如果先fulfilled,则返回的promise为fulfilled状态; 如果一个promise 先 reject,则返回的promise为 rejected状态。
let p1 = new Promise((resolve, reject) => resolve(42));
let p2 = Promise.reject(43); // 直接为rejected状态
let p3 = new Promise((resolve, reject) => resolve(44));
let p4 = Promise.race(function(value) {
console.log(value); // 43
});
总结
上面讲到的都是一些关于promise的基本概念,而没有深入的研究,比说promise chaining, promise如何处理异步任务等等,均未涉及,这些内容还需要我以后更深入的学习总结,今天到此为止,推荐一篇讲解比较的文章。
2016/9/21 17:47:43