What is Promise
Promise是JavaScript的异步操作的解决方案,为异步操作提供统一接口。
它起到代理作用(proxy), 充当异步操作与回调函数之间的中介。Promise可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。
Promise是一个对象,也是一个构造函数。
1 2 3 4 5
| function f1(resolve, reject) {
} var p1 = new Promise(f1); p1.then(f2);
|
传统方法与Promise方法对比:
1 2 3 4 5 6 7 8
| step1(function(v1){ step2(v1, function(v2){ }) })
new Promise(step1) .then(step2);
|
States of Promise
共三种状态:
- pending
- fulfilled
- rejected
fulfille为resolved.
这三种状态的变化途径只有两种:
1 2 3 4 5 6 7
| function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); }
timeout(100)
|
then 用法解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| f1().then(function () { return f2(); });
f1().then(function () { f2(); });
f1().then(f2());
f1().then(f2);
|
Promise优缺点
优点:
- 统一异步API,fetch API基于promise的:
1 2 3
| fetch(url) .then(request=>request.test()) .then(str=>...)
|
Promise与事件对比:
Promise与回调函数相比:
- 更干净的函数参数,回调函数的场景,主函数既有输入参数,又有输出参数。
缺点:
- 多次触发的事件
- 数据流
- 不能取消执行
- 无法获取当前执行的进度信息(比如,要在用户界面展示进度条)(Q Promise)
简单地实现Promise,并支持异步链式调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function Promise(fn) { this.cbs = []; const resolve = (value) =>{ setTimeout(()=>{ this.data = value; this.cbs.forEach((cb)=>cb(value)); }); } fn(resolve.bind(this)); }
|
分开来看,fn是用户传的函数,这个函数内部调用了resolve函数后,就会把promise实例上的cbs全部执行一遍,那么cbs数组中的函数从哪来呢?
1 2 3 4 5 6 7 8 9 10
| Promise.prototype.then = function(onResolved) { return new Promise((resolve)=>{ const result = onResolved(this.data); if(result instanceof Promise) { result.then(resolve); } else { resolve(result) } }) }
|
异步操作封装成Promise,实现对Ajax的封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function pajax({url=null, method='GET', dataType:'JSON', async='true'}) { return new Promise((resolve, reject)=>{ let xhr = new XMLHttpRequest(); xhr.open(method, url, async); xhr.responseType = dataType; xhr.onreadystatechange = () =>{ if(xhr.readyState===4 && xhr.status===200) { let result = xhr.responseText; resolve(result); } } xhr.onerror = (err) =>{ reject(err); } xhr.send(); }) }
pajax({ url: './test.json', }).then(console.log) .catch(console.err)
|
Promise then的第二个参数和catch的区别
主要区别就是,如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。
Promise的catch是个语法糖,还是通过then来处理的,类似于:
1 2 3
| Promise.prototype.catch = function(fn) { return this.then(null, fn); }
|
捕获错误信息的时候会就近原则。