感觉自己在异步编程这一块掌握的还是不很好,然后决定今天开始认认真真学习一下这一块的知识点,一定要学会!!
最基本的回调函数的使用
1.1 回调函数加载图片
let loadImage = function(src,callback){
var img = new Image();img.src = src;img.onload = ()=>{
callback(img);};img.onerror = ()=>{
console.log("加载失败");}
}
let imageloadCallback = function(img){
document.body.appendChild(img);console.log("图片加载完成~");
}
loadImage("**",imageloadCallback);
1.2 定时器
let interval = function(callback,time=50){
let tag = setTimeInterval(callback,time);
}
1.3 回调地狱的产生:以加载文件为例
假设下列文件是有相互依赖的关系的话,就会产生层层的叠加=>回调地狱
let loadJs = function(src,callback){
let script = document.createElement("script");script.src = src;document.body.appendChild(script);script.onload = callback;
}loadJs("1.js",()=>{
console.log("1.js加载完成了");loadJS("2.js",()=>{
console.log("2.js加载完成了");loadJS("3.js",()=>{
console.log("3.js加载完成了");})})
})
Promise的使用
2.1 基本使用方法
new Promise((res,rej)=>{
res("value");// rej(new Erro("reason"));
}).then((value)=>{
console.log(value);
}).catch((reason)=>{
console.log(reason);
});
2.2 代码的同步和异步执行顺序
主线程代码(同步代码)->(微任务 & 宏任务)
以下是非常典型的两个例子:
console.log("主线程开始");let pro1 = new Promise((res,rej)=>{
console.log("同步任务");setTimeout(()=>{
console.log("宏任务")res();},0);}).then(()=>{
console.log('微任务回调');});console.log("主线程结束");//输出顺序 主线程开始 同步任务 主线程结束 红任务 微任务
setTimeout(()=>{
console.log("宏任务")},0);console.log("主线程开始");let pro1 = new Promise((res,rej)=>{
console.log("同步任务");res();}).then(()=>{
console.log('微任务回调');});console.log("主线程结束")//输出顺序 主线程开始 同步任务 主线程结束 微任务回调 宏任务
根据?两个例子可以知道,微任务并不是总是优先于红任务执行的,这主要是要根据判断微任务队列中是否有任务,第一个例子中因为微任务的产生依靠宏任务,所以出现了这样的结果。
2.2 单一状态和状态中转
在学习promise的过程中,这边出现了问题(等到后期修改解决一下)
var pro1 = new Promise((res,rej)=>{
rej(new Error("somethinr wrong with promise1"));
})
var pro2 = new Promise((res,rej)=>{
res(pro1);
})
pro2.then(()=>{
console.log("成功")}).catch(()=>{
console.log("失败")});
//结果是 失败
从这个例子可以看出这个pro2的状态完全依赖于pro1的状态,哪怕pro2中调用了resolve回调。
but~!
var pro1 = new Promise((res,rej)=>{
rej(new Error("somethinr wrong with promise1"));
}).then(()=>{
console.log("成功")}).catch(()=>{
console.log("失败")});
var pro2 = new Promise((res,rej)=>{
res(pro1);
})
pro2.then(()=>{
console.log("成功")}).catch(()=>{
console.log("失败")});
//结果是 失败 成功
暂时不是很理解为什么这里pro2的状态是成功~
2021.1.25 更新:因为pro1的状态已经确定了所以pro2的res调用其实就是简单的把pro1这个确定的对象传给了成功回调函数;而当pro1的状态还没有确定的时候,对于pro2的状态决定于pro1!
2.3 使用promise修改并对比回调函数加载图片的方法
let loadImage = function(src){
return new Promise((res,rej)=>{
let img = new Image();img.src = src;img.onload = ()=>{
res(img);}img.onerror = ()=>{
rej("加载失败");}})
}
loadImage('**').then((img)=>{
document.body.append(img);
})
Promise链式调用的结论
let p1 = new Promise((res,rej)=>{
res("成功");
});
p1.then(()=>{
return {
then(res,rej){
rej('链式调用的时候的错误');}};
}).catch(value=>{
console.log(value)});
手写promise
//-------------------------------------------class GCPromise{
constructor(excutor){
this.resolveList = [];this.rejectList = [];this.value = undefined;this.reason = undefined;let resolve = (input)=>{
this.value = input;while(this.resolveList.length!==0){
let fun = this.resolveList.shift();fun(this.value);}}let reject = (input)=>{
this.reason = input;while(this.rejectList.length!==0){
let fun = this.rejectList.shift();fun(input);}}excutor(resolve,reject);}then(onResolved,onrejected){
this.rejectList.push(onrejected);this.resolveList.push(onResolved);}}var p1 = new GCPromise((res,rej)=>{
setTimeout(()=>{
rej("sorry");},1000);}).then((res)=>{
console.log(res);},(reason)=>{
console.log(reason);});;//----------------------------------------------const PENDING = 'pending';const RESOLVE = 'fullfilled';const REJECT = 'rejected';class MyPromise{
constructor(executor){
this.resolveList = [];this.rejectList = [];this.status = PENDING;this.value = undefined;this.reason = undefined;let resolve = (val)=>{
if(this.status!==PENDING) return;this.status = RESOLVE;this.value = val;while(this.resolveList.length){
let fun = this.resolveList.shift();fun(this.value);}}let reject = (val)=>{
if(this.status!==PENDING) return;this.status = REJECT;this.reason = val;while(this.rejectList.length){
let fun = this.rejectList.shift();fun(this.reason);}}executor(resolve,reject);}then(onresolved,onrejected){
onresolved = typeof onresolved === 'function'? onresolved: value=>value;onrejected = typeof onrejected === 'function'? onrejected: value=>value;return new MyPromise((res,rej)=>{
let resolve = value=>{
try {
const x = onresolved(value);x instanceof MyPromise? x.then(res,rej):res(x);}catch(e){
rej(e);}}let reject = value=>{
try {
const x = onrejected(value);x instanceof MyPromise? x.then(res,rej):rej(x);}catch(e){
rej(e);}}if(this.status === PENDING){
this.resolveList.push(resolve);this.rejectList.push(reject);}else if(this.status === RESOLVE){
resolve(this.value);}else if(this.status === REJECT){
resolve(this.reason);}})}}new MyPromise((res,rej)=>{
setTimeout(()=>{
res(1);},1000);}).then((value)=>{
console.log(value);return 1;}).then((value)=>{
console.log(value);return 2;}).then((value)=>{
console.log(value);})
promise队列实现
5.1 map实现promise队列
let query = function(numList){
let promise1 = Promise.resolve();numList.map(x=>{
promise1 = promise1.then(value=>{
return new Promise((res,rej)=>{
setTimeout(()=>{
res(x);console.log(x);},1000);});})})}query([1,2,3,4,5]);
let queue = function(numList){
let promise1 = Promise.resolve();numList.map(x=>{
promise1 = promise1.then(value=>{
return x();})})}query([p1,p2,p3,p4]);
async await
这算是promise和generator的语法糖,写起来比较容易
使用方法有以下几种
1.
function yibu(){
return new Promise((res,rej)=>{
...res();//...rej();})
}
async function tongbu(){
let response = await yibu();return response;
}
tongbu().then((value)=>{
})...
class yibu{
constructor(name){
this.name = name;}then(res,rej){
res(this.name);}
}
async function tongbu(){
let response = await new yibu("gucheng");return response;
}
tongbu().then((value)=>{
})...
function yibu1(){
return new Promise((res,rej)=>{
setTimeout(()=>{
resolve("yibu1");},1000);})
}
function yibu2(){
return new Promise((res,rej)=>{
setTimeout(()=>{
resolve("yibu2");},1000);})
}
async function tonbu(){
let res1 = await yibu1();let res2 = await yibu2();
}