首頁  >  文章  >  web前端  >  NodeJS的Promise的用法解析_javascript技巧

NodeJS的Promise的用法解析_javascript技巧

WBOY
WBOY原創
2016-05-16 15:02:001481瀏覽

Javascript的特點是異步,Javascript不能等待,如果你實現某件需要等待的事情,你不能停在那裡一直等待結果回來,相反,底線是使用回調callback:你定義一個函數,這個函數只有等到結果可用時才能被呼叫。

這種回調模型對於好的程式碼組織是沒有問題的,但是也可以透過從原始回呼切換到promise解決很多問題,將promise看成是一個標準的資料容器,這樣會簡化你的程式碼組織,可以成為基於promise的架構。

什麼是Promise?

一個promise是一個帶有".then()"方法的對象,其代表的是一個操作的結果可能還沒有或不知道,無論誰訪問這個對象,都能夠使用".then()"方法加入回呼等待操作出現成功結果或失敗時的提醒通知,。

那為什麼這樣做好處會優於回調呢?標準的回呼模式在我們處理請求時需要同時提供回呼函數:

request(url, function(error, response) { 

 // handle success or error.

});

doSomethingElse(); 

很不幸,這段程式碼意味著這個request函數並不知道它自己什麼時候能夠完成,當然也沒有必要,我們最終透過回調傳遞結果。這會導致多個回調形成了嵌套回調,或稱為回調陷阱。

queryTheDatabase(query, function(error, result) { 

 request(url, function(error, response) {

  doSomethingElse(response, function(error, result) {

   doAnotherThing(result, function(error, result) {

    request(anotherUrl, function(error, response) {

     ...

    });

   });

  });

 });

});

Promise能夠解決這個問題,允許低層程式碼建立一個request然後返回一個對象,其代表著未完成的操作,讓呼叫者去決定應該加入什麼回呼。

Promise是什麼?

promise是一個非同步程式設計的抽象,它是一個傳回值或拋出exception的代理對象,一般promise物件都有一個then方法,這個then方法是我們如何獲得傳回值(成功實現承諾的結果值,稱為fulfillment)或拋出exception(拒絕承諾的理由,稱為rejection),then是用兩個可選的回調作為參數,我們可以稱為onFulfilled和OnRejected:

var promise = doSomethingAync()
promise.then(onFulfilled, onRejected)

當這個promise被解決了,也就是非同步過程完成後,onFulfilled和OnRejected中任何一個將被調用,

因此,一個promise有以下三個不同狀態:

■pending待承諾 - promise初始狀態
■fulfilled實現承諾 - 一個承諾成功實現狀態
■rejected拒絕承諾 - 一個承諾失敗的狀態

以讀取檔案為案例,以下是使用回呼實作讀取檔案後應該做什麼事情(輸出列印):

readFile(function (err, data) {

 if (err) return console.error(err)

 console.log(data)

})

如果我們的readFile函數回傳一個promise,那麼我們可以如下實作同樣的邏輯(輸出列印):

var promise = readFile()
promise.then(console.log, console.error)

這裡我們有了一個值promise代表的是非同步操作,我們能夠一直傳遞這個值promise,任何人訪問這個值都能夠使用then來消費使用它,無論這個值代表的非同步操作是否完成或沒有完成,我們也能保證異步的結果不會改變,因為這個promise代表的非同步操作只會執行一次,狀態是要么fulfilled要么是rejected。

理解Promise

Promise可能是不同於日常直覺,為了理解它,一些重要原理必須記牢: .then()總是返回一個新的promise.,如下面代碼:

var promise = readFile()
var promise2 = promise.then(readAnotherFile, console.error)

這裡then的參數readAnotherFile, console.error是代表非同步操作成功後的動作onFulfilled或失敗後的動作OnRejected,也就是說,讀取檔案成功後執行readAnotherFile函數,否則失敗列印記錄錯誤。這種實現是兩個只有一種可能。

我們再看下面上述程式碼如下:

var promise = readFile()

var promise2 = promise.then(function (data) {

 return readAnotherFile() // 如果readFile成功,执行readAnotherFile

}, function (err) {

 console.error(err) // 如果readFile不成功,记录,但是还是执行readAnotherFile

 return readAnotherFile()

})

promise2.then(console.log, console.error) // readAnotherFile函数的执行结果

因為then回傳一個promise,它意味著promise能夠被chain串列鏈條花,這樣能避免回呼地獄:

readFile()

 .then(readAnotherFile)

 .then(doSomethingElse)

 .then(...)

Promise法则有两部分必须分离:

(1).then()总是返回一个新的promise,每次你调用它,它不管回调做什么,因为.then()在回调被调用之前已经给了你一个承诺promise,回调的行为只影响承诺promise的实施,如果回调返回一个值,那么promise将使用那个值,如果这个值是一个promise,返回这个promise实施后的值给这个值,如果回调抛出错误,promise将拒绝错误。

(2)被.then()返回的promise是一个新的promise,它不同于那些.then()被调用的promise,promise长长的链条有时会好些隐藏这个事实,不管如何,每次.then()调用都会产生一个新的promise,这里必须注意的是你真正需要考虑的是你最后调用.then()可能代表失败,那么如果你不捕获这种失败,那么容易导致你的错误exception消失。

一些人认为.then()串联链条调用很类似fluent风格,但是长长的promise链条会让人迷惑,最后切分为一个个有意义的函数:

function getTasks() { 

 return $http.get('http://example.com/api/v1/tasks')

  .then(function(response) {

   return response.data;

  });

}

 

function getMyTasks() { 

 return getTasks()

  .then(function(tasks) {

   return filterTasks(tasks, {

    owner: user.username

   });

  });

}

在这个例子中,两个函数各自获得一个promise,携带了一个回调函数。

有趣的Promise

同样的promise能够接受任何数目的回调,当一个Promise被解决实施后,其中所有回调函数都会被调用,此外,一个promise在被解决实施后,甚至可以接受一个新的回调,这些回调完成能以正常方式被调用,这就允许我们使用回调实现简单形式的缓存:

var tasksPromise; 

function getTasks() { 

 taskPromise = taskPromise || getTasksFromTheServer();

 return taskPromise;

}

这个案例中,getTasks()函数可以被任意次数调用,它总是返回铜牙的promise,其中函数getTasksFromTheServer()却只是被调用一次。

以上这篇NodeJS的Promise的用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn