文 / 景朝霞


目录:0 / Promise 的应用(1)ajax串行,很久很久以前的写法(2)Promise应用于异步请求1 / Promise的语法(1)执行resolve函数(2)执行reject函数(3)resolve和reject俩函数都调用了2 / Promise如何管控异步(1)没有宏任务时(2)有宏任务时3 / 小结

0 / Promise 的应用

ES6中新增一个内置的类:Promise承诺/约定模式,基于这种模式可以有效的处理异步编程

异步执行代码 java 异步执行代码_异步操作

△ 图1_promise的兼容性

(1)ajax串行,很久很久以前的写法

需求:

① 首先从服务器端基于"api/A.json"这个接口获取数据,紧接着把获取的某些数据作为参数

② 再基于"api/B.json"获取其他的数据

③ 最后在第二次数据获取成功后,再基于"api/C.json"获取新的数据……

即:A请求成功才可以获取B请求,B成功后才可以获取C请求……【AJAX的串行】

<script src="./node_modules/jquery/dist/jquery.js">script> <script src="./1.js">script>

△ html

//---> /api/A.json {     "1":1,     "name":"朝霞的光影笔记",     "id":"zhaoxiajingjing" }  //---> /api/B.json 2  //---> /api/C.json 3

△ 需要请求的数据

如果是这样写的,那么三个ajax之间没有关联:

let data = null; //=> 基于JQ的AJAX"异步"从服务器获取数据 //=> 【项目中从服务器获取数据也是异步的】 $.ajax({     url:'/api/A.json',     dataType:'json',     success:function(result){         //=> result 是基于JQ的AJAX方法从服务器获取的结果         data = result;         console.log('第一次请求',result);//=> 第二次输出:第一次请求 {name: "朝霞的光影笔记", id: "zhaoxiajingjing"}     } }); console.log(data);//=>第一次输出:null  //=> 【异步:上面的事情没有完,也不会等;下面的事情也会继续执行】 //=> 【同步:上面的事情没有完,后面的事情不会执行】  $.ajax({     url:'/api/B.json',     dataType:'json',     success:function(result){         console.log('第二次请求', result);     } });  $.ajax({     url:'/api/C.json',     dataType:'json',     success:function(result){         console.log('第三次请求', result);     } });  console.log('OK');

△ 三个请求没有关联

而,咱的需求是:三个请求是串行的

异步执行代码 java 异步执行代码_json_02

△ 图2_晕不晕?绕不绕?

很久很久以前写代码,有时候的需求真得这么干:实现异步操作,并且串行的模式下,基本上都是回调函数嵌套着回调函数,实现非常恐怖的 回调地狱 => 看着头晕,写着头疼

为了不让自己头疼,大佬们就想着怎么治治这帮孩子的头疼呢?

Promise设计模式就是管理异步编程的

(2)Promise应用于异步请求

把三个请求封装成方法:

const apiA = () => {     return new Promise(resolve => {         $.ajax({             url: '/api/A.json',             dataType: 'json',             success(result) {                 resolve(result);             }         });     }); };  const apiB = () => {     return new Promise(resolve => {         $.ajax({             url: '/api/B.json',             dataType: 'json',             success(result) {                 resolve(result);             }         });     }); };  const apiC = () => {     return new Promise(resolve => {         $.ajax({             url: '/api/C.json',             dataType: 'json',             success(result) {                 resolve(result);             }         });     }); };

△ 用Promise请求数据,但是还没有调用

可以这样调用:

apiA().then(result => {     console.log('第一次请求', result);     return apiB(); }).then(result => {     console.log('第二次请求', result);     return apiC(); }).then(result => {     console.log('第三次请求', result);     console.log('OK'); });

△ 串行调用

异步执行代码 java 异步执行代码_异步执行代码 java_03

△ 图3_调用结果

也可以这样调用

(async function () {     let result = await apiA();     console.log('第一次请求', result);      result = await apiB();     console.log('第二次请求', result);      result = await apiC();     console.log('第三次请求', result);     console.log('OK'); })();

△ 调用结果跟上面的是一样的,串行

1 / Promise的语法

异步执行代码 java 异步执行代码_异步操作_04

△ 图4_直接这样写,会报错

要求new的时候,必须传一个函数进来才可以

异步执行代码 java 异步执行代码_json_05

△ 图5_new Promise是立即执行的

上图可知,new Promise的时候

1、 会立即执行传递executor函数

① 在executor函数中可以用来管控一个异步的操作(不写异步的也可以)

② 传递给executor函数两个参数:resolve, reject;这俩参数也是函数

异步执行代码 java 异步执行代码_jq each 异步执行_06

△ 图6_两个参数也是函数

2、创造Promise类的实例p1:

[[PromiseState]] 是promise的状态:

=> pending准备状态

=> fulfilled/resolve 成功(已兑现)

=> rejected 失败(已拒绝)

[[PromiseResult]]是promise值:默认是undefined,一般存储成功的结果或者失败的原因

p1.__proto__ => Promise.prototype有公共方法:then/catch/finally

异步执行代码 java 异步执行代码_jq each 异步执行_07

△ 图7_promise实例,PromiseState/PromiseResult 浏览器不一样名字也会不一样,但存储的值是一样的

(1)执行resolve函数

异步执行代码 java 异步执行代码_ajax_08

△ 图8_执行resolve函数

执行resolve控制实例的状态变为成功,传递的值100是成功的结果

① [[PromiseState]]:"fulfilled"

② [[PromiseResult]]:100

(2)执行reject函数

异步执行代码 java 异步执行代码_ajax_09

△ 图9_执行reject函数

执行reject控制实例的状态变为失败,并传递失败的原因是404【不影响代码执行】

① [[PromiseState]]:"rejected"

② [[PromiseResult]]:404

异步执行代码 java 异步执行代码_异步操作_10

△ 图10_失败态

如果executor函数中的代码报错,则实例的状态也会变为失败态:

① [[PromiseState]]:"rejected"

② [[PromiseResult]]:报错的原因

(3)resolve和reject俩函数都调用了

异步执行代码 java 异步执行代码_ajax_11

△ 图11_谁先执行谁说了算,说一不二

对于promise实例的状态和结果:resolve函数和reject函数,谁先执行谁说了算,另外一个就无效了

即:一旦状态从pending改变为fulfilled或者rejected,都无法再次改变状态了 promise是一个说一不二的主

2 / Promise如何管控异步

let p1 = new Promise(function executor(resolve, reject) {     //...COCE }); p1.then(onFulfilled, onRejected);

△ promise实例上的then方法:接收两个函数为参数

(1)没有宏任务时

let p1 = new Promise((resolve, reject)=>{     console.log(1);     resolve('ok');     console.log(2); });  p1.then(result =>{     console.log('成功->', result); }, reason =>{     console.log('失败->', result); }); console.log(3);

△ 没有宏任务,执行结果是?

异步执行代码 java 异步执行代码_异步执行代码 java_12

△ 图12_执行过程

代码执行顺序很重要

① new Promise

② 执行executor:通过执行resolve/reject来改变promise实例的状态和结果

=> 需要【将来通知】then方法的两个参数中的某一个执行

=> 此时,还没有执行到then方法,所以形参函数还没有被注入

=> 先把这个【通知】存起来

③执行p1.then(onFulfilled, onRejected) 将这两个方法注入【需要执行的微任务

④ 当同步任务执行完以后,去EventLoop里面找需要执行的微任务

=> 拿到【通知】,此时then方法的形参函数已经注入好了

=> 根据p1的状态来执行具体的函数

(2)有宏任务时

let p1 = new Promise((resolve, reject)=>{    // 在new Promise时,立即执行executor函数中管理了一个一个异步编程代码    // 此时状态是pending    // 当异步操作达到指定时间,开始执行时【理解为异步操作成功】    // 此时我们执行通过resolve,把promise状态修改为fulfilled,值:'Ok'    setTimeout(()=>{        resolve('OK');    }, 1000);});//=> 执行p1.then时,把将来需要执行的函数都注入好了p1.then(result =>{    // 当p1实例的状态修改为fulfilled的时候,通知传递的第一个函数执行    // result -> [[PromiseResult]]    console.log('成功->', result);}, reason =>{    // 当p1实例的状态修改为rejected的时候,通知传递的第二个函数执行    // reason -> [[PromiseResult]]    console.log('失败->', result);});

Promise 是如何管控异步编程的?

① new Promise 的时候创建一个promise实例,此时在executor函数中管理一套异步的代码

② 后面等异步操作成功或失败的时候,执行resolve/reject,以此控制promise实例的状态和结果

③ 根据状态和结果,就可以控制基于.then 注入的两个方法中的哪一个去执行了

必须要非常、非常、非常地清除代码执行的顺序

① new Promise

② 执行executor:设置一个异步定时器【宏任务】

③ 执行 p1.then注入两个方法【注入的方法保存起来】【微任务】

-----> 同步代码执行完了,EventLoop里面没有微任务,有宏任务

-----> 等待1000ms后

④ 执行定时器的回调函数:执行resolve改变promise状态和值【通知】

----> 去EventLoop找微任务

⑤ 通知之前基于.then注入的两个方法中的第一个执行

3 / 小结

1、Promise可以管控异步代码的执行

2、Promise是一个说一不二的主,有决策了,就不反悔

3、Promise变为失败态,有两种:

① 主动调用reject方法

② 报错了,比如:变量没有定义 resolve(a),这个a没有定义,promise实例的[[PromiseState]]:'rejected' [[PromiseResult]]:报错的原因

- end -