注意:本文的目的是让你尽快了解Promise的核心思想和基本用法。如果想了解更多细节和全面的使用方法,请阅读官方API。另外:本文假设你有最基本的异步编程知识,比如知道什么是回调,知道什么是链式调用,并且有最基本的词汇,比如page,user,promise,then,resovle,reject,pay,fix,order等等,如果你对这些词很陌生,那么你需要花点时间提高你的英语水平,否则你还是会觉得这篇文章很难理解。(参考我在表达能力训练视频里讲解的信息不对称原理)什么是异步操作?所谓异步操作是指可以与当前程序同时执行的操作。示例:$("#page").scrolltop(0,1000);//用1秒将页面滚动到顶部$("#nav-float").hide(1000);//使用1秒时间会隐藏浮动导航栏。只要稍微有点异步编程经验的,都应该知道这两个方法会同时完成。它们的写入顺序不会影响它们的执行顺序//异步操作的特点是不会打断当前程序的执行//getUsers请求发出后,会立即继续执行第二个请求ajax("/getUsers",function(data){//请求成功后会调用回调函数})//resumelist请求会立即开始,不管getUsers是否结束ajax("/resumelist",function(data){})//至于where一个ajax先返回结果再执行回调函数,从代码写的先后顺序无法判断。我们可以对异步操作做一个简单的定义。当一个操作开始执行时,主程序可以继续向下执行,而不用等待它完成。这时候可以像主程序一样调用**异步操作**。通常在操作完成后,会执行一个预先设置好的回调函数,进行后续处理。(同时)执行。这种操作就是我们常见的异步操作,比如:异步会带来什么问题?比如我们现在有两个动画需要按顺序执行,即第一个结束,第二个可以开始。这可能有点麻烦。传统的方案是使用回调:animateA(function(){animateB();})这个方案显然不是很好。如果有很多异步操作需要顺序执行,就会出现所谓的“回调地狱”...});});});})这种代码写起来和读起来都很烦人。我们来看看Promise长什么样子(伪代码)newPromise(ajaxA).then(ajaxB).then(ajaxC).then(ajaxD);Promise的使用及原理要想熟练使用Promise,首先要了解它是如何解决问题的,贴一段实际的Promise代码,大家先感受一下:newPromise(resolve=>{ajax("/pay/post",data=>resolve());}).then(resolve=>{ajax("/order/fix",data=>{//处理数据})})上面的代码使用了箭头函数ES6。不友好的读这种代码简直就像读金刚经。我们把代码还原成ES5newPromise(function(resolve){ajax("/pay/post",function(data){resolve();})}).then(function(){ajax("/order/fix",function(data){})})接下来,我们将按照费曼技巧一步步学习Promise是如何解决问题的。问题1作为一个异步函数,尤其是像ajax这样的网络请求,连我自己都无法确定函数的执行时间。Promise如何知道第一个函数何时结束?然后开始下一个?Promise并没有那么神奇,它不知道我们的函数什么时候结束,你注意到上面代码中的第3行了吗?当ajax请求完成执行回调时,我们调用resolve()函数。这段代码非常关键。这实际上是在通知Promise当前函数结束,可以开始执行下一个了。这时候Promise就会去执行then中的函数。问题2,那么按照你的意思,如果我不调用这个方法,Promise不知道函数是否结束,那么then中的函数就不会执行,也就是说我的第二个请求永远不会已经发送了吗?答对了!!恭喜你,你学会了逻辑推理+速答题。问题3但是这个resolve函数是从哪里来的呢?我需要自己定义吗?从代码看,好像是一个参数,那么是谁传给函数的呢?你必须首先了解Promise的基本结构newPromise(function1).then(function2);我们将函数1和函数2作为参数传给了一个Promise对象,那么函数1和函数2就会被这个Promise对象控制定义,简单的说,函数1和函数2会被Promise对象执行。所以在函数1执行的时候,参数当然是Promise对象传入的。newPromise(function(resolve){//resolve是调用函数时Promise对象传入的参数}).then(function2);问题4,Promise对象为什么要把这个resolve函数传入,目的是什么?你怎么说?废话,我知道还需要问你吗?好猪脑,我刚才不是说了吗?Promise对象无法知道我们的异步函数何时结束。那我问你,如果你去车站接一个人,但你不知道那个人什么时候下车,你会怎么办?把我的电话号码给他,快到时给我打电话。没错,Promise就是用同样的思路来解决问题的。它传入的resolve函数就像一个对讲机。当我们的异步任务即将结束时,通过对讲机通知Promise对象。即调用resolve方法newPromise(function(resolve){ajax("/pay/post",function(data){//请求结束时,调用resolve方法通知Promise对象任务已经完成completedresolve();//Promise收到通知后会立即开始执行函数2})}).then(函数2);我明白了,所以这个resolve函数肯定是在异步任务结束的时候调用的(比如ajax的回调方法),相当于告诉Promise对象任务结束了,请开始下一个。非常正确的问题5,所以Promise也不过如此,并没有在功能上带来什么革命性的变化,因为传统的回调嵌套方式也可以达到效果。说白了就是编码方式的改进??基本上就是这样,但是Promise带来的编码方式和异步编程思想的进步是非常巨大的。问题6,如果我有ajaxA、ajaxB、ajaxC三个异步任务,想按照A、B、C的顺序执行,是否应该这样写行?决不!我还没说呢!那如果我这样写你觉得呢?newPromise(function(resolve){ajax("/AAA",function(){resolve();//通知Promise任务结束})}).then(function(resolve){ajax("/BBB",function(){resolve();//通知Promise任务结束})}).then(function(){ajax("/CCC",function(){//....})})以上拼写错误。Promise的中文意思是“promise”,意思是每一个Pomise对象代表一个promise,每一个promise只能保证一个任务的顺序,也就是说newPromise(A).then(B);也就是说,只能保证A和B的顺序。一旦A被执行,B开始,promise就会被履行,Promise对象就会失效。如果还有C怎么办?我们必须在函数B中重新创建一个新的Promise对象来完成下一个Promise。具体写法是这样的:newPromise(function1(resolve){ajaxA("xxxx",function(){resolve();//通知Promise任务结束})}).then(Function2(){//函数2开始运行后,第一次创建的Promise对象完成了使命,无法继续工作。//此时,我们创建并返回了一个新的Promise对象returnnewPromise(function(resolve){ajaxB("xxxx",function(){resolve();//通知新的Promise对象任务结束})})}).then(Function3(){//这里虽然使用了链式调用,但是负责执行函数3的已经是一个新的Promise对象//如果我们还有ajaxD可以顺序调用//那么就必须在这里更新Promise()对象ajaxC("xxx",function(){})})问题7,我明白了,Promise还有哪些强大的功能?是的,比如:如果我有A、B、C三个异步任务,ABC同时开始执行。当A、B、C三个任务都完成后,执行任务D。传统方法实现起来比较复杂,而Promise很简单,像这样:Promise.all([newPromise(A),newPromise(B),newPromise(C)]).then(function(){D();});问题8,如果我希望完成任务A、B、C中的任意一项,然后马上开始任务D,怎么办?Promise.race([newPromise(A),newPromise(B),newPromise(C)]).then(function(){D();});恭喜,你在这么短的时间内学会了Promise
