深入理解JS異步編程-Promise
前言
“JS 是基于單線程事件循環(huán)”的概念構(gòu)建的,回調(diào)函數(shù)不會立即執(zhí)行,由事件輪詢?nèi)z測事件是否執(zhí)行完畢,當(dāng)執(zhí)行完有結(jié)果后,將結(jié)果放入回調(diào)函數(shù)的參數(shù)中,然后將回調(diào)函數(shù)添加到事件隊(duì)列中等待被執(zhí)行。
同時(shí)也講了回調(diào)函數(shù)的問題:
一是“回調(diào)地獄”,因?yàn)楫惒交卣{(diào)函數(shù)的特點(diǎn):回調(diào)函數(shù)是作為異步函數(shù)的參數(shù),一層一層嵌套,當(dāng)嵌套過多,將使代碼邏輯變得混亂,也無法做好錯誤捕捉和處理(只能在回調(diào)函數(shù)內(nèi)部 try catch)。
二是回調(diào)的執(zhí)行方式不符合自然語言的線性思維方式,不容易被理解。
三是控制反轉(zhuǎn)(控制權(quán)在其他人的代碼上),假如異步函數(shù)是別人提供的庫,我們把回調(diào)函數(shù)傳進(jìn)去,我們并不能知道異步函數(shù)在調(diào)用回調(diào)函數(shù)之外做了什么事情。
func1(() => {
func2(() => {
func3(() => {
func4(() => {
try {
...
} catch (err){
...
}
})
});
});
});
一、Promise 原理
首先,Promise 中文翻譯為“承諾”, 是 JavaScript 的一種對象,表示承諾終將返回一個結(jié)果,無論成功還是失敗。
Promise 有三個狀態(tài):等待中(pending),完成(fullfilled),失?。╮ejected), Promise 的設(shè)計(jì)具有原子性,狀態(tài)一旦從 pending 狀態(tài)轉(zhuǎn)換為 fullfilled 狀態(tài)或者 rejected 狀態(tài)后,將不能被改變。

var promise1 = new Promise((resolve, reject) => {
console.log("Promise 構(gòu)造器會立即執(zhí)行");
setTimeout(function (){
if(true) {
resolve("完成");
} else {
reject("失敗");
}
}, 1000);
})
promise1
.then((result) => {
// do something
console.log(result);
return 1
// return Promise.resolve(1); // 返回一個決議為成功的 promise 實(shí)例
// return Promise.reject("error"); // 返回一個決議為拒絕的 Promise 實(shí)例
})
.then((result) => {
// .then() 方法會返回一個 promise, 完成調(diào)用的參數(shù)為前一個 promise 的返回值或者決議值。
// do other things
console.log(result);
throw new Error("錯誤") // 拋出錯誤是隱式拒絕
})
.catch((error) => {
// 捕捉錯誤
console.log(error)
})
.then(() => {
// 還能繼續(xù)執(zhí)行!
})
.finally(() => {
// always do somethings
console.log("finally!")
})
二、Promise 的優(yōu)勢
1.鏈?zhǔn)秸{(diào)用
Promise 使用 then 方法后還會返回一個新的 Promise 對象,便于我們傳遞狀態(tài)數(shù)據(jù),同時(shí)鏈?zhǔn)綄懛ń咏谕綄懛?,更符合線性思維。
2.錯誤捕捉
相比回調(diào)函數(shù)的錯誤無法在外部捕捉的問題,Promise 能夠?yàn)橐贿B串的異步調(diào)用提供錯誤處理。
3.控制反轉(zhuǎn)再反轉(zhuǎn)
由于第三方提供的異步函數(shù),無法保證回調(diào)函數(shù)如何被執(zhí)行,但是 Promise 的特點(diǎn),能夠保證異步函數(shù)只能被 resolve 一次,以及始終以異步的形式執(zhí)行代碼。
4.可以利用 Promise.all 和 Promise.race 來解決 Promise 始終未決議和并行 Promise 嵌套的問題
三、Promise 的不足
1.每個 .then() 都是一個獨(dú)立的作用域
加入有很多個 .then() 方法,就會創(chuàng)建很多個獨(dú)立的作用域,那么將只能通過外面包裹一層函數(shù)作用域的閉包來共享狀態(tài)數(shù)據(jù)
2.無法取消單個 .then()
當(dāng) Promise 鏈中任意一個 .then() 方法中有語句執(zhí)行錯誤后,盡管經(jīng)過 catch 方法的錯誤處理,還是并不會中斷整個 Promise 鏈的執(zhí)行。
3.無法得知進(jìn)度
由于 Promise 只能從 pending 到 fullfilled 或 rejected 狀態(tài),無法得知 pending 階段的進(jìn)度。
四、Promise 應(yīng)用
// Promise 封裝 ajax
function fetch(method, url, data){
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
var method = method || "GET";
var data = data || null;
xhr.open(method, url, true);
xhr.onreadystatechange = function() {
if(xhr.status === 200 && xhr.readyState === 4){
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
xhr.send(data);
})
}
// 使用
fetch("GET", "/some/url.json", null)
.then(result => {
console.log(result);
})
// 封裝 nodejs error first 風(fēng)格回調(diào)
function readFile(url) {
return new Promise((resolve, reject) => {
fs.readFile(url,'utf8', (err, data) => {
if(err) {
reject(err);
return;
}
resolve(data)
})
})
}
五、總結(jié)
Promise 是 ES6 提出的簡化異步流程控制新規(guī)范,強(qiáng)調(diào)異步任務(wù)的完成狀態(tài)且具有原子性,這使得我們的代碼更容易追蹤和維護(hù)。Promise 在事件輪詢中屬于異步事件隊(duì)列中的微任務(wù),而微任務(wù)總是一次性全部執(zhí)行,而宏任務(wù)是每輪輪詢執(zhí)行一個。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
js實(shí)現(xiàn)unicode碼字符串與utf8字節(jié)數(shù)據(jù)互轉(zhuǎn)詳解
這篇文章主要介紹了js實(shí)現(xiàn)unicode碼字符串與utf8字節(jié)數(shù)據(jù)互轉(zhuǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Javascript基礎(chǔ)教程之?dāng)?shù)據(jù)類型 (布爾型 Boolean)
本文簡單講解了javascript數(shù)據(jù)類型中的布爾型(boolean),十分的簡單,小伙伴們看下就明白了2015-01-01
深入理解JS中的Function.prototype.bind()方法
bind 是 ES5 中新增的一個方法,可以改變函數(shù)內(nèi)部的this指向。這篇文章小編將帶領(lǐng)大家深入理解Javascript中的Function.prototype.bind()方法。有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-10-10
js中 關(guān)于undefined和null的區(qū)別介紹
本篇文章小編將為大家介紹,js中 關(guān)于undefined和null的區(qū)別,有需要的朋友可以參考一下2013-04-04
JavaScript學(xué)習(xí)筆記(一) js基本語法
JavaScript學(xué)習(xí)筆記(一) js基本語法,想要學(xué)習(xí)js的朋友可以參考下。2011-10-10
THREE.JS入門教程(5)你應(yīng)當(dāng)知道的十件事
Three.js是一個偉大的開源WebGL庫,WebGL允許JavaScript操作GPU,在瀏覽器端實(shí)現(xiàn)真正意義的3D,本文會讓你了解一下使用THREE.JS處理3D/避免SetInterval/使用倒序循環(huán)等等,感興趣的朋友可以了解下哦2013-01-01
javascript中對Date類型的常用操作小結(jié)
下面小編就為大家?guī)硪黄猨avascript中對Date類型的常用操作小結(jié)。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-05-05
JavaScript字符串對象toLowerCase方法入門實(shí)例(用于把字母轉(zhuǎn)換為小寫)
這篇文章主要介紹了JavaScript字符串對象toLowerCase方法入門實(shí)例,toLowerCase方法用于把字母字符串轉(zhuǎn)換為小寫形式,需要的朋友可以參考下2014-10-10

