前端 | 異步操作小結

本文旨在前期學習前端異步過程中的筆記整理,多多指教。

1乳乌、迭代器Iterator的模擬

迭代器有一個next方法,每次執(zhí)行的時候會返回一個對象 對象里面有兩個屬性市咆,一個是value表示返回的值汉操,還有就是布爾值done,表示是否迭代完成

function buy(books){
    let i = 0;
    return {
        next(){
            let done = i == books.length;
            let value = !done? books[i++]:undefined;
            return {
                value,
                done
            }
        }
    }
}

let it = buy(['js','node']);
var book;
do{
    book = it.next()
    console.log(book);
}while(!book.done);

2、生成器Generator的模擬

Generator是一個特殊的函數(shù)蒙兰,執(zhí)行它會返回一個Iterator對象磷瘤。 通過遍歷迭代器, Generator函數(shù)運行后會返回一個遍歷器對象搜变,而不是普通函數(shù)的返回值膀斋。

generator和函數(shù)的執(zhí)行流程不一樣。函數(shù)是順序執(zhí)行痹雅,遇到return語句或者最后一行函數(shù)語句就返回仰担。而變成generator的函數(shù),在每次調用next()的時候執(zhí)行绩社,遇到y(tǒng)ield語句返回摔蓝,再次執(zhí)行時從上次返回的yield語句處繼續(xù)執(zhí)行。

function *buy(books){
    for(let i = 0; i < books.length;i++){
        yield books[i]
    }
}

let books = buy(['js','node']);
var book;
do{
    book = books.next()
    console.log(book);
}while(!book.done);

3愉耙、Promise

3.1 基本原理(整理from阮一峰)
#Promise對象是一個構造函數(shù)贮尉,用來生成Promise實例
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise構造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject朴沿。它們是兩個函數(shù)猜谚,由 JavaScript 引擎提供,不用自己部署赌渣。

resolve函數(shù)的作用是魏铅,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved),在異步操作成功時調用坚芜,并將異步操作的結果览芳,作為參數(shù)傳遞出去;reject函數(shù)的作用是鸿竖,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected)沧竟,在異步操作失敗時調用铸敏,并將異步操作報出的錯誤,作為參數(shù)傳遞出去悟泵。

Promise實例生成以后杈笔,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數(shù)。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受兩個回調函數(shù)作為參數(shù)糕非。第一個回調函數(shù)是Promise對象的狀態(tài)變?yōu)閞esolved時調用桩撮,第二個回調函數(shù)是Promise對象的狀態(tài)變?yōu)閞ejected時調用。其中峰弹,第二個函數(shù)是可選的店量,不一定要提供。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)鞠呈。

#demo
function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

timeout方法返回一個Promise實例融师,表示一段時間以后才會發(fā)生的結果。過了指定的時間(ms參數(shù))以后蚁吝,Promise實例的狀態(tài)變?yōu)閞esolved旱爆,就會觸發(fā)then方法綁定的回調函數(shù)。

3.1.1 Promise.prototype.then()

Promise 實例具有then方法窘茁,也就是說怀伦,then方法是定義在原型對象Promise.prototype上的。它的作用是為 Promise 實例添加狀態(tài)改變時的回調函數(shù)山林。前面說過房待,then方法的第一個參數(shù)是resolved狀態(tài)的回調函數(shù),第二個參數(shù)(可選)是rejected狀態(tài)的回調函數(shù)驼抹。

then方法返回的是一個新的Promise實例(注意桑孩,不是原來那個Promise實例)。因此可以采用鏈式寫法框冀,即then方法后面再調用另一個then方法流椒。

#getJSON方法(返回的是promise對象) 
#參考 http://es6.ruanyifeng.com/#docs/promise
getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});
#上面的代碼使用then方法,依次指定了兩個回調函數(shù)明也。
#第一個回調函數(shù)完成以后宣虾,會將返回結果作為參數(shù),傳入第二個回調函數(shù)温数。

第一個then回調函數(shù)返回promise對象

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("resolved: ", comments);
}, function funcB(err){
  console.log("rejected: ", err);
});

上面代碼中绣硝,第一個then方法指定的回調函數(shù),返回的是另一個Promise對象帆吻。這時域那,第二個then方法指定的回調函數(shù),就會等待這個新的Promise對象狀態(tài)發(fā)生變化猜煮。如果變?yōu)閞esolved次员,就調用funcA,如果狀態(tài)變?yōu)閞ejected王带,就調用funcB淑蔚。

此外還有:Promise.prototype.catch() 、 Promise.prototype.finally()

3.1.2 Promise.all()

Promise.all方法用于將多個 Promise 實例愕撰,包裝成一個新的 Promise 實例刹衫。

const p = Promise.all([p1, p2, p3]);

p的狀態(tài)由p1、p2搞挣、p3決定带迟,分成兩種情況。

(1)只有p1囱桨、p2仓犬、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成fulfilled舍肠,此時p1搀继、p2、p3的返回值組成一個數(shù)組翠语,傳遞給p的回調函數(shù)叽躯。

(2)只要p1、p2肌括、p3之中有一個被rejected点骑,p的狀態(tài)就變成rejected,此時第一個被reject的實例的返回值谍夭,會傳遞給p的回調函數(shù)畔况。

let p1 = new Promise(function(resolve,reject){
    setTimeout(() => {
        resolve(100);
    }, 1000);
})


let p2 = new Promise(function(resolve,reject){
    setTimeout(() => {
        resolve(200);
    }, 2000);
})

// Promise.all 會接收一個promise數(shù)組,如果promise全部完成這個
// promise才會成功慧库,如果有一個失敗跷跪,那么這個promise就整個失敗了

console.time('cost')
// 同時異步請求多個數(shù)據(jù)的時候 會用all
Promise.all([p1,p2]).then(function(data){
    console.log(data);
    console.timeEnd('cost');
},function(err){
    console.log(err);
})
3.1.3 Promise.race()
const p = Promise.race([p1, p2, p3]);

只要p1、p2齐板、p3之中有一個實例率先改變狀態(tài)吵瞻,p的狀態(tài)就跟著改變。那個率先改變的 Promise 實例的返回值甘磨,就傳遞給p的回調函數(shù)橡羞。
誰先回來用誰的


let p1 = new Promise(function(resolve,reject){
    setTimeout(() => {
        reject(100);
    }, 1000);
})


let p2 = new Promise(function(resolve,reject){
    setTimeout(() => {
        resolve(200);
    }, 2000);
})
// Promise.race 會接收一個promise數(shù)組,只要有一個成功就成功了济舆,有一個失敗就失敗了
console.time('cost')
Promise.race([p1,p2]).then(function(data){
    console.log(data);
    console.timeEnd('cost');
},function(err){
    console.log(err);
})
3.1.4 Promise.resolve()

將現(xiàn)有對象轉為 Promise 對象

Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))

a卿泽、如果參數(shù)是一個thenable對象
thenable對象指的是具有then方法的對象,比如下面這個對象。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Promise.resolve方法會將這個對象轉為 Promise 對象签夭,然后就立即執(zhí)行thenable對象的then方法齐邦。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代碼中,thenable對象的then方法執(zhí)行后第租,對象p1的狀態(tài)就變?yōu)閞esolved措拇,從而立即執(zhí)行最后那個then方法指定的回調函數(shù),輸出 42慎宾。

b丐吓、參數(shù)不是具有then方法的對象,或根本就不是對象
如果參數(shù)是一個原始值趟据,或者是一個不具有then方法的對象券犁,則Promise.resolve方法返回一個新的 Promise 對象,狀態(tài)為resolved汹碱。

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello
3.2 Promise/A+規(guī)范

Promise/A+規(guī)范中文版
Promise/A+規(guī)范英文版

下面我們嘗試重寫下Promise

//Promise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REHECTED = 'rejected';

function Promise(exector){
    let self = this;
    self.status = PENDING;
    self.value = undefined;
    self.onResolvedCallbacks = [];
    self.onRejectedCallbacks = [];

    function resolve(value){
        if(value instanceof Promise){
            return value.then(resolve,reject);
        }
        setTimeout(() => {
            if(self.status == PENDING){
                self.status = FULFILLED;
                self.value = value;
                self.onResolvedCallbacks.forEach(cb=>cb(value));
            }
        });
    }
    function reject(reason){
        setTimeout(() => {
            if(self.status == PENDING){
                self.status = REHECTED;
                self.value = reason;
                self.onRejectedCallbacks.forEach(cb=>cb(reason));
            }
            
        });
    }
    try {
        exector(resolve,reject);
    } catch (e) {
        reject(e);
    }
}

function resolvePromise(promise2,x,resolve,reject){
    // 如果x就是promise2 死循環(huán)粘衬,一直處于pending狀態(tài)
    if(promise2 === x){
        return reject(new TypeError('循環(huán)引用'));
    }
    let called = false; //promise是否已經(jīng)resolve / reject
    if(x instanceof Promise){
        if(x.status == PENDING){
            x.then(function(y){
                // 遞歸調用
                resolvePromise(promise2,y,resolve,reject);
            },reject);
        }else{
            x.then(resolve,reject);
        }
        // x是一個thenable對象或函數(shù) 只要有then方法的對象
    } else if(x != null && ((typeof x == 'object' || typeof x == 'function'))){
        try { //取then的時候可能拋異常 這里捕捉下
            let then = x.then;
            if(typeof then == 'function'){
                // 有些Promise會同時執(zhí)行成功和失敗的回調
                // 如果promise2已經(jīng)成功或者失敗了,則不要再處理了
               then.call(x,function(y){
                    if(called) return;
                    called = true;
                    resolvePromise(promise2,y,resolve,reject);
                },function(err){
                    if(called) return;
                    called = true;
                    reject(err);
                })
            } else{
                 // 到此的話 x不是一個thenable對象那直接當成值resolve 
                // 比如返回是一個對象的時候:{name:'haha'比被,then:{}}會出現(xiàn)這樣的情況
                resolve(x);
            }
        } catch (e) {
            if(called) return;
            called = true;
            reject(e);
        }
    }else {
        //如果x是一個普通的值色难,則用x的值resolve promise2
        resolve(x);
    }
}

Promise.prototype.then = function(onFulfilled,onRejected){
    onFulfilled = typeof onFulfilled == 'function' ? onFulfilled:value=>value;
    onRejected = typeof onRejected == 'function' ? onRejected:value=>{throw value;}

    let self = this;
    let promise2;

    if(self.status == FULFILLED){
        promise2 = new Promise(function(resolve,reject){
            setTimeout(() => {
                try {
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2,x,resolve,reject);
                } catch (e) {
                    reject(e);
                }   
            });
        })
    }

    if(self.status == REHECTED){
        promise2 = new Promise(function(resolve,reject){
            setTimeout(() => {
                try {
                    let x = onRejected(self.value);
                    resolvePromise(promise2,x,resolve,reject);
                } catch (e) {
                    reject(e);
                }   
            });
        })
    }

    if(self.status == PENDING){
        promise2 = new Promise(function(resolve,reject){
            self.onResolvedCallbacks.push(function(value){
                setTimeout(() => {
                    try {
                        let x = onFulfilled(value);
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }   
                });
            })

            self.onRejectedCallbacks.push(function(value){
                setTimeout(() => {
                    try {
                        let x = onRejected(value);
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }   
                });
            })
        })
    }
    return promise2;
}


Promise.prototype.catch = function(onRejected){
    this.then(null,onRejected);
}

Promise.deferred = Promise.defer = function(){
    let df = {}
    df.promise = new Promise(function(resolve,reject){
        df.resolve = resolve;
        df.reject = reject;
    })
    return df;
}

function gen(times,cb){
    let result = [], count = 0;
    return function(i,data){
        result[i] = data;
        if(++count == times){
            cb(result);
        }
    }
}

// 都成功了才會成功
Promise.all = function(promises){
    return new Promise(function(resolve,reject){
        let done = gen(promises.length,resolve);
        for(let i = 0; i < promises.length; i++){
            promises[i].then(function(data){
                done(i,data);
            },reject)
        }
    })
}

// 都成功了才會成功
Promise.race = function(promises){
    return new Promise(function(resolve,reject){
        for(let i = 0; i < promises.length; i++){
            promises[i].then(resolve,reject)
        }
    })
}

module.exports = Promise;

使用promises-aplus-tests對該方法進行測試

promises-aplus-tests Promise.js
Promise測試.png

下面我們簡單做下測試

let Promise = require('./Promise')

let p1 = new Promise(function(resolve,reject){
    setTimeout(() => {
        let num = Math.random();
        if(num > .5){
            resolve('ok')
        }else{
            reject('failed')
        }
    }, 1000);
})

// 測試1
// p1.then(function(data){
//     console.log(data);
// },function(reason){
//     console.log(reason);
// })


// 測試2
// 里面函數(shù)返回的是一個新的promise實例
// let p2 = p1.then(function(data){
//     console.log(data);
//     return new Promise(function(resolve,reject){
//         resolve(1000); //異步成功的結果傳遞給P2的resolved
//     })
// },function(err){
//     console.log(err);
//     return new Promise(function(resolve,reject){
//         reject(2000);
//     })
// })
// p2.then(function(data){
//     console.log(data);
// },function(reason){
//     console.log(reason);
// })



// 測試3
// p1.then('aaa').then(function(data){
//     console.log(data);
// },function(err){
//     console.log(err)
// })

// 測試4 循環(huán)引用

// let p2 = p1.then(function(data){
//     return p2
// },function(err){
//     return p2;
// })
// p2.then(function(data){
//     console.log(data);
// },function(err){
//     console.log(err)
// })

// 測試5  thenable 調用后返回不是函數(shù)
let p2 = p1.then(function(data){
    // 不是thenable對象
    return {name:'hhaa',then:{}}
},function(err){
    console.log(err);
})
p2.then(function(data){
    console.log(data);
},function(err){
    console.log(err);
})

4、Q的使用

// 
let Q = require('q');
let fs =require('fs');

function readFile(filename){
    let defer = Q.defer();
    fs.readFile(filename,'utf-8',function(err,data){
        if(err){
            defer.reject(err);
        } else{
            defer.resolve(data);
        }
    })
    return defer.promise;
}

readFile('./1.txt').then(function(data){
    console.log(data);
})

參照上面的調用方式等缀,簡單實現(xiàn)Q

//Q的簡單實現(xiàn)
let Q = {
    defer(){
        let success, error;
        return {
            resolve(data){
                success(data);
            },
            reject(err){
                error(err);
            },
            promise:{
                then(onFulfilled,onRejected){
                    success = onFulfilled;
                    error = onRejected; 
                }
            }
        }
    }
}

5枷莉、bluebird的使用

let Promise = require('bluebird');
let fs = require('fs');

let readFile = fs.readFile;
//可以把把一個普通的異步方法轉成返回promise的方法
let readFileSync = Promise.promisify(readFile);
readFileSync('./1.txt','utf8').then(function(data){
    console.log(data);
})
//promisify的簡單實現(xiàn)
function promisify(fn){
    return function(...args){
        return new Promise(function(resolve,reject){
            fn.apply(null,[...args,function(err,data){
                err?reject(err):resolve(data);
            }])
        })
    }
}

Promise.promisifyAll

// 會遍歷對象所有方法,然后都復制一份 對每個方法添加一個新的方法Async

Promise.promisifyAll(fs);
fs.readFileAsync('./1.txt','utf8').then(data=>console.log(data));

function promisifyAll(obj){
    for(let key in obj){
        if(obj.hasOwnProperty(key)&& typeof obj[key] =='function'){
            obj[key+'Async'] = Promise.promisify(obj[key]);
        }
    }
}

6尺迂、generator + promise

let fs = require('fs');
function readFile(filename){
    return new Promise(function(resolve,reject){
        fs.readFile(filename,'utf-8',function(err,data){
            err?reject(err):resolve(data);
        })
    })
}

function *read(){
    console.log('start');
    let a = yield readFile('./promise/1.txt');
    console.log(a);
    let b = yield readFile('./promise/2.txt');
    console.log(b)
    let c = yield readFile('./promise/3.txt');
    console.log(c);
    return c;
}

let it = read();//調用生成器返回迭代器
let r1 = it.next();
r1.value.then(function(data){
    console.log('haha'+data);
    let r2 = it.next(data);
    r2.value.then(function(data){
        let r3 = it.next(data);
        r3.value.then(function(data){
            let r4 = it.next(data);
            console.log(r4);
        })
    })
})

7笤妙、co

基于第六條,我們這里使用co來簡化

let fs = require('fs');
let co = require('co');
function readFile(filename){
    return new Promise(function(resolve,reject){
        fs.readFile(filename,'utf-8',function(err,data){
            err?reject(err):resolve(data);
        })
    })
}

function *read(){
    console.log('start');
    let a = yield readFile('./promise/1.txt');
    console.log(a);
    let b = yield readFile('./promise/2.txt');
    console.log(b)
    let c = yield readFile('./promise/3.txt');
    console.log(c);
    return c;
}

co(read);

co的原理實現(xiàn)

// co是用來自動執(zhí)行迭代器的
function co(gen){
    let it = gen(); //我們讓我們的生成器持續(xù)執(zhí)行
    return new Promise(function(resolve,reject){
        !function next(lastVal){ //自執(zhí)行函數(shù)
            let {value,done} = it.next(lastVal);
            if(done){
                resolve(value);
            } else{
                value.then(next,reject)
            }
        }()
    })
}

8噪裕、async await

// async await 異步終極解決方案
// 他只是generator+promise的語法糖

let fs = require('fs');

function readFile(filename){
    return new Promise(function(resolve,reject){
        fs.readFile(filename,'utf8',function(err,data){
            err?reject(err):resolve(data);
        })
    })
}

// 如果代碼里面有異步代碼蹲盘,前面加async,方法返回promise需要await
async function read(){
    let a = await readFile('./1.txt');
    console.log(a)
    let b = await readFile('./2.txt');
    console.log(b);
    let c = await readFile('./3.txt');
    console.log(c)
    return 'ok';
}
read().then(data=>console.log(data))

拓展

//獲取前端返回的頁面和數(shù)據(jù)
let html = {};
let fs = require('fs');

function render(length,cb){
    let html = {};
    return function(key,value){
        html[key]=value;
        if(Object.keys(html).length == length){
            cb(html);
        }
    }
}

let done = render(2,function(html){
    console.log(html);
})

fs.readFile('./template.txt','utf8',function(err,template){
    done('template',template);
})

fs.readFile('./data.txt','utf8',function(err,data){
    done('data',data);
})
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市膳音,隨后出現(xiàn)的幾起案子召衔,更是在濱河造成了極大的恐慌,老刑警劉巖祭陷,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苍凛,死亡現(xiàn)場離奇詭異,居然都是意外死亡兵志,警方通過查閱死者的電腦和手機醇蝴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來想罕,“玉大人悠栓,你說我怎么就攤上這事。” “怎么了惭适?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵笙瑟,是天一觀的道長。 經(jīng)常有香客問我腥沽,道長逮走,這世上最難降的妖魔是什么鸠蚪? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任今阳,我火速辦了婚禮,結果婚禮上茅信,老公的妹妹穿的比我還像新娘盾舌。我一直安慰自己,他們只是感情好蘸鲸,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布妖谴。 她就那樣靜靜地躺著,像睡著了一般酌摇。 火紅的嫁衣襯著肌膚如雪膝舅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天窑多,我揣著相機與錄音仍稀,去河邊找鬼。 笑死埂息,一個胖子當著我的面吹牛技潘,可吹牛的內容都是我干的。 我是一名探鬼主播千康,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼享幽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拾弃?” 一聲冷哼從身側響起值桩,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎豪椿,沒想到半個月后奔坟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡砂碉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年蛀蜜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片增蹭。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡滴某,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情霎奢,我是刑警寧澤户誓,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站幕侠,受9級特大地震影響帝美,放射性物質發(fā)生泄漏。R本人自食惡果不足惜晤硕,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一悼潭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舞箍,春花似錦舰褪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捎迫,卻和暖如春晃酒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窄绒。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工贝次, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颗祝。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓浊闪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親螺戳。 傳聞我的和親對象是個殘疾皇子搁宾,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調函...
    neromous閱讀 8,707評論 1 56
  • title: promise總結 總結在前 前言 下文類似 Promise#then倔幼、Promise#resolv...
    JyLie閱讀 12,244評論 1 21
  • Promise對象是一種解決異步問題的方法盖腿,還有的解決方案是asyns 和 await (es7) 這么是目前的終...
    站在大神的肩膀上看世界閱讀 1,265評論 0 6
  • 摘自:阮一峰 http://es6.ruanyifeng.com/#docs/promise 一、首先损同,我們要弄明...
    泡杯感冒靈閱讀 801評論 0 4
  • 是不是每個人身體里都有不同的靈魂翩腐? 我偏執(zhí)又直接 冷漠又自私 熱情又單純 復雜又陰暗 自閉又外向 哪一個是我?
    昵稱被人搶了閱讀 85評論 0 0