JavaScript 異步編程_035

JavaScript 異步編程

一道面試題

for(var i = 0; i < 3; i++) {
   setTimeout(function() {
       console.log('timeout' + i);
   })
}

new Promise(function(resolve) {
    console.log('promise1');
    for(var i = 0; i < 1000; i++) {
        i == 99 && resolve();
    }
    console.log('promise2');
}).then(function() {
    console.log('then1');
})

console.log('global1');


promise1
promise2
global1
then1
3 timeout3

JavaScript單線程

在瀏覽器的一個頁面中,該頁面的JS程序只有一個線程,故曰單線程。因爲是單線程,所以程序的執行順序就是從上到下依次執行,同一時間內只能有一段代碼被執行。

瀏覽器多進程

  • 瀏覽器是多進程的
  • 瀏覽器之所以能夠運行,是因爲系統給它的進程分配了資源(cpu、內存)
  • 簡單點理解,每打開一個Tab頁,就相當於創建了一個獨立的瀏覽器進程。
  • 瀏覽器的渲染進程是多線程的

    • GUI渲染線程
    • JS引擎線程
    • 事件觸發線程
    • 定時觸發器線程
    • 異步http請求線程

瀏覽器渲染進程圖:
img

異步機制

 for (var i = 0; i < 5; i ++) {
        setTimeout(function(){
            console.log(i);
        }, 0);
    }
    console.log(i);
    //5 ; 5 ; 5 ; 5; 5

回調函數Callback

這是異步編程最基本的方法。

假定有兩個函數f1和f2,後者等待前者的執行結果。

  f1();

  f2();

如果f1是一個很耗時的任務,可以考慮改寫f1,把f2寫成f1的回調函數。\

  function f1(callback){
    setTimeout(function () {
      // f1的任務代碼
      callback();
    }, 1000);
  }

執行代碼就變成下面這樣:

 f1(f2);

採用這種方式,我們把同步操作變成了異步操作,f1不會堵塞程序運行,相當於先執行程序的主要邏輯,將耗時的操作推遲執行。

回調函數的優點是簡單、容易理解和部署,缺點是不利於代碼的閱讀和維護,各個部分之間高度耦合Coupling,流程會很混亂,而且每個任務只能指定一個回調函數。

發佈訂閱

發佈-訂閱模式又叫做觀察者模式,他定義了一種一對多的依賴關係,即當一個對象的狀態發生改變的時候,所有依賴他的對象都會得到通知。

let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (fn) {
    this.peopleList.push(fn);
}
yourMsg.triger = function () {
    for(var i = 0,fn;fn=this.peopleList[i++];){
        fn.apply(this,arguments);
    }
}

yourMsg.listen(function (name) {
    console.log(`${name}收到了你的消息`);
})
yourMsg.listen(function (name) {
    console.log('哈哈');
})

yourMsg.triger('張三');
yourMsg.triger('李四');

Promise

Promise 是一個對象,它代表了一個異步操作的最終完成或者失敗。

Promise 最直接的好處就是鏈式調用(chaining

const promise = new Promise(function(resolve, reject) {
  // ... some code

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

生成器Generators/ yield

Generator

function* Hello() {
    yield 100
    yield (function () {return 200})()
    return 300
}

var h = Hello()
console.log(typeof h)  // object

console.log(h.next())  // { value: 100, done: false }
console.log(h.next())  // { value: 200, done: false }
console.log(h.next())  // { value: 300, done: true }
console.log(h.next())  // { value: undefined, done: true }

yield

yield關鍵字使生成器函數執行暫停,yield關鍵字後面的表達式的值返回給生成器的調用者。它可以被認爲是一個基於生成器的版本的return關鍵字。

function* countAppleSales () {
  var saleList = [3, 7, 5];
  for (var i = 0; i < saleList.length; i++) {
    yield saleList[i];
  }
}
var appleStore = countAppleSales(); // Generator { }
console.log(appleStore.next()); // { value: 3, done: false }
console.log(appleStore.next()); // { value: 7, done: false }
console.log(appleStore.next()); // { value: 5, done: false }
console.log(appleStore.next()); // { value: undefined, done: true }

async/await

async function func() {
    try {
        let res = await asyncFunc()
    } catch (e) {
      //......
    }
}

async 函數返回的 Promise 對象,必須等到內部所有的 await 命令的 Promise 對象執行完,纔會發生狀態改變

async 函數的語法不難,難在錯誤處理上。

https://juejin.im/post/5a6547...
http://www.ruanyifeng.com/blo...
https://juejin.im/post/5a1681...
https://juejin.im/post/5ce75f...
https://developer.mozilla.org...
https://juejin.im/post/596e14...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章