2015-12-31 120 views
0

我想構建一個承諾,但推遲到稍後解決。下面的代碼創建了一個承諾,但它會立即解決。我如何控制何時獲得評估?解決承諾,在以後的時間

var p = new Promise((resolve, reject) => { 
     resolve(1); 
    }) 
    .then((p1) => { 
     console.log(p1 + 1); 
    }); 

UPDATE:澄清,爲希望從它的執行所承諾的聲明分開的原因是添加動態then回調,基於一些參數。

+0

您需要決定如何以及爲什麼承諾將得到解決:沒有一般情況。實際上你很難直接做到這一點,因爲絕大多數async已經返回一個Promise,或者至少做一些你可以承諾的事情。經常感覺需要直接做這件事本身就是一個跡象,表明代碼中的某些東西需要重構。 – Dtipson

回答

1

不完全確定你在問什麼 - 下面的代碼表明承諾的構造和調用then以相同的順序發生,但可以在不同的時間執行。更改wait1wait2的值,並查看輸出如何不同,但無論時間如何,代碼都能正常工作。

我認爲這將取決於您實施承諾代碼,以便它等待您想要等待的任何條件。在這個例子中,它是一個簡單的setTimeout,但你可以想象做任何事情來推遲執行。

你可能需要使用Chrome看到這些結果在您的瀏覽器:

var wait1 = 2000; 
 
var wait2 = 1000; 
 

 
function log(...str) { 
 
    var li = document.createElement('li'); 
 
    str.forEach((s) => { 
 
    li.appendChild(document.createTextNode(s)); 
 
    }); 
 
    document.getElementById("log").appendChild(li); 
 
} 
 

 
var p = new Promise((resolve, reject) => { 
 
    setTimeout(() => { 
 
    log("Resolving promise!"); 
 
    resolve(1); 
 
    }, wait1); 
 
}); 
 

 
log("Promise created!"); 
 

 
setTimeout(() => { 
 
    log("Calling 'then'"); 
 
    p.then((p1) => { 
 
    log("Value:", p1 + 1); 
 
    }); 
 
}, wait2);
<ol id="log" />

-1

不知道這是最好的方式,但您可以:

var resolve; 
 
var promise = new Promise(function(fulfill) { 
 
    resolve = fulfill; 
 
}); 
 

 
// now you can resolve the promise whenever you want 
 
promise.then(function() { 
 
    console.log('done!'); 
 
}); 
 

 
resolve();

0

您可以將resolvereject傳遞給您想要使用的任何異步功能。而這樣的功能可以在它完成工作時調用它。以下是Node中可運行的示例。如果您運行此操作,它將在當前目錄中執行ls -lexecSomething函數只需要回調函數,而promiseToExec函數將resolve, reject回調函數傳遞到execSomething,而不是立即調用其中任何一個。

const childProcess = require("child_process"); 

function execSomething(command, options, onSuccess, onError) { 
    childProcess.exec(command, options, (err, stdout, stderr) => { 
    if (err) { 
     onError(err); 
    } 
    onSuccess(stdout, stderr); 
    }); 
} 

function promiseToExec(command, options) { 
    return new Promise((resolve, reject) => { 
     execSomething(command, options, resolve, reject); 
    }); 
} 

promiseToExec("ls -l").then(console.log.bind(console)); 

Kazlauskis建議這樣做:

var resolve; 
var promise = new Promise(function(fulfill) { 
    resolve = fulfill; 
}); 

不要這樣做!

當回調中發生異常時,您傳遞給new Promise,承諾規範會自動將異常轉換爲承諾拒絕。所以如果回調裏面有任何東西throw Error...,你會得到自動轉換。

如果您保存resolve回調並將您的邏輯移到回調之外,那麼您將傳遞給new Promise,那麼您不會獲得此自動轉換。在回調之外拋出的異常將被傳遞到堆棧,而不會被轉換爲承諾拒絕。這很糟糕,因爲它要求您的函數的用戶使用.catch來捕獲拒絕的承諾try...catch以引發異常。這是一個糟糕的設計實踐。

這裏的代碼說明問題:

// This is how things should be done. 
function makeGoodPromise(num) { 
    return new Promise((resolve) => { 
    if (num < 0) { 
     throw new Error("negative num"); 
    } 
    resolve(num); 
    }); 
} 

// This is a bad approach because it will sometimes result in synchronous 
// exceptions. 
function makeBadPromise(num) { 
    let resolve; 
    const p = new Promise((fullfil) => { 
    resolve = fullfil; 
    }); 

    if (num < 0) { 
    throw new Error("negative num"); 
    } 
    resolve(num); 

    return p; 
} 

// Shoring up the bad approach with a try... catch clause. This illustrates what 
// you need to do convert the exception into a rejection. However, why deal with the 
// additional scaffolding when you can just take the simpler approach of not 
// leaking the callbacks?? 
function makeBadPromise2(num) { 
    let resolve, reject; 
    const p = new Promise((fullfil, deny) => { 
    resolve = fullfil; 
    reject = deny; 
    }); 

    try { 
    if (num < 0) { 
     throw new Error("negative num"); 
    } 
    resolve(num); 
    } 
    catch (e) { 
    reject(e); 
    } 

    return p; 
} 


makeGoodPromise(-1).catch(() => console.log("caught the good one!")); 

try { 
    makeBadPromise(-1).catch(() => console.log("caught the bad one!")); 
} 
catch(e) { 
    console.log("Oops! Synchronous exception: ", e); 
} 

makeBadPromise2(-1).catch(() => console.log("caught the bad2 one!")); 

當我在節點執行它,這是輸出:

Oops! Synchronous exception: Error: negative num 
    at makeBadPromise (/tmp/t12/test2.js:17:11) 
    at Object.<anonymous> (/tmp/t12/test2.js:48:3) 
    at Module._compile (module.js:570:32) 
    at Object.Module._extensions..js (module.js:579:10) 
    at Module.load (module.js:487:32) 
    at tryModuleLoad (module.js:446:12) 
    at Function.Module._load (module.js:438:3) 
    at Module.runMain (module.js:604:10) 
    at run (bootstrap_node.js:394:7) 
    at startup (bootstrap_node.js:149:9) 
caught the good one! 
caught the bad2 one!