异步与promise

异步编程

多线程:多个任务同时执行

单线程:网络请求,任务队列

主线程对任务队列不断地轮询,有任务进来了就执行;就不会出现阻塞的问题

异步加载图片

图片加载是比较慢的,这个任务是耗时比较长的;主线程通过事件循环不断地轮询;

这段代码的逻辑:

代码执行到loadImg这个函数,我们交给一个文件处理模块,处理完之后,把任务放到任务队列里面;

轮询这个任务队列,如果图片加载任务执行完毕,那么就会执行回调;

把主线程全部完成之后,轮询遍历任务队列,把里面所有任务执行完;处理任务通过回调

function loadImg(src,resolve,reject){const img=new Image();img.src=src;img.onload=resolve;img.onerror=reject;
}
loadImg('xxx',()=>{console.log('图片加载完成');
},()=>{console.log('图片加载失败');
})

JS异步编程,回调函数与promise - susana123 - 博客园

定时器例子

任务交给定时器处理的模块,任务抛到任务队列里面,不断轮询任务队列读取任务开始执行;

主线程执行完就去任务队列找有没有新的任务,回调就会被执行;

有专门的的timer模块管理定时器,到时间时会将回调放到任务队列中,主线程执行完会去任务队列中执行任务;


function interval(callback,delay){let timerId=window.setInterval(()=>{callback(timerId);},delay)
}
interval((timerId)=>{const div=document.querySelector('div');const left=parseInt(window.getComputedStyle(div).left);div.style.left=left+10+'px';if(left>=200){window.clearInterval(timerId);interval((timerId)=>{const width=parseInt(window.getComputedStyle(div).width);div.style.width=width-10+'px';if(width<=30){clearInterval(timerId);}},50)}
},50)
// 如果主线程执行很长时间,还是会卡死
// 注意:还是等主线程执行完,才会轮询看这个任务队列
for(let i=0;i<20000;i++){console.log(i);
}
<body><div style="position:absolute;width:100px;height:100px;left:5px;background:green;"></div>
</body>

文件依赖加载

任务队列是谁先放进去的先干谁的活

function load(src,resolve){const script=document.createElement('script');script.src=src;script.onload=resolve;document.body.appendChild(script);
}
// 要注意:这2个是没有队列顺序的。 如果加载完了就抛任务,那就看这2个谁快了
// ps.如果这2个文件在不同的服务器上暴露的频率会更高一点
load('js/hd.js',()=>{hd();// 所以需要这样load('js/houdunren.js',()=>{houdunren();})
})
load('js/houdunren.js',()=>{houdunren();
})

ajax异步请求

通过http模块请求后台数据,之后往任务队列里面抛一个任务,主线程执行完后轮询任务集合,轮询之后就执行到相应回调。

这里的业务场景:如果请求之间存在依赖,必须要等待上一个请求结束之后才开始第二个请求

问题:回调会产生嵌套,即回调地狱

promise实例相关

pending状态 -》resolve/reject状态

.then是对状态的处理

微任务和宏任务的执行顺序

同步立刻执行

setTimeout放到任务队列里面准备执行

setTimeout(()=>{console.log('setTimout');
},0)
new Promise(resolve=>{resolve()console.log('promise')
}).then(()=> console.log('then 1'))
console.log('houdunren');

Promise构造函数代码也是同步的

then/catch是属于异步的,微任务队列

优先级:

同步>微任务>宏任务 eventloop

有个有点难度的例子:

这里宏任务执行了才有微任务,没执行前微任务没有创建,宏任务执行之后再创建的微任务

宏任务已经拿到主线程里面执行了之后再创建的微任务,需要再下一次轮询时再执行这个微任务


new Promise(resolve=>{setTimeout(()=>{resolve()console.log('setTimout');},0)console.log('promise')
}).then(()=> console.log('then 1'))
console.log('houdunren');

单一状态与状态中转

let p1=new Promise((resolve,reject)=>{setTimeout(()=>{reject('拒绝');// 上面已经设置了状态这一行是没有效果的// 状态是单向的不可逆的resolve('成功')},5000)
})
new Promise((resolve,reject)=>{// 这一行会产生微任务,下一次轮询时才会执行// resolve('fullfield');// 一定是要等待p1非pending状态才会中转resolve(p1);
}).then((msg)=>{console.log(msg)
},(error)=>{console.log(error);
})

ES6---Promise 3: Promise状态和状态中转 - jane_panyiyun - 博客园

异步编程——回调函数/Promise/Async/Await_顾承要加油啊的博客-CSDN博客

https://segmentfault.com/a/1190000023903564

then链

then是对上一个promise状态的处理,then返回的也是一个promise

let p1=new Promise((resolve,reject)=>{// resolve('fullfield')// 这里reject then后面也是成功reject('reject');
})
let p2=p1.then((msg)=>console.log(msg),(error)=>console.log(error))
.then(()=>console.log('成功'),()=>console.log('失败'))
console.log(p1);
console.log(p2);
setTimeout(()=>{console.log('---setTimeout');console.log(p1);console.log(p2);
})

then的返回值

后面then是对前面(上一个)返回的promise的处理

  1. then中return的值(普通值)能被下一个then接收到

  2. 当return一个promise时,对返回promise的处理

-pending状态会持续在等待它完成

new Promise((resolve,reject)=>{resolve('fullfield')
}).then((msg)=>{console.log(msg)  // return 'then 1 success'return new Promise((resolve,reject)=>{resolve('then 1 promise success')})
},error=>console.log(error))
.then((msg)=>{console.log(msg)
},error=>console.log(error))
  1. 只要返回的对象有then方法,同返回promise效果一样

看原型中有没有then方法

new Promise((resolve,reject)=>{resolve('fullfield')
}).then((msg)=>{console.log(msg)  return new Promise((resolve,reject)=>{resolve('then 1 promise success')})// 1.返回一个有then方法的对象return {then(resolve,reject){resolve('abc')}}// 2.返回一个new MyPromise()实例class MyPromise{then(resolve,reject){resolve('abc')}}return new MyPromise();// 3.返回一个有static方法的类class MyPromise1{static then(resolve,reject){resolve('abc')}}return MyPromise1;
},error=>console.log(error))
.then((msg)=>{console.log(msg)
},error=>console.log(error))

封装ajax

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET',url);xhr.send();xhr.onload=function(){if(this.status===200){resolve(JSON.parse(this.response));}else{reject('加载失败')}}xhr.onerror=function(){reject(this);}})
}
ajax('xxx')
.then(user=> ajax(`xxx${user.id}`))
// 第2个处理错误的情况
// 把错误处理放在最后一个then,让它沿着then链一直找到顶级
.then((lessons)=> console.log(lessons),error=>console.log(error))

JavaScript中的promise的then()方法以及链式调用_Fighting社火底子-CSDN博客_promise.then链式调用

ES6 Promise对象then方法链式调用 - 后除 - 博客园

错误处理

promise对错误还是挺完善的:

不管是抛出错误还是系统级的语法错误,它也都能捕获到

使用catch统一对错误进行处理,并且是把它放到最后

如果之前你已经捕获特殊处理了,那就走你的错误回调

new Promise((resolve,reject)=>{reject(new Error('error'))// 抛出的错误还是系统判定错误// throw new Error('throw error')// hd + 1;
})
.then(value => console.log(value))
.then(value => console.log(value))
// 把catch放在最后
.catch(error => console.log(error))

自定义错误

class ParamError extends Error{constructor(message){super(message)this.name='ParamError';}
}
class HttpError extends Error{constructor(message){super(message)this.name='HttpError';}
}
function ajax(url){return new Promise((resolve,reject)=>{if(!/request$/.test(url)){throw new ParamError('请求url错误')}const xhr=new XMLHttpRequest();xhr.open('GET',url);xhr.send();xhr.onload=function(){if(this.status===200){resolve(JSON.parse(this.response));}else if(this.status === 404){reject(new HttpError('404未找到'))}else{reject('加载失败')}}xhr.onerror=function(){reject(this);}})
}
ajax('request')
.then(user=> ajax(`xxx${user.id}`))
// 第2个处理错误的情况
// 把错误处理放在最后一个then,让它沿着then链一直找到顶级
.then((lessons)=> console.log(lessons))
.catch(error=>{if(error instanceof ParamError){console.log(error.message);}if(error instanceof HttpError){alert(error.message);}
})

使用finally做加载效果

finally永远都会执行

ajax('xxx')
.then(user=> ajax(`xxx${user.id}`))
.finally(() => loading=false;)

封装异步加载图片

function loadImg(src){return new Promise((resolve,reject)=>{const img=new Image()img.src=src;img.onload=()=>{resolve(img)}img.onerror=reject})
}loadImg('http://cdn.jsrun.top/css/img/ds_2.jpg').then((img)=>{document.body.appendChild(img);
}).catch((error)=>console.log(error))

封装setTimout

function timeout(delay){return new Promise(resolve=>{setTimeout(()=>{resolve();},delay)})}
timeout(3000).then(()=>{console.log('3ms is over');return timeout(3000)
}).then(()=>{console.log('3ms again');
})

封装setInterval

  1. 要终止,callback里要传递一个timerId

  2. 同时也需要改变promise状态,所以resolve也要暴露出去

  3. resolve(div)

每一步是一个then方法,使用promise使得代码更加扁平化,避免了嵌套

function interval(callback,delay){return new Promise(resolve=>{let timerId=window.setInterval(()=>{// 把resolve传递出去callback(timerId,resolve);},delay)})
}const div=document.querySelector('div');
interval((timerId,resolve)=>{const left=parseInt(window.getComputedStyle(div).left);div.style.left=left+10+'px';if(left>=200){window.clearInterval(timerId);resolve()}
},50).then(timerId=>{return interval((timerId,resolve)=>{const width=parseInt(window.getComputedStyle(div).width);div.style.width=width-10+'px';if(width<=30){clearInterval(timerId);resolve(div)}},50)
}).then(div=>{div.style.background='red';
})

封装script文件加载

function load(src){return new Promise((resolve,reject)=>{const script=document.createElement('script');script.src=src;script.onload=()=>resolve(script);script.onerror=reject;document.body.appendChild(script);})}load('js/hd.js')
.then(()=>{hd();return load('js/houdunren.js')
})
.then(()=> houdunren() )
.catch(()=>{})

Promise全局API

Promise.resolve

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET',url);xhr.send();xhr.onload=function(){if(this.status===200){resolve(JSON.parse(this.response));}else{// reject('加载失败')resolve('abc');}}xhr.onerror=function(){reject(this);}})
}
function query(){const cache=query.cache || (query.cache=new Map());if(cache.has('user')){console.log('走cache')return Promise.resolve(cache.get('user'))}return ajax('xxx').then(value=>{console.log('调接口')cache.set('user',value);return value;})
}
query().then(value=>{console.log(value);
})
setTimeout(()=>{
query().then(value=>{console.log(value);
})
},1000)

Promise.reject

返回一个reject状态的promise

更改状态

new Promise((resolve,reject)=>{resolve('fullfield');
}).then((value)=>{if(value!=='success'){// throw new Error('error');return Promise.reject('rejectd')}
}).catch(value=>console.log(value))

Promise.all

语法:Promise.all([ promise ]).then( ... )

全部promise状态均为resolved状态才可以then

const p1=new Promise(resolve=>{setTimeout(()=> resolve('p1'),1000)
})
const p2=new Promise(resolve=>{setTimeout(()=> resolve('p2'),2000)
})
Promise.all([p1,p2]).then(value=>console.log(value));

function ajax(){return new Promise(resolve=>resolve());
}function getUsers(names){// 这里是一个promise数组const promises= names.map(name=>{return ajax(`xxx${name}`)})return Promise.all(promises);
}
getUsers(['user1','user2']).then(users=>console.log(users));

Promise.allSettled

语法结构和Promise.all一致,不同的是:

不管resolve还是reject都会接收,返回的结果为[ { status:xxx, value:xxx } ]

const p1=new Promise((resolve,reject)=>{setTimeout(()=> reject('p1'),1000)
})
const p2=new Promise(resolve=>{setTimeout(()=> resolve('p2'),2000)
})
Promise.allSettled([p1,p2]).then(value=>console.log(value));

Promise.race

哪个promise返回得最快,就获得哪个的结果

取返回的最快的那个promise的结果

let p1=new Promise(resolve=>{setTimeout(()=>{resolve('fullfield')},1000);
})
let p2=new Promise((resolve,reject)=>{setTimeout(()=>{reject('rejected')},3000);
})
Promise.race([p1,p2]).then(value=>console.log(value))
.catch(value=>console.log(value));

做请求超时的例子

function ajax(){ /* ... */ }
function query(url,delay){let promises=[ajax(url),new Promise((resolve,reject)=>{setTimeout(()=>{reject('请求超时')},delay)})]return Promise.race(promises);}
query('xxx',2000)
.then(value=>console.log(value))
.catch(value=>console.log(value));

Promise队列

队列的例子

在then中又返回了一个promise,就会形成一条链

队列中的每个成员都是一个promise,下一个成员是依赖于上一个成员的状态改变

let promise=new Promise(resolve=>{setTimeout(()=>{resolve('promise 1')},1000)
})
promise=promise.then(value=>{console.log(value);return new Promise(resolve=>{setTimeout(()=>{resolve('promise 2')},2000)})
})
promise=promise.then(value=>{console.log(value);return new Promise(resolve=>{setTimeout(()=>{resolve('promise 3')},2000)})
})
promise.then(value=>{console.log(value);
})

使用map封装promise队列

在then中返回promise时就会实现队列的操作:得等前面的完成再走后面的

把promise.then返回的promise赋给自己,依次往下进行传递

function queue(arr){let promise=Promise.resolve()arr.map((v,index)=>{console.log(index);console.log(promise);// promise.then返回的promise赋值给自己,依次往下进行传递promise=promise.then(()=>{return new Promise(resolve=>{setTimeout(()=>{console.log(v)resolve()},1000);})})})
}
queue([1,2,3,4,5])
function queue(arr){let promise=Promise.resolve()arr.map((v)=>{promise=promise.then(()=>{// 这里也要加上returnreturn v();})})
}
function p1(){return new Promise(resolve=>{setTimeout(()=>{console.log(1);resolve()},1000)})
}
function p2(){return new Promise(resolve=>{setTimeout(()=>{console.log(2);resolve()},1000)})
}
queue([p1,p2])

使用reduce封装队列

function queue(arr){let promise=Promise.resolve()arr.reduce((promise,v)=>{return promise.then(()=>{return new Promise(resolve=>{setTimeout(()=>{console.log(v)resolve()},1000);})})},promise)
}
queue([1,2,3,4,5])

扩展一下reduce的用法

JS数组reduce()方法详解及高级技巧 - 简书

let arr=['alice','angela','angela','tom'];
// 计算次数
const obj=arr.reduce((obj,cur)=>{if(obj[cur]){obj[cur]++;}else{obj[cur]=1;}return obj;
},{})
console.log(obj);
// 数组去重
const newArr=arr.reduce((newArr,cur)=>{if(!newArr.includes(cur)){newArr.push(cur);}return newArr;
},[])
console.log(newArr);

使用队列来渲染数据

class User{render(users){users.reduce((promise,user)=>{return promise.then((resolve)=>{return this.ajax('xxx',user)}).then((user)=>{// 这里user接收上一个promise resolve的user信息return this.view(user)})},Promise.resolve())}ajax(url,name){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET',url);xhr.send();xhr.onload=function(){// if(this.status===200){//     resolve(name);// }else{//     reject('加载失败')// }resolve(name);}xhr.onerror=function(){reject(this);}})}view(user){return new Promise(resolve=>{setTimeout(()=>{let h2=document.createElement('h2');h2.innerHTML=user;document.body.appendChild(h2);resolve()},1000)})}
}
new User().render(['Angela','Tom'])

async/await

基础语法部分

async:

  1. async函数会默认返回一个promise对象(默认为resolved状态)

  2. 不管函数内部return的是什么,都会将其包装成promise对象

async function asyncFunc(){return 'hello async';
}
console.log(asyncFunc());
asyncFunc().then(value=>console.log(value));async function asyncFunc1(){return new Promise(resolve=>{setTimeout(()=>{resolve(1)},1000)});
}
console.log(asyncFunc1());
asyncFunc1().then(value=>console.log(value));

JavaScript中的async/await详解 - #Empty - 博客园

JS中的async/await的用法和理解 - 曼施坦因 - 博客园

await:

  1. 提取promise返回的内容,相当于then,可以理解为then的语法糖。

当等待的是一个promise的时候,它会阻塞程序的执行;

  1. 当等待非promise时,则会按照同步程序返回值处理;

//  await 关键字 只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值
// 如果await 后面并不是一个Promise的返回值,则会按照同步程序返回值处理,为undefined
const bbb = function(){ return 'string'}async function funAsy() {const a = await 1console.log(a);const b = await new Promise((resolve, reject)=>{setTimeout(function(){resolve('time')}, 3000)})const c = await bbb()console.log(a);console.log(b);console.log(c);
}funAsy()  //  运行结果是 3秒钟之后 ,输出 1, time , string,

async / await:

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET',url);xhr.send();xhr.onload=function(){// if(this.status===200){//     resolve(JSON.parse(this.response));// }else{//     reject('加载失败')// }resolve('fullfield');}xhr.onerror=function(){reject(this);}})
}
async function get(user){let id = await ajax('xxx');let lessons = await ajax('xxx');console.log(lessons);
}
get('Tom');

休眠函数例子

promise状态改变之前await会阻塞程序执行

function sleep(delay=2000){return new Promise(resolve=>{setTimeout(()=>{resolve();},delay)})
}
async function show(){for(const name of ['angela','tom']){await sleep();console.log(name);}
}
show();
// let i=0;
// const arr=['angela','tom']
// do{
//     await sleep();
//     console.log(arr[i]);
// }while(i<arr.length)

进度条例子

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET','xxx');xhr.send();xhr.onload=function(){// if(this.status===200){//     resolve(JSON.parse(this.response));// }else{//     reject('加载失败')// }setTimeout(()=>{resolve()},1000)}xhr.onerror=function(){reject(this);}})
}
async function getUsers(users){console.log(users);for(let i=0;i<users.length;i++){await ajax()let div=document.querySelector('.progress');let progress=Math.round((i+1)/users.length*100)console.log(progress);div.style.width=progress+'%';}
}
getUsers(['angela','tom','tonny','baby']);

class与async/await

如果一个类里面有then方法,会包装成promise

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET','xxx');xhr.send();xhr.onload=function(){// if(this.status===200){//     resolve(JSON.parse(this.response));// }else{//     reject('加载失败')// }setTimeout(()=>{resolve('xmlhttprequest')},1000)}xhr.onerror=function(){reject(this);}})
}
class User{constructor(name){this.name=name;}then(resolve,reject){// let promise = ajax('xxx');// resolve(promise)ajax('xxx').then(value=>resolve(value))}}
async function test(){let user = await new User()console.log(user);
}
test();class Sample{then(resolve,reject){resolve('sample xxx')}
}
async function print(){let value=await new Sample();console.log(value)
}
print();

封装在类内部的async函数

function ajax(url){return new Promise((resolve,reject)=>{const xhr=new XMLHttpRequest(); xhr.open('GET','xxx');xhr.send();xhr.onload=function(){// if(this.status===200){//     resolve(JSON.parse(this.response));// }else{//     reject('加载失败')// }setTimeout(()=>{resolve('xmlhttprequest')},1000)}xhr.onerror=function(){reject(this);}})
}
class User{async get(name){let user = await ajax();user += '-houdunren.com'return user;}
}
new User().get().then(value=>console.log(value));

用法总结

  1. 普通函数

  2. 对象

其实这3种是一种,只是换了表达形式而已

// 1.普通函数
async function test(){// 这里要return一下。await拿到的是promise返回的结果return await new Promise(resolve=>{setTimeout(()=>{resolve('abc')},1000)})// console.log(value);// return value;
}
test().then(value=>console.log(value))
// 2.对象中
let hd={async test(){// 这里要return一下。await拿到的是promise返回的结果return await new Promise(resolve=>{setTimeout(()=>{resolve('abc')},1000)})}
}
hd.test().then(value=>console.log(value))
// 3.类中实例的方法
class Hd{async test(){// 这里要return一下。await拿到的是promise返回的结果return await new Promise(resolve=>{setTimeout(()=>{resolve('abc')},1000)})}
}
new Hd().test().then(value=>console.log(value))

基本错误处理


async function test(){// 这里要return一下。await拿到的是promise返回的结果return await new Promise((resolve,reject)=>{reject('error occurred');setTimeout(()=>{// resolve('abc')},1000)})// console.log(value);// return value;
}
// 因为async函数返回的是promise,所以错误处理同promies
test().then(value=>console.log(value)).catch(error=>console.log(error))

错误处理流程

  1. async函数外部catch

  2. 函数内部try-catch代码块。若有多个await可以放到try-catch里面

发生错误时,后面的代码是不会执行的;

有错误都要处理


async function test(){// 这里要return一下。await拿到的是promise返回的结果return await new Promise((resolve,reject)=>{reject('error occurred');setTimeout(()=>{// resolve('abc')},1000)})// console.log(value);// return value;
}
// 因为async函数返回的是promise,所以错误处理同promies
// test().then(value=>console.log(value)).catch(error=>console.log(error))async function test1(){try{await new Promise((resolve,reject)=>{reject('error occurred');})await new Promise((resolve,reject)=>{reject('error reoccurred');})console.log('abc');}catch(error){console.log(error)}}
test1();

await并行

function h1(){return new Promise(resolve=>{setTimeout(()=>{resolve('h1');},2000)})
}
function h2(){return new Promise(resolve=>{setTimeout(()=>{resolve('h2');},2000)})
}
// promise.all方法
async function test(){let res = await Promise.all([h1(),h2()])console.log(res);
}
test();
// 一般方法
async function test1(){let p1=h1();let p2=h2();let h1value=await p1;let h2value=await p2;console.log(h1value);console.log(h2value);
}
test1();

异步与promise相关推荐

  1. JS - 15 - 异步、Promise、async、await

    Promise 类似 java 的 Callable then 方法 类似 java 的 Future 下一篇: <JS - 16 - 任务调度.宏任务.微任务.轮询> PromiseA+ ...

  2. ES6中的异步对象Promise

    回忆一下ES5中的怎么使用异步方法 // es5中的异步回调let ajax = function(callback){console.log('执行') // 执行setTimeout(() =&g ...

  3. 异步编程Promise、Generator和Async

    在JavaScript的世界里,对于异步编程存在如下几种方案: 1.回调函数: 2.事件触发监听: 3.发布订阅者模式: 4.Promise. 首先介绍Promise,然后介绍ES6提供的生成器函数, ...

  4. 支付宝异步回调返回success_深入解决异步编程Promise对象的学习

    1.什么是Promise 简单来说Promise是异步编程的一种解决方案 Promise是ES6中的特性. 什么是异步操作? 网络请求中,对端服务器处理需要时间,信息传递过程需要时间,不像我们本地调用 ...

  5. Asynchronous(异步处理-Promise)

    为什么使用Promise?解决 更好的解决回调问题,减少嵌套:什么是Promise? 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息: Promise 必须为以下三种状态之一:等待 ...

  6. rust异步编程--理解并发/多线程/回调/异步/future/promise/async/await/tokio

    1. 异步编程简介 通常我们将消息通信分成同步和异步两种: 同步就是消息的发送方要等待消息返回才能继续处理其它事情 异步就是消息的发送方不需要等待消息返回就可以处理其它事情 很显然异步允许我们同时做更 ...

  7. JavaScript异步函数Promise①——Promise筑基

    期约是对尚不存在的一个替身.期约(promise)这个名字最早是由 Daniel Friedman和 David Wise在他们于 1976 年发表的论文"The Impact of App ...

  8. JavaScript 异步 setTimeout promise async await

    异步在此就不再赘述,下面主要说一下JS中异步的实现方式. 1,setTimeout 计时器 ,实现代码如下 <!DOCTYPE html> <html lang="en&q ...

  9. JavaScript异步与Promise基本用法(resolve与reject)

    Promise解决的问题 相信每个前端都遇到过这样一个问题,当一个异步任务的执行需要依赖另一个异步任务的结果时,我们一般会将两个异步任务嵌套起来,这种情况发生一两次还可以忍,但是发生很多次之后,就形成 ...

最新文章

  1. dom元素滚动条高度 js_DOM 事件与事件委托
  2. R语言使用t.test函数计算两组独立数据的t检验(Independent t-test)
  3. 数据类型与数据传送指令
  4. java io 输出流_Java IO 输入和输出流
  5. Windows 10 下 VS2017(+Clion) C/C++ 配置 OpenCV-4.4.0
  6. java 内存排序_详细解析Java内存,处理器重排序,编译器重排序以及它对线程的影响...
  7. The connection to adb is down, and a severe error has occured.问题解决方法小结
  8. Android中的数据库
  9. gin+vue的前后端分离开源项目
  10. 服务器之间远程拷贝scp
  11. 判断当前页面是否在微信浏览器中打开
  12. 简述dijkstra算法原理_路径规划算法(1)--Dijkstra和Floyd算法
  13. 浪潮服务器 虚拟光驱,玩转虚拟光驱:DAEMON TOOLS Pro
  14. 冲刺倒计时,复习核心是什么?
  15. 关于运行微信小程序报错 [微信小程序开发者工具] Error: read EBADF
  16. 实习期将近一月的找工作感想
  17. Linux 内核配置项详解 myimx6
  18. Visio2010中设置线为直线
  19. 信号采样基本概念 —— 1. 冲激函数
  20. OkHttp3基本使用

热门文章

  1. TP5.1使用创蓝短信实现验证码的发送以及频控
  2. 2个专业的c语言学时不同,C语言教学大纲(48学时)
  3. 百度API加载离线百度电子地图和卫星切片
  4. 编译原理 赋值语句翻译成四元式
  5. 如何检索论文时让两个词在一块而不是分开?
  6. isolar bsw配置工具的基本配置CanIf
  7. 【Jquery手风琴】
  8. 华云大咖说 | 安超ArSDN云安全场景方案
  9. 微信小程序中如何引用weUI(踩坑记录)
  10. MATLAB绘制SOI指数