源宝导读:现今互联网的WEB网站,几乎没有不用到JS异步技术的,虽然大家经常用到,但Javascript提供的异步机制如何才能真正用好呢,可能很多开发小伙伴还有点含糊,本文将从常见的开发场景出发,系统的介绍JS异步对象的原理与使用方法。(正文约9000字,预计阅读时间10分钟)
一、promise是什么
Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
二、Promise的优点
2.1、解决回调导致的代码难以维护
在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱,比如:
// 优化前
var sayhello = function (name, callback) {setTimeout(function () {console.log(name);callback();}, 1000);
}
sayhello("first", function () {sayhello("second", function () {sayhello("third", function () {console.log("end");});});
});
// 优化后
var sayhello = function (name) {return new Promise(function (resolve, reject) {setTimeout(function () {console.log(name);resolve(); //在异步操作执行完后执行 resolve() 函数}, 1000);});
}
sayhello("first").then(function () {return sayhello("second"); //仍然返回一个 Promise 对象
}).then(function () {return sayhello("third");
}).then(function () {console.log('end');
})
2.2、可读性
Promise规范了这种异步场景的代码,相对callback的方式,更加清晰易懂,语义化更强。
2.3、可靠性
Promise是原生支持的API,它已经被加到了JS的规范里面,在各大浏览器中的运行机制是相同的。这样就保证了它的可靠。
2.4、信任问题
只能决议一次,决议值只能有一个,决议之后无法改变。任何then中的回调也只会被调用一次。Promise的特征保证了Promise可以解决信任问题。
三、promise的三种状态
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用。
3.1、兼容性
对于低版本不支持的浏览器可以使用开源的polyfill解决。
[https://github.com/stefanpenner/es6-promise]
3.2、基础使用方式
let myFirstPromise = new Promise(function(resolve, reject){//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)//在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.setTimeout(function(){resolve("成功!"); //代码正常执行!}, 250);
});myFirstPromise.then(function(successMessage){//successMessage的值是上面调用resolve(...)方法传入的值.//successMessage参数不一定非要是字符串类型,这里只是举个例子console.log("Yay! " + successMessage);
}, function (errorMessage) {console.log(errorMessage);
});
四、Promise接口
4.1、Promise.prototype.then
方法返回一个新的Promise。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
基础使用方式
var p1 = new Promise((resolve, reject) => {resolve('成功!');// or// reject(new Error("出错了!"));
});p1.then(value => {console.log(value); // 成功!}, reason => {console.error(reason); // 出错了!});
返回新的Promise
每次执行then之后都将返回新的Promise对象。
回调都没有定义,那么这个新的Promise状态将为原 Promise的状态
var promise = new Promise(function(resolve, reject){reject('error')
})
var promise1 = promise
promise1.then(function(){console.log('success')
}, function (rs) {console.log(rs)
})
// 输出
// error
回调中返回了新的状态,那么以新的状态为准
var promise2 = new Promise(function(resolve, reject){reject('error')
})
var promise3 = promise2.then(null, function () {return Promise.resolve('promise3-success')
})
promise3.then(function(rs){console.log(rs)
}, function (rs) {// 不会执行
})
// 输出
// promise3-success
没有定义回调,那么以原来Promise状态为准
var promise = Promise.reject('error')
promise.then(() => {// 不会执行
}, null).then(() => {// 不会执行
}, (rs) => {console.log(rs) // error
}
回调中如果返回了Error,那么新的Promise状态为rejected
var promise4 = new Promise(function(resolve, reject){resolve('success')
})
var promise5 = promise4.then(function(){throw new Error('error')
})
promise5.then(function(){}, function(rs){console.log(rs)
})
// 输出
// error
Promise可重复执行then或者catch
var promise = new Promise(function(resolve, reject){resolve('success')
})
promise.then(function(){console.log('one')
})
promise.then(function(){console.log('two')
})
promise.then(function(){console.log('three')
})
// 输出
// one
// two
// three
4.2、Promise.prototype.catch
添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果。
使用链式语句的 catch方法
var p1 = new Promise(function(resolve, reject) {resolve('Success');
});
p1.then(function(value) {console.log(value);return Promise.reject('oh, no!');
}).catch(function(e) {console.log(e); // "oh, no!"
}).then(function(){console.log('after a catch the chain is restored');
}, function () {console.log('Not fired due to the catch');
});// 输出为
// 'Success'
// 'oh, no!'
// 'after a catch the chain is restored
捕抛出的错误
// 抛出一个错误,大多数时候将调用catch方法
var p1 = new Promise(function(resolve, reject) {throw 'Uh-oh!';
});p1.catch(function(e) {console.log(e); // "Uh-oh!"
});// 在异步函数中抛出的错误不会被catch捕获到
var p2 = new Promise(function(resolve, reject) {setTimeout(function() {throw 'Uncaught Exception!';}, 1000);
});p2.catch(function(e) {console.log(e); // 不会执行
});// 在resolve()后面抛出的错误会被忽略
var p3 = new Promise(function(resolve, reject) {resolve();throw 'Silenced Exception!';
});p3.catch(function(e) {console.log(e); // 不会执行
});
如果已解决
//创建一个新的 Promise ,且已解决
var p1 = Promise.resolve("calling next");var p2 = p1.catch(function (reason) {//这个方法永远不会调用console.log("catch p1!");console.log(reason);
});p2.then(function (value) {console.log("next promise's onFulfilled"); console.log(value);
}, function (reason) {console.log("next promise's onRejected");console.log(reason);
});
// 输出
// next promise's onFulfilled
// calling next
4.3、Promise.prototype.allSettled
返回一个promise,该promise在所有给定的promise已被解析或被拒绝后解析,并且每个对象都描述每个promise的结果。
兼容性并不是很好,polyfill也并未支持
4.4、Promise.prototype.finally
返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。
var p1 = new Promise(function(resolve, reject){resolve('success')
})
var p2 = new Promise(function(resolve, reject){reject('error')
})p1.finally(function(){console.log('one')
})
p2.finally(function(rs){console.log('two')
})// 输出
// one
// two
注意:由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
4.5、Promise.all
这个方法返回一个新的promise对象,该promise对象在参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个参数里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含参数里所有promise返回值的数组作为成功回调的返回值,顺序跟参数的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把参数里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {setTimeout(resolve, 100, 'foo');
});Promise.all([promise1, promise2, promise3]).then(function(values) {console.log(values);
});
// 输出
// [3, 42, "foo"]
4.6、Promise.reject
返回一个带有拒绝原因reason参数的Promise对象。
Promise.reject("error").then(function(reason) {// 未被调用
}, function(reason) {console.log(reason); // "error"
});Promise.reject(new Error("fail")).then(function(result) {// 未被调用
}, function(error) {console.log(error); // stacktrace
});
4.7、Promise.resolve
返回一个以给定值解析后的Promise 对象。如果该值为promise,返回这个promise;如果这个值是带有”then” 方法,返回的promise会采用它的最终状态;否则返回的promise将以此值完成。
Promise.resolve("Success").then(function(value) {console.log(value); // "Success"
}, function(value) {// 不会被调用
});
Resolve另一个promise
var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function(value) {console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));// 输出
// original === cast ? true
// value: 33
resolve 包含then的对象参数
// resolve
var p1 = Promise.resolve({ then: function(onFulfill, onReject) { onFulfill("fulfilled!"); }
});p1.then(function(v) {console.log(v); // 输出"fulfilled!"}, function(e) {// 不会被调用
});// reject
var p2 = Promise.resolve({ then: function(onFulfill, onReject) { onReject("rejected!"); }
});p2.then(function(v) {// 不会被调用}, function(e) {console.log(e); // 输出"fulfilled!"
});
4.8、Promise.race
当参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
var p1 = new Promise(function(resolve, reject) {setTimeout(resolve, 500, 'one');
});var p2 = new Promise(function(resolve, reject) {setTimeout(resolve, 100, 'two');
});Promise.race([p1, p2]).then(function(value) {console.log(value);// Both resolve, but p2 is faster
});
// 输出
// two
五、Promise事件
使用Promise编写异步代码时,使用reject来处理错误。有时,开发者通常会忽略这一点,导致一些错误没有得到处理。例如:
new Promise((resolve, reject) => {reject('error')
}).then(function(){}).then(function(){})
由于没有使用catch方法捕获错误,当reject时,抛出的错误则没有被处理。
5.1、unhandledrejection
当 Promise 被拒绝,但没有提供 reject 函数来处理该 rejection 时,会派发此事件。
window.addEventListener('unhandledrejection', event => {console.log(event.reason); // 打印"Hello, Fundebug!"
});Promise.reject('Hello, Fundebug!');
5.2、rejectionhandled
当一个Promise错误最初未被处理,但是稍后又得到了处理,则会派发此事件:
window.addEventListener('unhandledrejection', event => {console.log(event.reason); // 打印"Hello, Fundebug!"
})window.addEventListener('rejectionhandled', event => {console.log('rejection handled'); // 1秒后打印"rejection handled"
});function foo() {return Promise.reject('Hello, Fundebug!');
}var r = foo();setTimeout(() =>{r.catch(e =>{});
}, 1000);
我们可以通过以上事件为 Promise 失败时提供补偿处理,也有利于调试 Promise 相关的问题。在每一个上下文中,该处理都是全局的,因此不管源码如何,所有的错误都会在同一个handler中被捕捉处理。
举例如下:
window.addEventListener("unhandledrejection", event => {/* 你可以在这里添加一些代码,以便检查event.promise 中的 promise 和event.reason 中的 rejection 原因 */event.preventDefault();
}, false);
六、高级使用方式
6.1、链式调用
连续执行两个或者多个异步操作是一个常见的需求,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。我们可以通过创造一个 Promise 链来实现这种需求。
var promise = new Promise(function(resolve, reject){resolve('promise')
})
promise.then(function(rs){console.log(rs)return 'success'
}).then(function(rs){console.log(rs)return new Promise(function(resolve, reject) {setTimeout(function(){reject('error')}, 3000)})
}).then(function(){// 不会执行console.log('不会执行')
}, function (rs) {console.log(rs)return 'finish'
}).then(function(rs){console.log(rs)
})// 输出
// promise
// success
// error
// finish
注意:一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果。
6.2、Catch 的后续链式操作
有可能会在一个回调失败之后继续使用链式操作,即 使用一个 catch,这对于在链式操作中抛出一个失败之后,再次进行新的操作很有用。请阅读下面的例子:
new Promise((resolve, reject) => {console.log('初始化');resolve();
})
.then(() => {throw new Error('有哪里不对了');console.log('执行「这个」”');
})
.catch(() => {console.log('执行「那个」');
})
.then(() => {console.log('执行「这个」,无论前面发生了什么');
});// 输出结果
// 初始化
// 执行“那个”
// 执行“这个”,无论前面发生了什么
注意:因为抛出了错误 有哪里不对了,所以前一个 执行「这个」 没有被输出。
6.3、执行顺序
为了避免意外,即使是一个已经变成 resolve 状态的 Promise,传递给 then() 的函数也总是会被异步调用:
Promise.resolve().then(function(){console.log(2)
})
console.log(1); // 1, 2
传递到 then() 中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,事件队列被清空之后,才开始执行:
var loading = new Promise(function (resolve, reject) {setTimeout(resolve)
})
loading.then(function () {console.log(4)
});
Promise.resolve().then(function(){console.log(2)
}).then(function(){console.log(3)
});
console.log(1); // 1, 2, 3, 4
微任务宏任务参考文章[http://www.manongjc.com/article/9144.html。
promise微任务;
setTimeout宏任务。
6.4、嵌套
then回调函数中如果返回了新的异步对象,那么后续链式调用的then都会等待新的异步对象完成才会继续向下执行,如:
var p1 = new Promise(function(resolve, reject){console.log('p1')resolve()
})
p1.then(function(){return new Promise(function(resolve, reject) {setTimeout(function(){console.log('p2')resolve()}, 1000)}).then(function(){console.log('p3')}).then(function(){console.log('p4')})
}).then(function(){console.log('p5')
})
// 输出
// p1
// p2
// p3
// p4
// p5
简便的 Promise 链式编程最好保持扁平化,不要嵌套 Promise,因为嵌套会导致可读性降低,代码也不容易排除,上述逻辑优化如下:
var p1 = new Promise(function(resolve, reject){console.log('p1')resolve()
})
p1.then(function(){return new Promise(function(resolve, reject) {setTimeout(function(){console.log('p2')resolve()}, 1000)})
}).then(function(){console.log('p3')
}).then(function(){console.log('p4')
}).then(function(){console.log('p5')
})
// 输出
// p1
// p2
// p3
// p4
// p5
七、Promise的缺点
代码有风险造成未解决的promise;
无法取消Promise,一旦新建它就会立即执行,无法中途取消;
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;
当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
八、async await
async/await 是 ES7 引入的新的异步代码 规范,它提供了一种新的编写异步代码的方式,这种方式在语法层面提供了一种形式上非常接近于同步代码的异步非阻塞代码风格,在此之前我们使用的多是异步回调、 Promise 模式。
使用方式
8.1、async 关键字
async function 用来定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。
async function name([param[, param[, ... param]]]) { statements }
name 函数名称。param 要传递给函数的参数。statements 函数体语句。返回值 返回的Promise对象会运行执行(resolve)异步函数的返回结果,或者运行拒绝(reject)——如果异步函数抛出异常的话。
8.2、await 关键字
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。await 会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled,其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。若 Promise 处理异常(rejected)await 表达式会把 Promise 的异常原因抛出。另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。
[return_value] = await expression;
表达式 一个 Promise 对象或者任何要等待的值。
返回值 返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
示例
async function f1() {var x = await resolveAfter2Seconds(10);console.log(x); // 10
}
f1();
8.3、并联的 await
async/await 语法确实很简单好用,但在现实场景中也容易出现一些问题。以下面代码为例:
async function retriveProfile(email) {const user = await getUser(email);const roles = await getRoles(user);const level = await getLevel(user);return [user, roles, level];
}
上面代码实现了获取用户基本信息,然后通过基本信息获取用户角色、级别信息的功能,其中 getRoles 与 getLevel 两者之间并无依赖,是两个并联的异步操作。但代码中 getLevel 却需要等待 getRoles resolve 之后才能执行。并不是所有人都会犯这种错误,而是同步风格很容易诱惑我们忽略掉真正的异步调用次序,而陷入过于简化的同步思维中。写这一段的目的正是为了警醒大家,async 只是形式上的同步,根本上还是异步的,请注意不要让使用者把时间浪费在无谓的等待上。上面的逻辑,用一种稍微 绕 一些的方式来实现,就可以避免这种性能损耗:
async function retriveProfile(email) {const user = await getUser(email);const p1 = getRoles(user);const p2 = getLevel(user);const [roles, levels] = await Promise.all(p1, p2);return [user, roles, levels];
}
注意,代码中的 getRoles 、getLevel 函数都没有跟在 await 关键字之后,而是把函数返回的 Promise 存放在变量 p1、p2 中,后续才对 p1、p2 执行 await 声明, getRoles 、getLevel 就能同时执行,不需等待另一方的完成。
九、错误处理
使用try…catch
async function asyncCall() {try {await asyncFunc();throw new Error("oops");} catch (e) {console.log(e);// output// Error: oops at asyncCall (<anonymous>:4:11)}
}
包装promise,使其返回统一的格式的代码
/*** 包装promise, 使其返回统一的错误格式* @param {Promise} promise */
function to (promise) {// 第一个标识异常数据return promise.then(res => [null, res]).catch(err => [err])
}
const [err, res] = await to(fetchUser(true))
if (err) {console.error('touser err:', err)
}
继续使用catch
// 因为async 返回的promise对象,所以可以使用catchconst user4 = await fetchUser(true).catch(err => {console.error('user4 error:', err)})
优点
async/await从上到下,顺序执行,就像写同步代码一样。这更符合人编写代码的习惯。
缺点
编译后增加了代码的体积;
编译后的代码不容易理解,会给调试时带来一定困扰。
十、jQuery 异步对象
jquery中试通过$.Deferred来实例化异步对象的,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是”延迟”,所以deferred对象的含义就是”延迟”到未来。
简单示例
在 jQuery 中
var deferred = $.Deferred();
var promise = deferred.promise();
在 ES6 中
var promise= function (function(resolve, reject){
})
处理状态
一个 deferred对象 能做的和一个promise对象差不多,它也有resolve和reject两个函数来触发 done()和fail()函数 。
在jQuery中
var deferred = $.Deferred();
setTimeout(function(){deferred.resolve('success')
}, 2000)
var promise = deferred.promise();
在 ES6 中
var promise = new Promise(function(resolve, reject){resolve('success')
})
jquery的延时对象可以在外面解决,二promise的异步对象在实例化的回调中解决,相比promise的更加安全,语法也简洁。
等待多个异步完成
在jQuery中
var deferred1 = $.Deferred();
deferred1.resolve('promise1');
var promise1 = deferred1.promise();
var deferred2 = $.Deferred();
deferred2.resolve('promise2');
var promise2 = deferred2.promise();
$.when(promise1, promise2).then(function(rs1, rs2){console.log(rs1, rs2)// promise1, promise2
})
在 ES6 中
var promise1 = Promise.resolve('promise1')
var promise2 = Promise.resolve('promise2')
Promise.all([promise1, promise2]).then(function(rs){console.log(rs) // ['promise1', 'promise2']
})
成功或失败都触发
在jQuery中
var deferred1 = $.Deferred();
deferred1.reject('promise1');
var promise1 = deferred1.promise();
promise1.always(function(rs){console.log(rs) // promise1
})
var deferred2 = $.Deferred();
deferred2.resolve('promise2');
var promise2 = deferred2.promise();
promise2.always(function(rs){console.log(rs) // promise2
})
在 ES6 中
var promise1 = Promise.reject('promise1')
var promise2 = Promise.resolve('promise2')
promise1.finally(function(rs){console.log(rs) // undefined
})
promise2.finally(function(rs){console.log(rs) // undefined
})
ES6中Promise的finally回调中并不会有解决的结果。
十一、Promise常见应用场景
按钮锁定,防止重复提交
实际场景中往往存在用户提交后,需要等待后台逻辑完毕后,才能执行其它的操作,那么这个过程中需要锁定界面相关操作按钮的,防止用户做其他不符合业务的操作,如还没等表单保存完毕就发起审批,那么这种情况代码中应该怎么处理,下面从代码层面简单说明一下:
// main.js
module.exports = {// 是否保存中saving: false,// 保存按钮点击onSaveClick: function () {var me = this// 先判断如果处于保存中,不允许再次提交保存if (this.saving) {return}this.save().then(function(){// 释放saving状态,可继续执行保存操作me.saving = false}, function(){// 失败时saving也要处理为falseme.saving = false})},// 审批按钮点击onApplyClick: function () {// 如果处于保存中,不允许执行审批操作if (this.saving) {return}...},// 保存save: function () {return new Promise(function(resolve, reject){// 向后端发起请求Ajax({... }).then(resolve, reject)})}
}
这里主要是借助了save方法返回了异步Promise对象来完成对saving状态的释放,实际的场景会比这个更复杂,比如校验或者按钮的loading效果,但是这仅是逻辑与交互的叠加,主要的处理点还是这里。
实现串行任务队列
有些表单提交前是需要做校验的,比如新增签约用户,需要校验客户的身份证号以及手机号的正确性后才能保存,并且保存完毕后需要弹出提示,这就需要借助Promise的请求依赖完成这个需求场景,相关代码如下:
// form.js
module.exports = { // 校验客户名称是否重名validateName: function () {return new Promise(function(resolve, reject) {...resolve()})},// 校验手机号是否存在validateMobile: function () {// Ajax仅表示通过jQuery或者平台ajax返回的异步对象return Ajax({...})},// 校验身份证号正确性validateIdNumber: function () {// 如果要使用串行调用方式,即使是前端校验也要返回Promise对象,如return new Promise(function(resolve, reject) {// 伪代码,实际应用时不做参考if (/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(this.formData.idNumber)) {resolve()} else {reject()}})},// 保存表单saveForm: function () {var me = thisreturn me.validateName().then(function(){return me.validateMobile()}).then(function(){return me.validateIdNumber()}).then(function(){return Ajax({...})}).then(function(){alert('保存成功')}, function () {alert('保存失败')})},// 用户点击保存按钮onSaveClick: function () {return this.saveForm()}
}
这个场景中,如果用户的名称校验失败了,那么不会走到后面的校验手机号,直接会到最后的保存失败,这也是符合实际业务的,只有前面的校验全部通过了才会到最后的保存,整个环节是串行的任务执行。
多个异步任务并发控制
在页面初始化的时候,往往会发送很多的请求从后端获取数据,在这个阶段页面会显示一个loading遮罩层,等所有的请求完毕后再将这个遮罩层关闭掉,这个时候需要借助到Promise并发多个异步,同时监听异步完成后的动作,大致的代码如下:
// main.js
module.exports = {// 页面初始化pageInit: function () {// 页面开始loadingthis.pageLoading = true// 加载用户数据、证件类型数据、购房信息数据,Promise.all会监听异步队列完毕后执行then中的回调,具体细节可参考上诉Promise.all的用法Promise.all([this.getUserData(),this.getCertificateData(),this.getBuyRoomInfo()]).then(function(){// 页面关掉loadingthis.pageLoading = false}, function () {// 页面关掉loadingthis.pageLoading = false})},// 获取用户数据getUserData: function () {return new Promise(function(resolve, reject) {...resolve({userName: 'xxx',...})})},// 获取证件类型数据getCertificateData: function () {// Ajax仅表示通过jQuery或者平台ajax返回的异步对象return Ajax({...})},// 获取用户购买房间信息getBuyRoomInfo: function () {return new Promise(function(resolve, reject) {...resolve({roomName: '房间名称',...})})}
}
小结
Promise是一种很好的编程设计思想,在设计一些对外的耗时异步API时候,也可以借助Promise,而非传统的callback方式,可以很优雅的对外输出。同时这又需要团队内的成员都需要熟悉Promise的使用,才能更好的发挥它的威力。
------ END ------
作者简介
杨同学: 研发工程师,目前负责ERP建模平台的设计与开发工作。
也许您还想看
从案例角度解析建模平台动态规则引擎
WEB页面前端性能诊断方法与实践
【复杂系统迁移 .NET Core平台系列】之界面层
链路追踪在ERP系统中的应用实践