异步编程简述:
let obj = {};
let fs = require('fs');
fs.readFile('./data/name.txt', 'utf-8', (err, data) => {
obj.name = data;
Store.fire(obj);
});
fs.readFile('./data/number.txt', 'utf-8', (err, data) => {
obj.number = data;
Store.fire(obj);
});
fs.readFile('./data/score.txt', 'utf-8', (err, data) => {
obj.score = data;
Store.fire(obj);
});
let Store = {
list: [],
times: 3,
subscribe (func) {
this.list.push(func);
},
fire (...args) {
--this.times == 0 && this.list.forEach(ele=>{
ele.apply(null, args);
})
}
}
Store.subscribe(show);
function show (data) {
console.log(data);
}
复制代码
异步编程问题:
解决方案:
Promise(.then)
微任务和宏任务
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
复制代码
打印顺序是什么?javascript
正确答案是: ==script start, script end, promise1, promise2, setTimeout==java
微任务一般来讲就是须要在当前 task 执行结束后当即执行的任务,好比对一系列动做作出反馈,或或者是须要异步的执行任务而又不须要分配一个新的 task,这样即可以减少一点性能的开销。只要执行栈中没有其余的js代码正在执行且每一个宏任务执行完,微任务队列会当即执行。若是在微任务执行期间微任务队列加入了新的微任务,会将新的微任务加入队列尾部,以后也会被执行。微任务包括了mutation observe的回调还有接下来的例子promise的回调。node
一旦一个pormise有告终果,或者早已有告终果(有告终果是指这个promise到了fulfilled或rejected状态),他就会为它的回调产生一个微任务,这就保证了回调异步的执行即便这个promise早已有告终果。因此对一个已经有告终果的promise调用.then(yey, nay)会当即产生一个微任务。这就是为何‘promise1’,'promise2'会打印在‘script end’以后,由于全部微任务执行的时候,当前执行栈的代码必须已经执行完毕。‘promise1’,'promise2'会打印在‘setTimeout’以前是由于==全部微任务总会在下一个宏任务以前所有执行完毕。==ajax
.then的链式操做编程
// resolve 和 resolve是互斥事件
let oP = new Promise((resolve, reject)=> {
// 在构造函数中同步执行
console.log('123');
reject('aaa');
resolve('ddd');
});
oP.then((data)=> { // 被看成微任务
// 异步执行
// setTimeout 是宏任务
// 宏任务 微任务
// task queue 1 task queue 2
// 微任务有优先执行权
console.log(data);
return 20;
}, (reason)=>{
console.log(reason);
return 30;
}).then((data)=> {
console.log('ok then2 ' + data);
}, (reason)=> {
console.log('no then2 ' + reason);
});
// .then的链式操做
// 上一个不抛出错误的话, 那下一个then会默认执行成功回调函数, 抛出错误的话会执行失败回调函数
// 上一个then的返回至会做为下一个then注册函数的执行参数
// 上一个then返回一个Promise对象的话,后面的then就会成为这个对象的注册函数
复制代码
用解决回调地狱
回调地狱数组
// name.txt: ./data/number.txt
// number.txt: ./data/score.txt
// score.txt: 100
let fs = require('fs');
fs.readFile('./data/name.txt', 'utf-8', (err, data)=> {
console.log(data);
if(data) {
fs.readFile(data, 'utf-8', (err, data)=> {
console.log(data);
if(data) {
fs.readFile(data, 'utf-8', (err, data)=> {
console.log(data);
});
}
});
}
});
复制代码
使用Promise后promise
// name.txt: ./data/number.txt
// number.txt: ./data/score.txt
// score.txt: 100
let fs = require('fs');
function readFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
if (data) {
resolve(data);
}
});
});
}
readFile('./data/name.txt').then((data) => {
console.log(data);
return readFile(data);
}).then((data) => {
console.log(data);
return readFile(data);
}).then((data) => {
console.log(data);
});
// node运行结果
// ./data/number.txt
// ./data/score.txt
// 100
复制代码
.then .catch .finally
// 链式操做当遇到空的.then时,就当它不存在
let oP = new Promise((res, rej) => {
res();
});
oP.then(() => {
throw new Error('www');
}).then(() => {
}).catch((err)=>{
console.log(err);
// throw new Error('dasf');
return 10;
}).then((val)=>{
console.log('catch after ok:' + val); // 输出
},(reason)=>{
console.log('catch after no:' + reason) // 解开catch报错注释的时候输出
}).finally(()=>{
console.log('over');
});
复制代码
Promise.all()获取并发进程的结果 Promise.race() 赛跑
Promise.all能够将多个Promise对象实例包装成一个新的Promise实例浏览器
同时,成功和失败的返回至使不一样的,成功的时候返回的是一个结果数组失败的时候则返回最早被reject失败状态的值bash
// 在数组中的全部异步进程都成功执行后再回执行.then后的resolve 有一个进程不成功都只会执行reject
Promise.all([readFile('./data/number.txt'), readFile('./data/name.txt'), readFile('./data/score.txt')]).then((val) => {
console.log(val);
}, (reason)=> {
console.log('no');
})
复制代码
// race 赛跑 数组中的线程谁先成功 后面的then参数就是谁的返回值
Promise.race([readFile('./data/number.txt'), readFile('./data/name.txt'), readFile('./data/score.txt')]).then((val) => {
console.log(val);
}, (reason)=> {
console.log('no');
})
复制代码
MyPromise
执行并发
let oP = new MyPromise((res, rej) => {
res('ee');
});
oP.then((val)=> {
console.log(val,'ok')
return new MyPromise((res, rej)=>{
res(0);
});
},(reason)=>{
console.log(reason,'no');
return 12;
}).then(val=> {
console.log(val);
});
复制代码
MyPromise文件
function MyPromise(executor) {
var self = this;
self.status = 'pending'; // 状态
self.resolveValue = null;
self.rejectReason = null;
self.resolveCallBacksList = []; // 实如今执行函数中可使用异步例如setTimeout
self.rejectCallBacksList = []; //
function resolve(value) {
if (self.status === 'pending') {
self.status = 'Fulfilled';
self.resolveValue = value;
self.resolveCallBacksList.forEach((ele) => {
ele();
});
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'Rejected';
self.rejectReason = reason;
self.rejectCallBacksList.forEach((ele) => {
ele();
});
}
}
// 报错时的处理方法 全部执行用 try catch 包裹
try {
// 执行咱们在外界传入的函数, 将对象里的resolve, reject函数传进去, 在new一个新的Promise时, 本身定义的名字只是用来接收 有点绕?
executor(resolve, reject);
} catch (e) {
reject(e);
}
};
// 若是then的返回值是对象时的处理方式
function ResolutionReturnPromise(nextPromise, returnValue, res, rej) {
if(returnValue instanceof MyPromise) {
// Promise对象
returnValue.then(function (val) {
res(val);
}, function (reason) {
rej(reason);
})
}else {
res(returnValue);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
var self = this;
// 判断注册函数是否为空, 若是是true就返回如下函数 将返回值做为下一个then的参数
if (!onFulfilled) {
onFulfilled = function (val) {
return val;
}
}
if (!onRejected) {
onRejected = function (reason) {
return new Error(reason);
}
}
// 链式操做? new一个新的Promise时,里面的代码是同步执行的
var nextPromise = new MyPromise(function (res, rej) {
if (self.status === 'Fulfilled') { // 判断状态 下同
setTimeout(() => {
try {
var nextResolveValue = onFulfilled(self.resolveValue); // 执行注册函数并接收返回值
ResolutionReturnPromise(nextPromise, nextResolveValue, res, rej);
} catch (e) {
rej(e);
}
}, 0);
}
if (self.status === 'Rejected') {
setTimeout(() => {
try {
var nextRejectReason = onRejected(self.rejectReason);
ResolutionReturnPromise(nextPromise, nextRejectReason, res, rej);
} catch (e) {
rej(e);
}
}, 0);
}
if (self.status === 'pending') {
if (onFulfilled) {
self.resolveCallBacksList.push(function () {
setTimeout(() => {
try {
var nextResolveValue = onFulfilled(self.resolveValue);
ResolutionReturnPromise(nextPromise, nextResolveValue, res, rej);
} catch (e) {
rej(e);
}
}, 0);
});
}
if (onRejected) {
self.rejectCallBacksList.push(function () {
setTimeout(() => {
try {
var nextRejectReason = onRejected(self.rejectReason);
ResolutionReturnPromise(nextPromise, nextRejectReason, res, rej);
} catch (e) {
rej(e);
}
}, 0);
});
}
}
});
return nextPromise; // 返回一个Promise对象
}
MyPromise.all = function (promiseArr) {
return new MyPromise(function (resolve, reject) {
if(!Array.isArray(promiseArr)) {
return reject(new TypeError("argument must be anarray"));
}
var promiseArrValue = [];
promiseArr.forEach((promise, index) => {
promise.then((val)=>{
promiseArrValue.push(val);
if(index == promiseArr.length - 1) {
return resolve(promiseArrValue);
}
}, (reason)=>{
reject(reason);
})
});
});
}
复制代码