众所周知,Javascript是一种单线程语言,所有代码都必须按照所谓“自上而下”的顺序执行。 这个特性带来的问题是,一些未来未知的操作必须异步实现。 本文将讨论一种比较常见的异步解决方案——Promise。
问题承诺解决
相信每个后端都遇到过这样的问题。 当一个异步任务的执行依赖于另一个异步任务的结果时,通常会嵌套两个异步任务。 如果这种情况发生一两次也没关系。 当这种情况发生多次后,代码将如下所示:
async1(function(){ async2(function(){ async3(function( async4(funciton(){ async5(function(){ // 直到地老天荒 }); }); )); }); });
这就是所谓的反弹地狱。 代码层层嵌套,环环相扣。 显然,逻辑稍微复杂一些,这样的程序会显得难以维护。
Promise 的基本用法
如今很多现代浏览器都已经实现了webpack开发语言,为了兼容性,建议自己封装Promise或者使用第三方解决方案(比如webpack编译es6句型)。 获取 Promise 构造函数并创建一个新的 Promise 实例:
var _promise = new Promise(function(resolve, reject){ setTimeout(function(){ var rand = Math.random(); if(rand<0.5){ resolve("resolve" + rand); }else{ reject("reject" + rand); } },1000); });
如上所示,Promise的构造函数接收一个函数作为参数,这个函数额外接受两个函数resolve和reject,分别代表将当前Promise设置为fulfilled(已解决)和rejected(已拒绝)的两个函数。 状态。 Promise通过这两种状态来控制异步操作的结果。 接下来我们将讨论Promise的用法。 事实上,Promise上的实例_promise是一个对象,而不是一个函数。 声明时,Promise 传递的参数函数会立即执行,所以 Promise 使用的正确姿势是在其内层再包裹一层函数。
var run = function(){ var _promise = new Promise(function(resolve, reject){ setTimeout(function(){ var rand = Math.random(); if(rand<0.5){ resolve("resolve" + rand); }else{ reject("reject" + rand); } },1000); }); return _promise; } run();
这是Promise的正常用法。 出来的时候就是对异步操作结果的处理,然后里面创建的函数run()
run().then(function(data){ console.log(data); });
每个Promise实例对象都有一个then方法,用于处理前面各种异步逻辑的结果。
那么,这样做有什么用呢?
事实上,它很有用。 至此,我们已经了解了Promise的基本流程,这些用法显然和嵌套的bounce函数是一样的,只是复杂度降低了。 而我们说Promise的好处其实就在于多个异步操作相互依赖时的逻辑流程的控制。 Promise通过控制两种状态来解决过程控制。 请看下面的代码:
run().then(function(data){ //处理resolve的代码 cosnole.log("Promise被置为resolve",data); },function(data){ //处理reject的代码 cosnole.log("程序被置为了reject",data); })
如果异步操作得到了我们想要的结果,那么我们就会调用resolve函数,数据可以在匿名函数中获取,作为then的第一个参数。 如果我们得到错误的结果,则调用reject函数,在then函数中获取第二个匿名函数中的错误处理数据作为参数。 这样,一次完整的Promise调用就结束了。 对于 Promise 的 then() 方法,then 总是返回一个 Promise 实例,所以你可以随时调用 then,比如 run().then().then().then().then().then()。 .... 在 then() 方法中调用异步处理成功状态时,可以返回某个“值”,也可以再次返回 Promise 实例。 当返回一个准确的值时, then 这个准确的值将被传递给一个默认的 Promise 实例,但是这个 Promise 实例将立即被设置为已完成状态,以便在下一个 then 方法中使用。 如下:
run().then(function(data){ console.log("第一次",data); return data; }).then(function(data){ console.log("第二次",data); return data; }).then(function(data){ console.log("第三次",data); return data; }); /* 异步处理成功的打印结果: 第一次 resolve0.49040459200760167d.js:18 第二次 resolve0.49040459200760167d.js:21 第三次 resolve0.49040459200760167 由此可知then方法可以无限调用下去。 */
根据这个特性,我们可以管理多个按比较顺序相互依赖的异步逻辑。 下面是3个异步操作的例子,代码有点长。
这样就完成了几个持续依赖的异步操作,解决了令人头疼的反弹地狱。
异步操作拒绝并中止调用链
如上所述,then 方法可以接收两个匿名函数作为参数。 第一个参数是Promise设置为fulfilled状态后的反弹,第二个参数是Promise设置为rejected状态后的反弹。 很多情况下,如果有多个连续的异步任务webpack开发语言,其中一个异步任务处理失败,后面的几个任务很大程度上就不需要继续处理了,那么我们如何停止then的调用链呢? 在Promsie的例子中,不仅有then方法,还有一个catch方法。 对于catch方法的具体功能,我们继承里面的代码,修改run_a()可以看到:
上面的代码简单描述了如何停止链式调用。 值得注意的是,catch方法还具有trycatch的功能。 也就是说,如果上面的逻辑代码出现错误,那么不会在控制台中抛出错误,而是会直接有一个catch捕获。