從 Promise 開始踏入異步操作之旅

一、概述
1场刑、什么是 Promise般此?
MDN 對(duì) Promise 的定義:

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
直譯:Promise對(duì)象用于異步操作,它表示一個(gè)尚未完成且預(yù)計(jì)在未來完成的異步操作牵现。

通俗的說铐懊,這個(gè)異步操作可以一起執(zhí)行多個(gè)任務(wù),函數(shù)調(diào)用后不會(huì)立即返回執(zhí)行的結(jié)果瞎疼。如果任務(wù)A需要等待科乎,可先執(zhí)行任務(wù)B,等到任務(wù)A結(jié)果返回后再繼續(xù)回調(diào)贼急。
如下茅茂,定時(shí)器的異步模式:

// code1
setTimeout(function() {
    console.log('taskA, 定時(shí)器異步');
}, 0);
console.log('taskB, 同步操作');

// taskB, 同步操作
// taskA, 定時(shí)器異步

由 code1 可知,異步任務(wù)總是在當(dāng)前腳本執(zhí)行完同步任務(wù)后才執(zhí)行任務(wù)太抓。
2空闲、為什么要用 Promise?
在我們寫JavaScript 時(shí)走敌,難免是要用到回調(diào)函數(shù)的碴倾,有時(shí)候需要多層嵌套回調(diào),有時(shí)極端時(shí),會(huì)出現(xiàn)厄運(yùn)回調(diào)(如圖-厄運(yùn)回調(diào)金字塔):

厄運(yùn)回調(diào)地獄

一般我們?cè)陧?xiàng)目開發(fā)中用的比較多的情況是在使用 ajax 時(shí):

// code 2
request('test1.html', '', function(data1) {
    console.log('第一次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data1);
    request('test2.html', data1, function (data2) {
        console.log('第二次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data2);
        request('test3.html', data2, function (data3) {
            console.log('第三次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data3);
            //request... 繼續(xù)請(qǐng)求
        }, function(error3) {
            console.log('第三次請(qǐng)求失敗, 這是失敗信息:', error3);
        });
    }, function(error2) {
        console.log('第二次請(qǐng)求失敗, 這是失敗信息:', error2);
    });
}, function(error1) {
    console.log('第一次請(qǐng)求失敗, 這是失敗信息:', error1);
});

上述 code2 代碼出現(xiàn)了多層嵌套現(xiàn)象跌榔,這樣并不利于編碼維護(hù)和編程體驗(yàn)异雁。
這時(shí),我們就可以借用 promise 的強(qiáng)大作用矫户,用 then 鏈?zhǔn)交卣{(diào)把上述 code2 代碼簡(jiǎn)化如下 code3:

// code3
sendRequest('test1.html', '').then(function(data1) {
    console.log('第一次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data1);
}).then(function(data2) {
    console.log('第二次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data2);
}).then(function(data3) {
    console.log('第三次請(qǐng)求成功, 這是返回的數(shù)據(jù):', data3);
}).catch(function(error) {
    //用catch捕捉前面的錯(cuò)誤
    console.log('sorry, 請(qǐng)求失敗了, 這是失敗信息:', error);
});

上面代碼code3 是不是看起來清爽啦片迅!這就是 Promise 的強(qiáng)大之處残邀。
二皆辽、基本方法
1、基本用法
Promise 有以下三種狀態(tài):

  • Pending:進(jìn)行中芥挣,表示初始值
  • Fulfilled:表示操作成功
  • Rejected:表示操作失敗

Promise有兩種狀態(tài)改變的方式驱闷,既可以從pending轉(zhuǎn)變?yōu)閒ulfilled,也可以從pending轉(zhuǎn)變?yōu)閞ejected空免。一旦狀態(tài)改變空另,就 凝固 了,會(huì)一直保持這個(gè)狀態(tài)蹋砚,不會(huì)再發(fā)生變化扼菠。當(dāng)狀態(tài)發(fā)生變化,promise.then綁定的函數(shù)就會(huì)被調(diào)用坝咐。
2循榆、基本API
.then()

語法:Promise.prototype.then(onFulfilled, onRejected)

對(duì) promise 添加 onFulfilledonRejected 回調(diào),并返回的是一個(gè)新的Promise實(shí)例(不是原來那個(gè)Promise實(shí)例)墨坚,且返回值將作為參數(shù)傳入這個(gè)新Promise的 resolve 函數(shù)秧饮。

因此,我們可以使用鏈?zhǔn)綄懛ㄔ罄海缟衔牡?code3盗尸。由于前一個(gè)回調(diào)函數(shù),返回的還是一個(gè)Promise對(duì)象(即有異步操作)帽撑,這時(shí)后一個(gè)回調(diào)函數(shù)泼各,就會(huì)等待該P(yáng)romise對(duì)象的狀態(tài)發(fā)生變化,才會(huì)被調(diào)用亏拉。
.catch()

語法:Promise.prototype.catch(onRejected)

該方法用于指定放生錯(cuò)誤時(shí)的回調(diào)函數(shù)扣蜻。

// code4
promise.then(function(data) {
    console.log('success');
}).catch(function(error) {
    console.log('error', error);
});

Promise 對(duì)象捕獲錯(cuò)誤,還有其它的等同寫法:

// code5
var promise = new Promise(function (resolve, reject) {
    throw new Error('test');
});
/*******等同于*******/
var promise = new Promise(function (resolve, reject) {
    reject(new Error('test'));
});

//用catch捕獲
promise.catch(function (error) {
    console.log(error);
});
// Error: test

從 code5 中可以看出专筷,reject 方法的作用弱贼,等同于拋錯(cuò)。
Promise 對(duì)象的錯(cuò)誤磷蛹,會(huì)一直向后傳遞吮旅,直到被捕獲。即錯(cuò)誤總會(huì)被下一個(gè) catch 所捕獲。then 方法指定的回調(diào)函數(shù)庇勃,若拋出錯(cuò)誤檬嘀,也會(huì)被下一個(gè) catch 捕獲,catch 中也能拋錯(cuò)责嚷,則需要后面的 catch 來捕獲鸳兽。

// code6
sendRequest('test.html').then(function(data1) {
    //do something
}).then(function (data2) {
    //do something
}).catch(function (error) {
    //處理前面三個(gè)Promise產(chǎn)生的錯(cuò)誤
});

Promise 狀態(tài)一旦改變就會(huì)凝固,不會(huì)在改變罕拂。一次 Promise 一旦 fulfilled 了揍异,再拋錯(cuò),也不會(huì)變?yōu)?rejected爆班,就不會(huì)被 catch 了衷掷。

// code7
var promise = new Promise(function(resolve, reject) {
  resolve();
  throw 'error';
});

promise.catch(function(e) {
   console.log(e);      //This is never called
});

//在回調(diào)函數(shù)前拋異常
var p1 = { 
    then: function(resolve) {
      throw new Error("error");
      resolve("Resolved");
    }
};

var p2 = Promise.resolve(p1);
p2.then(function(value) {
    //not called
}, function(error) {
    console.log(error);       // => Error: error
});

//在回調(diào)函數(shù)后拋異常
var p3 = { 
    then: function(resolve) {
        resolve("Resolved");
        throw new Error("error");
    }
};

var p4 = Promise.resolve(p3);
p4.then(function(value) {
    console.log(value);     // => Resolved
}, function(error) {
    //not called
});

如果沒有使用 catch 方法指定處理錯(cuò)誤的回調(diào)函數(shù),Promise 對(duì)象拋出的錯(cuò)誤不會(huì)傳遞到外層代碼柿菩,即不會(huì)有任何反應(yīng)(chrome 會(huì)拋錯(cuò)戚嗅,Safari 和 Firefox 不拋錯(cuò)),這是 Promise 的一個(gè)缺點(diǎn)枢舶。

// code8
var promise = new Promise(function (resolve, reject) {
    resolve(x);
});
promise.then(function (data) {
    console.log(data);
});
// Uncaught (in promise) ReferenceError: x is not defined

.all()

語法:Promise.all(iterable)

該方法把多個(gè) Promise 實(shí)例懦胞,打包成一個(gè)新的 Promise 實(shí)例

// code9
var p = Promiese.all([p1, p2, p3]);

Promise.all 方法接受一個(gè)數(shù)組(或具有 Iterator 接口的對(duì)象)作為參數(shù)凉泄,數(shù)組中的對(duì)象([p1, p2, p3)均為 Promise 實(shí)例(如果不是一個(gè) Promise躏尉,該項(xiàng)會(huì)被用 Promise.resolve 放轉(zhuǎn)換為一個(gè) Promise),它的狀態(tài)由這個(gè)上 Promise 實(shí)例決定旧困。

  • 當(dāng)三個(gè)實(shí)例的狀態(tài)都變味 fulfilled醇份,p的狀態(tài)菜戶變?yōu)?fulfilled,并將三個(gè) Promise 返回的結(jié)果吼具,按照參數(shù)的順序(而不是 resolved 的順序)存入數(shù)組僚纷,傳給 p 的回調(diào)函數(shù),如 code10拗盒。
  • 當(dāng)三個(gè)實(shí)例中有一個(gè)裝填為 rejected怖竭,p 的狀態(tài)也會(huì)變?yōu)?rejected,并把第一個(gè) reject 的 Promise 的返回值陡蝇,傳給 p 的回調(diào)函數(shù)痊臭,如 code11.
// code10
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000, "first");
});
var p2 = new Promise(function (resolve, reject) {
    resolve('second');
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, "third");
}); 

Promise.all([p1, p2, p3]).then(function(values) { 
  console.log(values); 
});


// 約 3s 后
["first", "second", "third"] 
// code11
var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, "one"); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(reject, 2000, "two"); 
});
var p3 = new Promise((resolve, reject) => {
  reject("three");
});

Promise.all([p1, p2, p3]).then(function (value) {
    console.log('resolve', value);
}, function (error) {
    console.log('reject', error);    // => reject three
});

// reject three

這多個(gè) promise 是同時(shí)開始倚搬、并行執(zhí)行的岛抄,而不是順序執(zhí)行。從下面 code12 例子可以看出董栽。如果一個(gè)個(gè)執(zhí)行恼策,那至少需要 1+32+64+128鸦致。

// code12
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();

Promise.all([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (values) {
    console.log(Date.now() - startDate + 'ms');
    console.log(values);
});

// 130ms       //不一定,但大于128ms
[1,32,64,128]

.race()

語法: Promise.race(iterable)

該方法也是將多個(gè) Promise 實(shí)例,打包成一個(gè)新的 Promise 實(shí)例分唾。

var p = Promise.race([p1, p2, p3]);

Promise.race方法同樣接受一個(gè)數(shù)組(或具有Iterator接口)作參數(shù)抗碰。當(dāng)p1, p2, p3中任一個(gè)實(shí)例的狀態(tài)發(fā)生改變(變?yōu)閒ulfilled或rejected),p的狀態(tài)就跟著改變绽乔。并把第一個(gè)改變狀態(tài)的 promise 的返回值弧蝇,傳給 p 的回調(diào)函數(shù)。

// code13
var p1 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 500, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(function(value) {
    console.log('resolve', value); 
}, function(error) {
    //not called
    console.log('reject', error); 
});

// resolve two

var p3 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "three");
});
var p4 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 100, "four"); 
});

Promise.race([p3, p4]).then(function(value) {
    //not called
    console.log('resolve', value);              
}, function(error) {
    console.log('reject', error); 
});

// reject four

.resolve()

語法:
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);

該方法可以看做 new Promise() 的快捷方式折砸。

// code14
Promise.resolve('Success');

/*******等同于*******/
new Promise(function (resolve) {
    resolve('Success');
});

這段代碼會(huì)讓這個(gè)Promise對(duì)象立即進(jìn)入resolved狀態(tài)看疗,并將結(jié)果success傳遞給then指定的onFulfilled回調(diào)函數(shù)。由于Promise.resolve()也是返回Promise對(duì)象鞍爱,因此可以用.then()處理其返回值鹃觉。

// code15
Promise.resolve('success').then(function (value) {
    console.log(value);
});

// Success
// code16
//Resolving an array
Promise.resolve([1,2,3]).then(function(value) {
  console.log(value[0]);    // => 1
});

//Resolving a Promise
var p1 = Promise.resolve('this is p1');
var p2 = Promise.resolve(p1);
p2.then(function (value) {
    console.log(value);     // => this is p1
});

Promise.resolve()的另一個(gè)作用就是將thenable對(duì)象(即帶有then方法的對(duì)象)轉(zhuǎn)換為promise對(duì)象专酗。

// code17
var p1 = Promise.resolve({ 
    then: function (resolve, reject) { 
        resolve("this is an thenable object!");
    }
});
console.log(p1 instanceof Promise);     // => true

p1.then(function(value) {
    console.log(value);     // => this is an thenable object!
  }, function(e) {
    //not called
});

.reject()

語法: Promise.reject(reason)

這個(gè)方法和上述的Promise.resolve()類似睹逃,它也是new Promise()的快捷方式。

// code 18
Promise.reject(new Error('error'));

/*******等同于*******/
new Promise(function (resolve, reject) {
   reject(new Error('error'));
});

3祷肯、兩個(gè)附加方法

.done()

語法:
asyncFunc()
.then(f1)
.catch(r1)
.then(f2)
.done();

Promise對(duì)象的回調(diào)鏈沉填,不管以then方法或catch方法結(jié)尾,要是最后一個(gè)方法拋出錯(cuò)誤佑笋,都有可能無法捕捉到(因?yàn)镻romise內(nèi)部的錯(cuò)誤不會(huì)冒泡到全局)翼闹。因此,我們可以提供一個(gè)done方法蒋纬,總是處于回調(diào)鏈的尾端猎荠,保證拋出任何可能出現(xiàn)的錯(cuò)誤

.finally()
finally方法用于指定不管Promise對(duì)象最后狀態(tài)如何蜀备,都會(huì)執(zhí)行的操作关摇。它與done方法的最大區(qū)別,它接受一個(gè)普通的回調(diào)函數(shù)作為參數(shù)碾阁,該函數(shù)不管怎樣都必須執(zhí)行输虱。

// code19
Promise.resolve().then(()=>{
if(needToContinueProcess)   return xxx;
return Promise.reject({final})
})
.then(processOne)
.then(processTwo)
.catch(err=>{
if(err instanceof Error) return handleError
})
.finally()`

三、使用注意事項(xiàng)
缺點(diǎn):
1脂凶、無法取消 Promise宪睹。一旦新建它就會(huì)立即執(zhí)行,無法中途取消蚕钦。
2亭病、如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯(cuò)誤不會(huì)反應(yīng)到外部嘶居。
3罪帖、當(dāng)處于 pending 狀態(tài)時(shí),無法得知目前進(jìn)展到哪一階段。
注意事項(xiàng):
1胸蛛、始終在Promise 構(gòu)造器中書寫邏輯的話污茵,即使出現(xiàn)了意外的輸入,也能絕大部分情況下返回一個(gè)Rejected 的 Promise
2葬项、在 Promise 構(gòu)造器中泞当,除非你明確知道使用 throw 的正確姿勢(shì),否則都請(qǐng)使用 reject民珍。
3襟士、能夠兼容 Promise 和 Callback 確實(shí)是件很棒的事情,用第三方代碼庫(如bluebird)前請(qǐng)盡量理解其原理嚷量,短小的話完全可以自己寫一個(gè)陋桂。Promise雖好,可不要亂用哦蝶溶,實(shí)時(shí)牢記它會(huì)吞沒錯(cuò)誤的風(fēng)險(xiǎn)嗜历。
四、自我檢驗(yàn)題
https://zhuanlan.zhihu.com/p/30797777
五抖所、結(jié)語
本章的重點(diǎn)是需要明白什么是Promise梨州?為什么要使用 Promise?在使用 Promise 知道基本用法和注意事項(xiàng)田轧。下一章我們來認(rèn)識(shí)一下 ES6 中的遍歷器 Iterator暴匠。
六傻粘、參考

戳我博客

章節(jié)目錄

1每窖、ES6中啥是塊級(jí)作用域弦悉?運(yùn)用在哪些地方?
2警绩、ES6中使用解構(gòu)賦值能帶給我們什么崇败?
3、ES6字符串?dāng)U展增加了哪些后室?
4混狠、ES6對(duì)正則做了哪些擴(kuò)展岸霹?
5、ES6數(shù)值多了哪些擴(kuò)展将饺?
6贡避、ES6函數(shù)擴(kuò)展(箭頭函數(shù))
7、ES6 數(shù)組給我們帶來哪些操作便利刮吧?
8、ES6 對(duì)象擴(kuò)展
9井厌、Symbol 數(shù)據(jù)類型在 ES6 中起什么作用致讥?
10仅仆、Map 和 Set 兩數(shù)據(jù)結(jié)構(gòu)在ES6的作用
11垢袱、ES6 中的Proxy 和 Reflect 到底是什么鬼?
12咳榜、從 Promise 開始踏入異步操作之旅
13姚糊、ES6 迭代器(Iterator)和 for...of循環(huán)使用方法
14、ES6 異步進(jìn)階第二步:Generator 函數(shù)
15救恨、JavaScript 異步操作進(jìn)階第三步:async 函數(shù)
16释树、ES6 構(gòu)造函數(shù)語法糖:class 類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秸仙,隨后出現(xiàn)的幾起案子桩盲,更是在濱河造成了極大的恐慌,老刑警劉巖赌结,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柬姚,死亡現(xiàn)場(chǎng)離奇詭異拟杉,居然都是意外死亡量承,警方通過查閱死者的電腦和手機(jī)穴店,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拿穴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人默色,你說我怎么就攤上這事〉苁矗” “怎么了酗失?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)规肴。 經(jīng)常有香客問我,道長(zhǎng)拖刃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任央碟,我火速辦了婚禮均函,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘苞也。我一直安慰自己,他們只是感情好如迟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布殷勘。 她就那樣靜靜地躺著,像睡著了一般劳吠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淳附,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音奴曙,去河邊找鬼。 笑死炉菲,一個(gè)胖子當(dāng)著我的面吹牛坤溃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播薪介,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼汁政,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了记劈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤换途,失蹤者是張志新(化名)和其女友劉穎嘶窄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柄冲,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡现横,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年阁最,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姜盈。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡配阵,死狀恐怖示血,靈堂內(nèi)的尸體忽然破棺而出救拉,到底是詐尸還是另有隱情,我是刑警寧澤亿絮,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站黔姜,受9級(jí)特大地震影響蒂萎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岖是,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一豺撑、第九天 我趴在偏房一處隱蔽的房頂上張望烈疚。 院中可真熱鬧聪轿,春花似錦、人聲如沸灯抛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绳慎。三九已至,卻和暖如春靡砌,著一層夾襖步出監(jiān)牢的瞬間珊楼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工厕宗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留堕担,地道東北人骗炉。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓句葵,卻偏偏與公主長(zhǎng)得像厕鹃,于是被迫代替她去往敵國(guó)和親乍丈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案忆矛,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,702評(píng)論 1 56
  • Promiese 簡(jiǎn)單說就是一個(gè)容器催训,里面保存著某個(gè)未來才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果宗收,語法上說,Pr...
    雨飛飛雨閱讀 3,352評(píng)論 0 19
  • 00礼旅、前言Promise 是異步編程的一種解決方案洽洁,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大痘系。它由社區(qū)...
    夜幕小草閱讀 2,129評(píng)論 0 12
  • //本文內(nèi)容起初摘抄于 阮一峰 作者的譯文碎浇,用于記錄和學(xué)習(xí)璃俗,建議觀者移步于原文 概念: 所謂的Promise悉默,...
    曾經(jīng)過往閱讀 1,231評(píng)論 0 7
  • 下載安裝包 為了避免下載各種安裝包,推薦大家通過pip的方式進(jìn)行安裝抄课。比如我需要安裝beautifulsoup4雳旅,...
    xunzou閱讀 283評(píng)論 0 0