異步編程(回調函數,promise)


一、回調函數

概念:一般情況下,程序會時常通過API調用庫里所預先備好的函數。但是有些庫函數卻要求應用先傳給它一個函數,好在合適的時候調用,以完成目標任務。這個被傳入的、后又被調用的函數就稱為回調函數(callback function),也就是一個函數作為另外一個函數的參數使用。如果需要得到一個函數內部的異步操作的結果,這時候必須通過回調函數來獲取。

②推導:

 

③數組遍歷中使用的回調函數

  • every() 方法測試數組的所有元素是否都通過了指定函數的測試
function isBelowThreshold(currentValue) {
    return currentValue < 40;
  }
  var array1 = [1, 30, 39, 29, 10, 13];
  console.log(array1.every(isBelowThreshold));//  true
  • forEach() 方法對數組的每個元素執行一次提供的函數
var array1 = ['a', 'b', 'c'];
array1.forEach(function(element) {
  console.log(element);
});
// expected output: "a"
// expected output: "b"
// expected output: "c"
  • some() 方法測試數組中的某些元素是否通過由提供的函數實現的測試
var array = [1, 2, 3, 4, 5];
var even = function(element) {
  // checks whether an element is even
  return element % 2 === 0;
};
console.log(array.some(even));
// expected output: true
  • includes() 方法用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則返回 true,否則返回false
var array1 = [1, 2, 3];
console.log(array1.includes(2));
// expected output: true
  • map() 方法創建一個新數組,其結果是該數組中的每個元素都調用一個提供的函數后返回的結果
var array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
  •  reduce() 方法對累加器和數組中的每個元素(從左到右)應用一個函數,將其減少為單個值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
console.log(array1.reduce(reducer));
// 1 + 2 + 3 + 4
// expected output: 10

console.log(array1.reduce(reducer, 5));
// 5 + 1 + 2 + 3 + 4
// expected output: 15

④ajax請求里使用回調函數

function get(url,callback){
    var oReq=new XMLHttpRequest()
    // 當請求加載成功以后要調用指定的函數
    oReq.onload=function(){
        // 現在需要得到這里的oReq.oReq.responseText
        callback(oReq.responseText)
    }
    oReq.open('get',url,true)
    oReq.send()
}
get('data.json',function(data){
    console.log(data)
})

⑤ES6的find和findindex方法

// find() 方法返回數組中滿足提供的測試函數的第一個元素的值。否則返回 undefined。
var array1 = [5, 12, 8, 130, 44];
var found = array1.find(function(element) {
  return element > 10;
});
console.log(found);
// expected output: 12
// findIndex()方法返回數組中滿足提供的測試函數的第一個元素的索引。否則返回-1。
var array1 = [5, 12, 8, 130, 44];
function findFirstLargeNumber(element) {
  return element > 13;
}
console.log(array1.findIndex(findFirstLargeNumber));
// expected output: 3
// 原理
var users=[
    {id:1,name:'曹操'},
    {id:2,name:'許褚'},
    {id:3,name:'典韋'},
    {id:4,name:'於禁'},
]
Array.prototype.myFind=function(conditionFunc){
    for(var i=0;i<this.length;i++){
        if(conditionFunc(this[i],i)){
            return this[i]
        }
    }
}
var ret=users.myFind(function(item,index){
    return item.id===4
});
console.log(ret);//{ id: 4, name: '於禁' }

二、promise

①無法保證順序的代碼

var fs=require('fs');
// 讀取a.txt(里面包括文本 aaa)文件
fs.readFile('./a.txt','utf8',function(err,data){
    if(err){
        // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
        throw err
    }
    console.log(data)
})
// 讀取b.txt(里面包括文本 bbb)文件b
fs.readFile('./b.txt','utf8',function(err,data){
    if(err){
        // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
        throw err
    }
    console.log(data)
})
// 讀取c.txt(里面包括文本 ccc)文件
fs.readFile('./c.txt','utf8',function(err,data){
    if(err){
        // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
        throw err
    }
    console.log(data)
})

②通過回調嵌套的方式來保證順序

var fs=require('fs');
// 讀取a.txt(里面包括文本 aaa)文件
fs.readFile('./a.txt','utf8',function(err,data){
    if(err){
        // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
        throw err
    }
    console.log(data);
    // 讀取b.txt(里面包括文本 bbb)文件b
    fs.readFile('./b.txt','utf8',function(err,data){
        if(err){
            // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
            throw err
        }
        console.log(data);
        // 讀取c.txt(里面包括文本 ccc)文件
        fs.readFile('./c.txt','utf8',function(err,data){
            if(err){
                // 拋出異常:阻止程序的執行,把錯誤信息打印到控制台
                throw err
            }
            console.log(data)
        });
    });
});

③為了解決回調嵌套編碼方式帶來的問題(代碼不美觀,並且不好維護),ecmascript 6里增加了一個API:promise

  • promise代碼執行順序
var fs=require('fs');
console.log(1)
// 創建promise容器:一旦建立,就開始執行里面的代碼
new Promise(function(){
    console.log(2);
    fs.readFile('./a.txt','utf8',function(err,data){
        if(err){
            throw err;
        }
        console.log(3);
        console.log(data)
    });
});
console.log(4)
//執行順序是:1   2   4  3  aaa
  • promise圖示

  • promise基本語法
var fs=require('fs');
// 創建promise容器:一旦建立,就開始執行里面的代碼
var p1=new Promise(function(resolve,reject){
    fs.readFile('./aa.txt','utf8',function(err,data){
        if(err){
            // promise容器中的任務失敗,pending狀態變為rejectd
            reject(err)
        }else{
            // promise容器中的任務成功,pending狀態變為resolved
            // 這里調用的resolve方法就是下面then方法傳遞的第一個參數function(data){}
            resolve(data)
        }
    });
});
// 當p1成功以后,執行then方法的function(data){}
// 當p1失敗以后,執行then方法的function(err){}
p1.then(function(data){
    console.log(data)
},function(err){
    console.log('文件讀取失敗',err)
})

 

  • 解決讀取多個文件的嵌套問題
var fs=require('fs');
// 讀取a.txt(里面包括文本 aaa)文件
var p1=new Promise(function(resolve,reject){
    fs.readFile('./a.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    });
});
// 讀取b.txt(里面包括文本 bbb)文件
var p2=new Promise(function(resolve,reject){
    fs.readFile('./b.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    });
});
// 讀取c.txt(里面包括文本 ccc)文件
var p3=new Promise(function(resolve,reject){
    fs.readFile('./c.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    });
});
// then處理:當return一個promise對象,后續的then方法中的第一個參數就會接收這個對象
p1.then(function(data){
    console.log(data);
    return p2//后續的then里面的第一個參數會作為p2的resolve
},function(err){
    console.log('文件讀取失敗',err)
}).then(function(data){
    console.log(data);
    return p3//后續的then里面的第一個參數會作為p3的resolve
},function(err){
    console.log('文件讀取失敗',err)
}).then(function(data){
    console.log(data);
    console.log('end')
},function(err){
    console.log('文件讀取失敗',err)
})

  • 封裝promise版本的readFile方法

var fs=require('fs');
// 讀取文件封裝函數
function pReadFile(filePath){
    return new Promise(function(resolve,reject){
        fs.readFile(filePath,'utf8',function(err,data){
            if(err){
                reject(err)
            }else{
                resolve(data)
            }
        });
    })
}

pReadFile('./a.txt').then(function(data){
    console.log(data);
    return pReadFile('./b.txt')
}).then(function(data){
    console.log(data);
    return pReadFile('./c.txt')
}).then(function(data){
    console.log(data);
})

⑤promise使用場景:數據來源於多個數據接口,形成的嵌套問題

⑥mongoose所有的API都支持promise

⑧參考文章:http://es6.ruanyifeng.com/#docs/promise


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM