異步編程簡述:
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);
})
});
});
}
複製代碼