2016-09-16 63 views
35

在這裏,我試圖圍繞promise承擔我的頭。在第一次請求時,我獲取一組links.and下一個請求我獲取第一個鏈接的內容。但是我想在返回下一個承諾object.So我上它。但是它給了我下面的JSON錯誤(without setTimeout() it works just fine在承諾鏈上使用setTimeout

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

我想知道爲什麼它沒有使用的setTimeout?

let globalObj={}; 
function getLinks(url){ 
    return new Promise(function(resolve,reject){ 

     let http = new XMLHttpRequest(); 
     http.onreadystatechange = function(){ 
      if(http.readyState == 4){ 
       if(http.status == 200){ 
       resolve(http.response); 
       }else{ 
       reject(new Error()); 
       } 
      }   
     } 
     http.open("GET",url,true); 
     http.send(); 
    }); 
} 

getLinks('links.txt').then(function(links){ 
    let all_links = (JSON.parse(links)); 
    globalObj=all_links; 

    return getLinks(globalObj["one"]+".txt"); 

}).then(function(topic){ 


    writeToBody(topic); 
    setTimeout(function(){ 
     return getLinks(globalObj["two"]+".txt"); // without setTimeout it works fine 
     },1000); 
}); 
+0

請注意,'return'是函數特有的,只返回父函數,並且不能從異步方法返回。 – adeneo

+1

注意有很多[更好的方法](http://stackoverflow.com/q/28250680/1048572)來構造這個代碼,而不是使用'globalObj'。 – Bergi

+0

'JSON.parse'扔在哪裏?我很難相信在一個「then」回調中是否存在'setTimeout'會影響前一個'then'回調中的調用。 – Bergi

回答

68

要守信鏈去,你不能使用setTimeout()你做,因爲你不是從.then()處理程序返回一個承諾的方式 - 你從setTimeout()回調這確實它返回你不好。

相反,你可以做這樣一個簡單的小延時功能:

function delay(t, v) { 
    return new Promise(function(resolve) { 
     setTimeout(resolve.bind(null, v), t) 
    }); 
} 

而且,然後使用它是這樣的:

getLinks('links.txt').then(function(links){ 
    let all_links = (JSON.parse(links)); 
    globalObj=all_links; 

    return getLinks(globalObj["one"]+".txt"); 

}).then(function(topic){ 
    writeToBody(topic); 
    // return a promise here that will be chained to prior promise 
    return delay(1000).then(function() { 
     return getLinks(globalObj["two"]+".txt"); 
    }); 
}); 

在這裏,我們從.then()處理程序返回一個承諾因此它被適當地鏈接。


您也可以延遲方法添加到無極對象,然後直接使用.delay(x)方法對您的承諾是這樣的:

function delay(t, v) { 
 
    return new Promise(function(resolve) { 
 
     setTimeout(resolve.bind(null, v), t) 
 
    }); 
 
} 
 

 
Promise.prototype.delay = function(t) { 
 
    return this.then(function(v) { 
 
     return delay(t, v); 
 
    }); 
 
} 
 

 

 
Promise.resolve("hello").delay(500).then(function(v) { 
 
    console.log(v); 
 
});

或者,使用Bluebird promise library這已經有內置的.delay()方法。

+0

解析函數是then()中的函數,所以setTimeout(resolve,t)意味着setTimeout(function(){return ....},t)是不是......那麼爲什麼它會起作用? –

+0

@ AL-zami - 'delay()'返回一個在'setTimeout()'後面解析的promise。 – jfriend00

+0

我已經爲setTimeout創建了一個promise包裝來輕鬆地延遲承諾。 https://github.com/zengfenfei/delay – Kevin

8
.then(() => new Promise((resolve) => setTimeout(resolve, 15000))) 
+8

請詳細說明爲什麼這比已經接受的答案更好。如果你不添加任何東西,不要回答。 – klutt

+3

喜歡它!很好,很短! –