2016-11-12 93 views
-2

我有一段調用JS函數(NodeJS)的代碼。它所調用的函數包含一個Promise鏈。下面是調用該函數的代碼:調用包含承諾鏈的函數

'use strict' 

const request = require('request') 

try { 
    const data = search('javascript') 
    console.log('query complete') 
    console.log(data) 
} catch(err) { 
    console.log(err) 
} finally { 
    console.log('all done') 
} 

function search(query) { 
    searchByString(query).then(data => { 
    console.log('query complete') 
    //console.log(JSON.stringify(data, null, 2)) 
    return data 
    }).catch(err => { 
    console.log('ERROR') 
    console.log(err) 
    throw new Error(err.message) 
    }) 
} 

function searchByString(query) { 
    return new Promise((resolve, reject) => { 
    const url = `https://www.googleapis.com/books/v1/volumes?maxResults=40&fields=items(id,volumeInfo(title))&q=${query}` 
    request.get(url, (err, res, body) => { 
     if (err) { 
     reject(Error('failed to make API call')) 
     } 
     const data = JSON.parse(body) 
     resolve(data) 
    }) 
    }) 
} 

當我運行代碼,控制檯顯示query complete其次是搜索結果。

然後我得到一個錯誤:TypeError: google.searchByString(...).then(...).error is not a function這是沒有道理的!爲什麼這個錯誤被觸發?

+2

除非您使用某個Promise庫,否則您需要'.catch()'而不是'.error()'。 –

+1

肯定'.catch',而且,您擁有的try/catch將永遠不會工作,因爲它在同步函數內,並且您的承諾邏輯是異步的。 – loganfsmyth

+0

感謝您發現錯字Madara。爲了清晰起見,我已將所有代碼整合到一個腳本中。現在我得到'query complete',但沒有數據。我可以看到數據以錯誤的順序返回以使捕獲工作。 –

回答

0

好吧,你正在給數據分配返回值,但是你沒有返回promise的結果!

這裏有一個適合你的工作解決方案,我唯一做的事情就是a)在搜索中返回承諾,並b)從已解決的承諾中獲取數據。

你可以看到這個代碼,並在用它玩:https://runkit.com/arthur/5827b17b8795960014335852

'use strict' 

const request = require('request') 

try { 
    search('javascript') 
    .then(
     data => console.log('and the data', data), 
     error => console.error('uh - oh', error) 
    ); 
    console.log('the query isn\'t done yet!'); 
} catch(err) { 
    console.error(err); 
} finally { 
    console.log('all done, or is it?') 
} 

function search(query) { 
    return searchByString(query).then(data => { 
    console.log('query complete') 
    //console.log(JSON.stringify(data, null, 2)) 
    return data 
    }).catch(err => { 
    console.log('ERROR') 
    console.log(err) 
    throw new Error(err.message) 
    }) 
} 

function searchByString(query) { 
    return new Promise((resolve, reject) => { 
    const url = `https://www.googleapis.com/books/v1/volumes?maxResults=40&fields=items(id,volumeInfo(title))&q=${query}` 
    request.get(url, (err, res, body) => { 
     if (err) { 
     reject(Error('failed to make API call')) 
     } 
     const data = JSON.parse(body) 
     resolve(data) 
    }) 
    }) 
} 

下面是我怎麼會去了解它從頭開始。我認爲我在這裏最大的改進是使用節點url lib。總是一件好事,這樣做會爲您處理字符串轉義。在你的情況下,如果用戶遞交一個像「不」的字符串,它會中斷:)。

require('request'); 
// request promise is a popular, well tested lib wrapping request in a promise 
const request = require('request-promise'); 
// i like to use url handling libs, they do good things like escape string input. 
const url = require('url'); 

class Search { 
    constructor(query) { 
     this.query = query; 
    } 

    fetch() { 
     const endpoint = url.parse('https://www.googleapis.com/books/v1/volumes'); 

     const options = { 
      maxResults: 40, 
      fields: 'items(id,volumeInfo(title))', 
      q: this.query 
     } 

     endpoint.query = options; 

     const callUrl = url.format(endpoint); 
     return request.get(callUrl).then(result => JSON.parse(result)); 
    } 
} 

const search = new Search('javascript'); 
search.fetch() 
    .then(result => console.log(result)) 
    .catch(e => console.error('catch:', e)); 

和這裏的工作代碼:https://runkit.com/arthur/5827d5428b24ed0014dcc537

0

Now I get query complete but no data.

那是因爲你登錄datarequest.get()操作完成之前。此塊:

try { 
    const data = search('javascript') 
    console.log('query complete') 
    console.log(data) 
} catch(err) { 
    console.log(err) 
} finally { 
    console.log('all done') 
} 

同步執行和其後因此之前的代碼。您必須將其更改爲:

data = search('javascript') 

.then(function(data){ 
    console.log('query complete'); 
    console.log(data); 
    console.log('all done') 
}) 
.catch(function(err){ 
    console.log(err); 
})