這種不連續的執行,就叫作異步。相應地,連續的執行,就叫作同步。javascript
函數做爲一等公民,能夠做爲參數和返回值,也能夠做爲函數的參數html
// 判斷一個參數是不是字符串
function isString(param){
return Object.prototype.toString.call(param) == '[object String]';
}
isString(123);
// 判斷一個參數是不是數組
function isArray(param){
return Object.prototype.toString.call(param) == '[object Array]';
}
isArray([]);
複製代碼
函數能夠做爲返回值java
function isType(type){
return function(param){
return Object.prototype.toString.call(param) == `[object ${type}]`;
}
}
let isString = isType('String');
let isArray = isType('Array');
console.log(isString({}))
console.log(isArray([]))
複製代碼
函數能夠做爲參數傳到另一個函數裏面node
function eat(){
console.log("吃完了")
}
// 讓他執行幾回纔會執行
function after(times,fn){
let count = 0;
return function(){
if(count++==times){
fn();
}
}
}
let newEat = after(3,eat);
newEat();
newEat();
newEat();
複製代碼
好比我如今要讀取一個文件,異步讀取編程
let fs = require('fs');
fs.readFile('./1.txt','utf8',function(err,data){
if(err){ // 若是err有值,就表示程序出錯
console.log(err);
}else{ // 若是err爲空就表示成功沒有錯誤
console.log(data);
}
});
複製代碼
回調函數的問題數組
function read(filename){
fs.readFile(filename,'utf8',function(err,data){
if(err){ // 若是err有值,就表示程序出錯
console.log(err);
}else{ // 若是err爲空就表示成功沒有錯誤
console.log(data);
}
});
}
try{
read('1.txt');
}catch(e){
console.log(e);
}
console.log(2);
複製代碼
當你訪問服務器的時候,好比請求一個html頁面,好比用戶列表。服務器一方面會去讀取模板文件,多是ejs、pug、jade、handlebar、另一方面還要讀取數據(可能會放在文件裏,也能夠會放在數據裏),它們都很慢,因此都是異步的.promise
fs.readFile('./template.txt','utf8',function(err,template){
fs.readFile('./data.txt','utf8',function(err,data){
console.log(template+''+data);
})
})
複製代碼
如何解決這個回調嵌套的問題瀏覽器
// 這node核心模塊中一個類,經過它能夠穿件時間發射器的實例,裏面有兩個核心方法
// 一個叫on emit,on表示註冊監聽,emit表示發射事件
let EventEmitter = require('events');
let eve = new EventEmitter();
// 這個html對象是存放
let html = {}; // template data
// 監聽數據獲取成功事件,當事件發生以後調用回調函數
eve.on('ready',function(key,value){
html[key] = value;
if(Object.key(html).lenght==2){
console.log(html);
}
})
fs.readFile('./template.txt','utf8',function(err,template){
// 1事件名 2參數日後是傳遞給回調函數的參數
eve.emit('ready','template',template);
})
fs.readFile('./data.txt','utf8',function(err,data){
//
eve.emit('ready','data',data);
})
複製代碼
// 經過一個哨兵來解決
let html = {}
function done(key,value){
html[key]=value;
if(Object.keys(html).length===2){
console.log(html);
}
};
fs.readFile('./template.txt','utf8',function(err,template){
done("template",data)
})
fs.readFile('./data.txt','utf8',function(err,data){
done("data",data)
})
複製代碼
// 經過一個哨兵來解決
let html = {}
function render(lenght,cb){
let html = {};
if(Object.keys(html).length===lenght){
cb(html);
}
}
let done = render(2,function(html){
console.log(html);
});
fs.readFile('./template.txt','utf8',function(err,template){
done("template",data)
})
fs.readFile('./data.txt','utf8',function(err,data){
done("data",data)
})
複製代碼
生成器是一個函數,能夠用了生成迭代器
生成器函數和普通函數不同,普通函數一旦調用必定會執行完
可是生成器函數中間能夠展廳,能夠執行一會歇一會服務器
生成器函數有一個特色,須要加個* 生成器有若干個階段,如何劃分這些階段呢 yield 定義經過迭代器協議從生成器函數返回的值。若是省略,則返回undefined。網絡
function *go(params) {
console.log(1);
// 此處的b是提供外界輸入進來
// 這一行實現輸入和輸出,本次的輸出放在yield後面,下次的輸入放在yield前面
let b = yield 'a';
console.log(2);
let c = yield b;
console.log(3);
return c;
}
// 生成器函數和普通函數的函數不同,調用它的話,函數並不會馬上執行
// 它會返回生成器的迭代器,迭代器是一個對象,每調用一次next就能夠返回一個值對象
let it = go();;
let r1 = it.next();
// 第一次調用next返回一個對象,此對象有兩個屬性,一個value就是yield後面那個值,一個是done表示是否迭代完成
console.log(r1); //{value:'a',done:false};
// next 第一次執行不須要傳參,傳參是沒有意義的
let r2 = it.next('B值');//傳給了b
console.log(r2); // {value:'a',done:false};
let r3 = it.next();// {value:undefined,done:true};
console.log(r3);
複製代碼
Promise 對象是一個代理對象(代理一個值),被代理的值在Promise對象建立時多是未知的。它容許你爲異步操做的成功和失敗分別綁定相應的處理方法(handlers)。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1000)
}, 1000);
});
p1.then(res=>{
console.log(res)
})
複製代碼
會接收到promise數組,若是promise所有完成了這個,promise纔會成功,若是有一個失敗,總體就失敗了
同時異步請求多個數據的時候,會用all
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1000)
}, 1000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1000)
}, 1000);
});
Promise.all([p1,p2]).then(res=>{
console.log('====================================');
console.log(res);
console.log('====================================');
},err=>{
console.log('====================================');
console.log(err);
console.log('====================================');
})
複製代碼
原理
function gen(times,cb) {
let result = [],count=0
return function(i,data){
result[i] = data;
if (++count == times) {
cb(result);
}
}
}
Promise.alls = function (promises) {
return new Promise(function (resovle, reject) {
let result = []
let count =0
let done = gen(promises.length,resovle)
// function done(i,data){
// result[i] = data;
// if (++count== promises.length) {
// resovle(result)
// }
// }
for (let i = 0; i < promises.length; i++) {
// promises[i].then(done.bind(null,i));
promises[i].then(function (data) {
done(i,data)
}, reject);
}
})
}
Promise.alls([p1,p2]).then(res=>{
console.log('====================================');
console.log(res);
console.log('====================================');
},error=>{
console.log('====================================');
console.log(error);
console.log('====================================');
})
複製代碼
會接收到一個promise數組,只要一個成功,則就成功了,只有一個失敗就是失敗了
當你有三個接口都不穩定,可你能夠同時請求三個接口,誰先回來用誰的
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1000)
}, 1000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1000)
}, 1000);
});
Promise.race([p1,p2]).then(res=>{
console.log('====================================');
console.log(res);
console.log('====================================');
})
複製代碼
原理
Promise.race = function (promises) {
return new Promise(function (resovle, reject) {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resovle, reject);
}
})
}
複製代碼
co是一個爲Node.js和瀏覽器打造的基於生成器的流程控制工具,藉助於Promise,你可使用更加優雅的方式編寫非阻塞代碼。
let fs = require('fs');
function readFile(filename) {
return new Promise(function (resolve, reject) {
fs.readFile(filename, function (err, data) {
if (err)
reject(err);
else
resolve(data);
})
})
}
function *read() {
let template = yield readFile('./template.txt');
let data = yield readFile('./data.txt');
return template + '+' + data;
}
co(read).then(function (data) {
console.log(data);
}, function (err) {
console.log(err);
});
複製代碼
function co(gen) {
let it = gen();
return new Promise(function (resolve, reject) {
!function next(lastVal) {
let {value, done} = it.next(lastVal);
if (done) {
resolve(value);
} else {
value.then(next, reason => reject(reason));
}
}();
});
}
複製代碼
使用
async
關鍵字,你能夠輕鬆地達成以前使用生成器和co函數所作到的工做 可是實際上是它,只要generator+promise語法
Async的優勢
async function timeout() {
return 'hello world'
}
timeout().then(res=>{
console.log(res);
})
console.log('雖然在後面,可是我先執行');
複製代碼
async 返回是一個 promise
舉一個例子
function loading(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000);
} )
}
// 這是一個函數構造器
複製代碼
這時候我想傳入三個值30、50、40 經過計算後求和。 延遲的時間模擬網絡請求時間
async function testResult() {
let one = await loading(30);
let two = await loading(50);
let three = await loading(40);
console.log(one + two + three);
}
testResult();
複製代碼