参考原文:http://es6.ruanyifeng.com/#docs/promise
Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise
是一个对象,从它可以获取异步操作的消息。Promise
提供统一的 API,各种异步操作都可以用同样的方法进行处理。
基本用法
ES6 规定,Promise
对象是一个构造函数,用来生成 Promise
实例。
下面代码创造了一个 Promise
实例。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve
和 reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve
函数的作用是,将 Promise
对象的状态从“未完成”变为“成功”(即从 pending
变为 resolved
),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
reject
函数的作用是,将 Promise
对象的状态从“未完成”变为“失败”(即从 pending
变为 rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise
实例生成以后,可以用 then
方法分别指定 resolved
状态和 rejected
状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then
方法可以接受两个回调函数作为参数。第一个回调函数是 Promise
对象的状态变为 resolved
时调用。
第二个回调函数是 Promise
对象的状态变为 rejected
时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受 Promise
对象传出的值作为参数。
参考例子
下面是一个 Promise
对象的简单例子。
function timeout(ms) {
const promise = new Promise((resolve, reject) => {
setTimeout(resolve('done'), ms);
});
return promise;
}
timeout(100).then((value) => {
console.log(value);
});
// done
上面代码中,timeout
方法返回一个 Promise
实例,表示一段时间以后才会发生的结果。
过了指定的时间(ms
参数)以后,resolve
函数被执行;Promise
实例的状态变为 resolved
,就会触发 then
方法绑定的回调函数。
第二个例子:
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved
上面代码中,Promise
新建后立即执行,所以首先输出的是 Promise
。然后,then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以 resolved
最后输出。
第三个例子是一个用 Promise
对象实现的 Ajax 操作的例子。
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
上面代码中,getJSON
是对 XMLHttpRequest
对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个 Promise
对象。需要注意的是,在 getJSON
内部,resolve
函数和 reject
函数调用时,都带有参数。
如果调用 resolve
函数和 reject
函数时带有参数,那么它们的参数会被传递给回调函数。
reject
函数的参数通常是 Error
对象的实例,表示抛出的错误;resolve
函数的参数一般是获取到的正常的值。
链式 then
then
方法返回的是一个新的 Promise
实例(注意,不是原来那个 Promise
实例)。因此可以采用链式写法,即 then
方法后面再调用另一个 then
方法。
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上面的代码使用 then
方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果(也就是 retuen
的内容)作为参数,传入第二个回调函数。
下面是一个用链式 then
连续读取 A,B 两个文件的示例:
const fs = require('fs');
const readFile = (fileName) => {
return new Promise((resolve, reject) => {
fs.readFile(fileName, (error, data) => {
if (error) return reject(error);
resolve(data);
});
});
};
// 第一个 then 的 data 参数来自 readFile 的 resolve(data)
// 把 data 字符串化之后打印出来
readFile('./test-A.txt')
.then((data) => {
console.log(data.toString());
})
// 第二个 then 再执行一遍 readFile,但文件名换成了 B 文件
// return 出来的数据来自 readFile 的 resolve(data)
.then(() => {
const data = readFile('./test-B.txt');
return data;
})
// 第三个 then 的 data 来自第二个 then 的 return 值
.then((data) => {
console.log(data.toString());
})
网友评论