资料链接: http://liubin.org/promises-book/#what-is-promise
1.什么是promise
promise 是抽象异步处理对象以及对其进行各种操作的组件。
2.表现的形式是什么样子的?
回调函数:getAsync("fileA.txt", function(error, result){ if(error){// 取得失败时的处理 throw error; } // 取得成功时的处理 });
使用promise进行异步处理:var promise = getAsyncPromise("fileA.txt"); promise.then(function(result){ // 获取文件内容成功时的处理 }).catch(function(error){ // 获取文件内容失败时的处理 });
与异步回调函数相比较:在使用promise进行一步处理的时候,我们必须按照接口规定的方法编写处理代码。也就是说,除promise对象规定的方法(这里的 then 或 catch)以外的方法都是不可以使用的, 而不会像回调函数方式那样可以自己自由的定义回调函数的参数,而必须严格遵守固定、统一的编程方式来编写代码。
3.如何使用?
目前大致有下面三种类型。
Constructor
Promise类似于 XMLHttpRequest,从构造函数 Promise 来创建一个新建新promise对象作为接口。
要想创建一个promise对象、可以使用new来调用Promise的构造器来进行实例化。
var promise = new Promise(function(resolve, reject) { // 异步处理 // 处理结束后、调用resolve 或 reject });
Instance Method
对通过new生成的promise对象为了设置其值在 resolve(成功) / reject(失败)时调用的回调函数 可以使用promise.then() 实例方法。
promise.then(onFulfilled, onRejected)
resolve(成功)时
onFulfilled 会被调用
reject(失败)时
onRejected 会被调用
onFulfilled、onRejected 两个都为可选参数。
promise.then 成功和失败时都可以使用。 另外在只想对异常进行处理时可以采用 promise.then(undefined, onRejected) 这种方式,只指定reject时的回调函数即可。 不过这种情况下 promise.catch(onRejected) 应该是个更好的选择。
promise.catch(onRejected)
Static Method
像 Promise 这样的全局对象还拥有一些静态方法。
包括 Promise.all() 还有 Promise.resolve() 等在内,主要都是一些对Promise进行操作的辅助方法。
function asyncFunction() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Async Hello world');
}, 16);
});
}
asyncFunction().then(function (value) {
console.log(value); // => 'Async Hello world'
}).catch(function (error) {
console.log(error);
});
asyncFunction 这个函数会返回promise对象, 对于这个promise对象,我们调用它的 then 方法来设置resolve后的回调函数, catch 方法来设置发生错误时的回调函数。
该promise对象会在setTimeout之后的16ms时被resolve, 这时 then 的回调函数会被调用,并输出 'Async Hello world' 。
4.promise的状态
用new Promise 实例化的promise对象有以下三个状态。
"has-resolution" - Fulfilled
resolve(成功)时。此时会调用 onFulfilled
"has-rejection" - Rejected
reject(失败)时。此时会调用 onRejecte
"unresolved" - Pending
既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态等
关于上面这三种状态的读法,其中 左侧为在 ES6 Promises 规范中定义的术语, 而右侧则是在 Promises/A+ 中描述状态的术语
5.代码编写
function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } // 运行示例 var URL = "http://httpbin.org/get"; getURL(URL).then(function onFulfilled(value){ console.log(value); }).catch(function onRejected(error){ console.error(error); });
getURL 只有在通过XHR取得结果状态为200时才会调用 resolve - 也就是只有数据取得成功时,而其他情况(取得失败)时则会调用 reject 方法。
resolve(req.responseText) 在response的内容中加入了参数。 resolve方法的参数并没有特别的规则,基本上把要传给回调函数参数放进去就可以了。 ( then 方法可以接收到这个参数值)
6.promise.resolve
一般情况下我们都会使用 new Promise() 来创建promise对象,但是除此之外我们也可以使用其他方法。这里使用promise.resolve
例如:
new Promise(function(resolve){ resolve(42); });
在这段代码中的 resolve(42); 会让这个promise对象立即进入确定(即resolved)状态,并将 42 传递给后面then里所指定的 onFulfilled 函数。
在使用 Promise.resolve(value) 等方法的时候,如果promise对象立刻就能进入resolve状态的话,那么你是不是觉得 .then 里面指定的方法就是同步调用的呢?
实际上, .then 中指定的方法调用是异步进行的。
var promise = new Promise(function (resolve){ console.log("inner promise"); // 1 resolve(42); }); promise.then(function(value){ console.log(value); // 3 }); console.log("outer promise"); // 2
由于JavaScript代码会按照文件的从上到下的顺序执行,所以最开始 <1> 会执行,然后是 resolve(42); 被执行。这时候 promise 对象的已经变为确定状态,FulFilled被设置为了 42 。
下面的代码 promise.then 注册了 <3> 这个回调函数,这是本专栏的焦点问题。
由于 promise.then 执行的时候promise对象已经是确定状态,从程序上说对回调函数进行同步调用也是行得通的。但是即使在调用 promise.then 注册回调函数的时候promise对象已经是确定的状态,Promise也会以异步的方式调用该回调函数,这是在Promise设计上的规定方针。
因此 <2> 会最先被调用,最后才会调用回调函数 <3> 。
由于Promise保证了每次调用都是以异步方式进行的,所以我们在实际编码中不需要调用 setTimeout 来自己实现异步调用。