异步与promise
异步与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的处理
then中return的值(普通值)能被下一个then接收到
当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))
只要返回的对象有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
要终止,callback里要传递一个timerId
同时也需要改变promise状态,所以resolve也要暴露出去
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:
async函数会默认返回一个promise对象(默认为resolved状态)
不管函数内部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:
提取promise返回的内容,相当于then,可以理解为then的语法糖。
当等待的是一个promise的时候,它会阻塞程序的执行;
当等待非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));
用法总结
普通函数
对象
类
其实这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))
错误处理流程
async函数外部catch
函数内部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相关推荐
- JS - 15 - 异步、Promise、async、await
Promise 类似 java 的 Callable then 方法 类似 java 的 Future 下一篇: <JS - 16 - 任务调度.宏任务.微任务.轮询> PromiseA+ ...
- ES6中的异步对象Promise
回忆一下ES5中的怎么使用异步方法 // es5中的异步回调let ajax = function(callback){console.log('执行') // 执行setTimeout(() =&g ...
- 异步编程Promise、Generator和Async
在JavaScript的世界里,对于异步编程存在如下几种方案: 1.回调函数: 2.事件触发监听: 3.发布订阅者模式: 4.Promise. 首先介绍Promise,然后介绍ES6提供的生成器函数, ...
- 支付宝异步回调返回success_深入解决异步编程Promise对象的学习
1.什么是Promise 简单来说Promise是异步编程的一种解决方案 Promise是ES6中的特性. 什么是异步操作? 网络请求中,对端服务器处理需要时间,信息传递过程需要时间,不像我们本地调用 ...
- Asynchronous(异步处理-Promise)
为什么使用Promise?解决 更好的解决回调问题,减少嵌套:什么是Promise? 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息: Promise 必须为以下三种状态之一:等待 ...
- rust异步编程--理解并发/多线程/回调/异步/future/promise/async/await/tokio
1. 异步编程简介 通常我们将消息通信分成同步和异步两种: 同步就是消息的发送方要等待消息返回才能继续处理其它事情 异步就是消息的发送方不需要等待消息返回就可以处理其它事情 很显然异步允许我们同时做更 ...
- JavaScript异步函数Promise①——Promise筑基
期约是对尚不存在的一个替身.期约(promise)这个名字最早是由 Daniel Friedman和 David Wise在他们于 1976 年发表的论文"The Impact of App ...
- JavaScript 异步 setTimeout promise async await
异步在此就不再赘述,下面主要说一下JS中异步的实现方式. 1,setTimeout 计时器 ,实现代码如下 <!DOCTYPE html> <html lang="en&q ...
- JavaScript异步与Promise基本用法(resolve与reject)
Promise解决的问题 相信每个前端都遇到过这样一个问题,当一个异步任务的执行需要依赖另一个异步任务的结果时,我们一般会将两个异步任务嵌套起来,这种情况发生一两次还可以忍,但是发生很多次之后,就形成 ...
最新文章
- dom元素滚动条高度 js_DOM 事件与事件委托
- R语言使用t.test函数计算两组独立数据的t检验(Independent t-test)
- 数据类型与数据传送指令
- java io 输出流_Java IO 输入和输出流
- Windows 10 下 VS2017(+Clion) C/C++ 配置 OpenCV-4.4.0
- java 内存排序_详细解析Java内存,处理器重排序,编译器重排序以及它对线程的影响...
- The connection to adb is down, and a severe error has occured.问题解决方法小结
- Android中的数据库
- gin+vue的前后端分离开源项目
- 服务器之间远程拷贝scp
- 判断当前页面是否在微信浏览器中打开
- 简述dijkstra算法原理_路径规划算法(1)--Dijkstra和Floyd算法
- 浪潮服务器 虚拟光驱,玩转虚拟光驱:DAEMON TOOLS Pro
- 冲刺倒计时,复习核心是什么?
- 关于运行微信小程序报错 [微信小程序开发者工具] Error: read EBADF
- 实习期将近一月的找工作感想
- Linux 内核配置项详解 myimx6
- Visio2010中设置线为直线
- 信号采样基本概念 —— 1. 冲激函数
- OkHttp3基本使用