Open ccforward opened 8 years ago
一个稍微复杂点的例子_https://github.com/ccforward/cc/blob/master/promise/example-new.js_
_ES6规范确认以前,写过一个Promise的简单实现_
Promise就是一个容器,里面保存着某个未来才会结束的事件(一个异步操作)的结果。作为一个对象,从Promise可以获取异步操作的消息。
Pending
Resolved
Rejected
通过Promise对象就可以将异步操作以同步操作的流程表达出来,避免嵌套层层回调的地狱。
var getJSON = function(url){ var promise = new Promise(function(){ var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onreadystatechange = hanlder; xhr.responseType = 'json'; xhr.setRequestHeader('Accept', 'application/json'); xhr.send(); function hanlder(){ if(this.readyState !== 4){ return; } if(this.status == 200){ resolve(this.response); } else { reject(new Error(this.statusText)); } }); return promise; }
如果调用 resolve 或者 reject 函数时带有参数,那么这些参数会传递给回调函数。 reject的参数通常是 Error 对象的实例,表示跑出的错误。
then 方法是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是 Resolved 状态的回调函数,第二个参数(可选)是 Rejected 状态的回调函数。
then方法返回的是一个新的Promise实例(不是原来那个),可采用链式写法。如下:
getJSON("a.json").then(function(res){ return getJSON(res.dataURL) }).then(function fnA(data){ console.log('Resolved: ' + data); }, function fnB(err){ console.log('Rejected: ' + err); });
第一个then方法指定的回调函数返回的是一个新的 Promise 对象。这时,第二个then方法指定的回调函数就等待这个新的 Promise 对象发生变化来调用A或B函数
上面的代码改为箭头函数更简洁:
getJSON("a.json").then( res => getJSON(res.dataURL) ).then( data => console.log('Resolved: ' + data), err => console.log('Rejected: ' + err) );
Promise.prototype.catch 是 .then(null, rejection) 的别名。
如果异步操作抛出错误,状态就会变为 Rejected, 就会调用catch方法指定的回调函数处理这个错误。
一般来说,不要再then方法中定义 Rejected 状态的回调函数(then的第二个参数),而应该总是使用 catch 方法。
//bad promise .then(function(data){ // success },function(err){ // error }) // good promise .then(function(data){ //回调函数 // success }) .catch(function(err){ // error })
跟传统的 try/catch 不同,如果没有使用catch方法指定错误处理的回调函数, Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
catch 返回的还是一个 Promise 对象,因此后面可以继续调用 then 方法。
var someAsync = function(){ return new Promise(function(resolve, reject){ // x没声明 报错 resolve(x+2); }); } comAsync() .catch(function(err){ console.log('error: ' + err) }) .then(function(){ console.log('go on') }); // error: [ReferenceError: x is not defined] // go on 接着运行then方法
Promise.all 用于将多个 Promise 实例包装成一个新的 Promise 实例。
var p = Promise.all([p1, p2, p3]);
p的状态由 p1 p2 p3 决定
Promise.race 也是将多个 Promise 实例包装成一个新的 Promise 实例。
var p = Promise.race([p1, p2, p3]);
只要 p1 p2 p3 中有一个实例率先改变状态,p的状态就跟着改变
var p = Promise.race([ fetch('/data.json'), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('request timeout')), 5000) }) ]) p.then(response => console.log(response)) p.catch(error => console.log(error))
如果5秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
Promise.resolve方法将现有对象转为Promise对象。
Promise.resolve($.ajax('/whatever.json'));
把 jQuery 生成的 deferred 对象转为新的 Promise 对象
Promise.resolve('foo') // 等价于 new Promise(resolve => resolve('foo'))
如果resolve方法的参数是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved。
var p = Promise.resolve('Hello'); p.then(function (s){ console.log(s) });
字符串Hello不属于异步操作(判断方法是它不是具有then方法的对象),返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。
Promise.resolve方法允许调用时不带参数,直接调用Promise.resolve可以获得一个 Promise 对象。
var p = Promise.resolve(); p.then(function () { // ... });
Promise.reject() 方法也会返回一个新的Promise实例,且状态为rejected。
它的参数用法与Promise.resolve方法完全一致。
var p = Promise.reject('出错了'); // 等同于 var p = new Promise((resolve, reject) => reject('出错了')) p.then(null, function (s){ console.log(s) }); // 出错了
Promise.prototype.done = function (onFulfilled, onRejected) { this.then(onFulfilled, onRejected) .catch(function (reason) { // 抛出一个全局错误 setTimeout(() => { throw reason }, 0); }); };
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };
ES6 笔记三 - Promise
一个稍微复杂点的例子_https://github.com/ccforward/cc/blob/master/promise/example-new.js_
_ES6规范确认以前,写过一个Promise的简单实现_
Promise就是一个容器,里面保存着某个未来才会结束的事件(一个异步操作)的结果。作为一个对象,从Promise可以获取异步操作的消息。
两个特点
Promise对象代表一个异步操作,有三种状态:
Pending
(进行中)Resolved
(已完成 Fullfilled)Rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何操作都无法改变这个状态。
Promise的状态改变只有两种可能:Pending -> Resolved 或者 Pending -> Rejected。
只要两种情况发生,状态就固定不会改变了,会一直保持这个结果。
通过Promise对象就可以将异步操作以同步操作的流程表达出来,避免嵌套层层回调的地狱。
缺点
用 Promise 对象实现一个Ajax
如果调用 resolve 或者 reject 函数时带有参数,那么这些参数会传递给回调函数。 reject的参数通常是 Error 对象的实例,表示跑出的错误。
Promise.prototype.then
then 方法是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是 Resolved 状态的回调函数,第二个参数(可选)是 Rejected 状态的回调函数。
then方法返回的是一个新的Promise实例(不是原来那个),可采用链式写法。如下:
第一个then方法指定的回调函数返回的是一个新的 Promise 对象。这时,第二个then方法指定的回调函数就等待这个新的 Promise 对象发生变化来调用A或B函数
上面的代码改为箭头函数更简洁:
Promise.prototype.catch
Promise.prototype.catch 是 .then(null, rejection) 的别名。
如果异步操作抛出错误,状态就会变为 Rejected, 就会调用catch方法指定的回调函数处理这个错误。
一般来说,不要再then方法中定义 Rejected 状态的回调函数(then的第二个参数),而应该总是使用 catch 方法。
跟传统的 try/catch 不同,如果没有使用catch方法指定错误处理的回调函数, Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
catch 返回的还是一个 Promise 对象,因此后面可以继续调用 then 方法。
Promise.all()
Promise.all 用于将多个 Promise 实例包装成一个新的 Promise 实例。
p的状态由 p1 p2 p3 决定
Promise.race()
Promise.race 也是将多个 Promise 实例包装成一个新的 Promise 实例。
只要 p1 p2 p3 中有一个实例率先改变状态,p的状态就跟着改变
如果5秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
Promise.resolve()
Promise.resolve方法将现有对象转为Promise对象。
Promise.resolve($.ajax('/whatever.json'));
把 jQuery 生成的 deferred 对象转为新的 Promise 对象
如果resolve方法的参数是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved。
字符串Hello不属于异步操作(判断方法是它不是具有then方法的对象),返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。
Promise.resolve方法允许调用时不带参数,直接调用Promise.resolve可以获得一个 Promise 对象。
Promise.reject()
Promise.reject() 方法也会返回一个新的Promise实例,且状态为rejected。
它的参数用法与Promise.resolve方法完全一致。
附加方法