http://caniuse.com/promises/embed/agents=desktopjavascript
Promise是抽象异步处理对象以及对其进行各类操做的组件。html
说到 javascript 异步操做,可能想到的是这样:java
// 以 jQuery 的 ajax 为例 $.get('/get_url', function(result, status) { if(status == 'success') { alert('success'); } if(status == 'error') { alert('error'); } });
对于 ajax 的 get 操做来讲,是一个异步的过程,经过回调函数,在获得返回的时候才会去执行操做。ajax
可是试想一下当操做愈来愈多,回调里面还要回调的时候,一层层回调函数是否是让人抓狂,不论在代码可读性仍是编写效率来看都是很麻烦的。
看一下咱们用 Promise 能够怎么作一个异步的操做:数组
// 这个 getData 是咱们预先实例好的一个 Promise 对象,如何处理这个对象咱们这里不讨论 var promise = getData('/get_url');![图片描述][3] promise.then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
这样的风格是否是会更好呢,执行一个 promise,而后 then 里面传入回调函数,若是愿意,咱们能够在 then 后面再更不少个 then,catch 能够捕捉错误,看起来代码清晰简明多了。
因此,promise的功能是能够将复杂的异步处理轻松地进行模式化。promise
new Promise(executor); new Promise(function(resolve, reject) { ... });
这里的 executor
是咱们实例化一个 promise 对象时应该传入的参数,这个参数只一个函数,这个函数接受两个参数 resolve
和reject
。
两个方法:浏览器
resolve(result)
在 promise 中执行这个方法表示成功,会在执行以后执行后面的 then 所传入的函数,它接受到的参数也会被 then 里面的函数接受到,通常来讲参数为执行结果成功时候的数据;并发
reject(error)
在 promise 中执行这个方法表示失败,他通常接受一个 error 错误参数,会被后面的 catch 捕捉到错误执行。
demo:异步
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve('success'); }, 2000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
在这里咱们定义了一个 testFoo
函数,这个函数返回一个Promise
的实例化对象,两秒以后会执行resolve('success');
,表示成功,传入一个参数,在两秒以后,咱们then里面传入的函数执行了,接收到了刚刚那个参数;可是catch里面的函数并无执行,由于咱们没有在 promise 里面执行拒绝操做。函数
若是咱们在四秒以后执行 reject
操做呢:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve('success'); }, 2000); setTimeout(function() { reject('error'); }, 4000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
貌似只出现resolve
的结果,由于一个 promise 没办法作屡次结果操做。
咱们就这样:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { reject('error'); }, 4000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
如今结果如咱们所预料了。
状态分为三种:
fulfilled
- Fulfilled 已完成,在 resolve
时,调用 then 的 onFulfilled
函数;
Rejected
- Rejected 拒绝,在reject
时,调用 then 的 onRejected
函数,或者 catch 里面的函数;
unresolved
- Pending 等待,是 promise 初始化的时候的状态。
promise 的 初始化状态为 unresolved,根据异步结果变为 fulfilled 或者 Rejected,一旦变为其中一个就不可改变,这也是咱们以前上面为何执行了 resolve 以后再执行 reject 而没有结果的缘由了。
Promise.resolve()
这个是promise的静态方法
Promise.resolve(10).then(function(value){ console.log(value); });
这个方法会让 Promise 当即进入 fulfilled 状态,通常用来测试用。
Promise.reject()
相应着咱们有这个方法
Promise.reject('err').catch(function(err){ console.log(err); });
then(onFulfilled, onRejected)
这个方法具体是这样的,传入两个函数,一个处理fulfilled状态,另外一个处理Rejected状态,通常使用咱们只传入第一个函数,第二个放在 catch 来处理。
catch(onRejected)
处理Rejected状态,能够这么理解catch(onRejected)
=promise.then(undefined, onRejected)
。
看看这个 demo:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }); // 1 // 2 // 3
能够看见结果,这个方法的流程是什么样的呢?
第一个 then 函数和以前讲的同样,处理 promise 的 fulfilled,第二个 then 的函数是处理前一个 then 函数处理完的结果,他们之间参数传递的途径是前一个 then 函数 return 一个数据,而后后一个 then 函数接受到这个参数。
若是你愿意,能够再后面加不少不少个 then,他们的流程主要是这样。
若是咱们把 catch 提早呢?
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }).then(function(result) { console.log(result); return ++result; }); // 1 // 2 // 3
能够看出,结果同样,说明catch只会在发生 reject 的时候调用。
那若是在中间的一个 then 中抛出一个异常呢?
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); throw new Error("throw Error") return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }); // 1 // 2 // Error: throw Error
咱们在第二个then中抛出一个异常,然后当即被 catch 捕捉到,第三个 then 并无执行。
到这里咱们想一下从then的传参和捕捉异常来看,新加一个 then 只是注册了一个回调函数那么简单吗?
不不不,每次调用then都会返回一个新建立的promise对象,这就解释了上面的一切缘由。
试想一个场景,咱们执行多个异步操做(ajax等等),可是咱们想在这几个操做都完成的时候才去执行一个函数。
若是按照传统的方法来作,代码会很乱很散,关键不优雅。让咱们尝试用 promise 。
先看这个 demo
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { function recordValue(results, value) { results.push(value); console.log(value); console.log(results); return results; } var pushValue = recordValue.bind(null, []); return tasks.task1().then(pushValue).then(tasks.task2).then(pushValue).then(tasks.task3).then(pushValue); }; main().then(function(value) { console.log(value); }); // [2, 3, 1]
这么实现明显看起来凌乱,特别对于 main 函数,可读性也比较差。
那么有没有更优雅的方法呢,答案:有!?。
Promise.all
方法接受一个以 promise 对象为元素的数组,在所有执行操做完成后才回调用then里面的方法,看代码:
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }); // [2, 3, 1]
咱们吧要执行的 promise 对象做为数组的元素传给 Promise.all()
,Promise.all().then()
里面定义的函数接受到一个数组,元素是这几个操做返回的值,顺序和 promise 对象放入的顺序同样,好比第一个 promise 对象返回的值是2,那么结果的第一个元素就是2。
而且每个promise是同时执行的--并发。
在全部 promise 的状态为 FulFilled 的时候才会去执行 then 里面的函数。
那么捕捉异常呢?
修改一下例子:
var testFoo = function(time, value, err) { return new Promise(function(resolve, reject) { setTimeout(function() { if(err) { reject(err); return false; } resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2, 'error'); }, task2: function() { return testFoo(1.3, 3, 'error1'); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }).catch(function(err) { console.log(err); }); // [2, 3, 1]
咱们让其中2 promise 个抛出异常,看到捕捉到了那个异常,并且是捕捉到第一个异常就中止了。
说明 all 的操做是当全部 promise 状态为 FulFilled 的时候才会执行 then 的操做。而一旦有一个 Rejected 就catch这个异常,而且中止。
他和 Promise.all 同样,接受一个 promise 对象组成的数组,也是并发执行,可是 Promise.race 是只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.race([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }); // 2
能够看到,task1 最早完成,而后就拿到他的值进行 then 操做。
原文来自个人博客 http://qiutc.me/post/promise-learn-note.html欢迎你们关注~